mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
tccrun.c: standalone backtraces with -bt[N] or -b
This makes it possible to get backtraces with executables (including DLLs/SOs) like we had it already with -g -run. Option -b includes -bt, and -bt includes -g. - new file lib/bt-exe.c: used to link rt_printline and the exception handler from tccrun.c into executables/DLLs. - new file lib/bt-log.c: provides a function that may be called from user code to print out a backtrace with a message (currently for i386/x86_64 only): int (*tcc_backtrace)(const char *fmt, ...); As an extra hack, if 'fmt' is prefixed like "^file.c^..." then the backtrace will skip calls from within 'file.c'. - new file lib/bt-dll.c: used on win32 to link the backtrace and bcheck functions with the main module at runtime - bcheck.c: now uses the tcc_backtrace function from above - tccgen.c: minor cleanups - tccelf.c: stab sections get SHF_ALLOC for easy access. Also in relocate_section(): 64bit relocations for stabs in DLLs cannot work. To find DLL addresses, the DLL base is added manually in tccrun.c via rc.prog_base instead. - tccpe.c: there are some changes to allow merging sections, used to merge .finit_array into .data in the first place. - tccpp.c: tcc -run now #defines __TCC_RUN__ also: refactor a line in tal_realloc that was incompatible with bcheck - tcctest.c: fixed a problem with r12 which tcc cannot preserve as well as gcc does. - tests2/112_backtrace.c: test the feature and the bcheck test18 that previously was in boundtest.c
This commit is contained in:
parent
4092b05068
commit
ef42295fe8
5
Makefile
5
Makefile
@ -281,11 +281,12 @@ IBw = $(call IB,$(wildcard $1),$2)
|
|||||||
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
|
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
|
||||||
IFw = $(call IF,$(wildcard $1),$2)
|
IFw = $(call IF,$(wildcard $1),$2)
|
||||||
IR = mkdir -p $2 && cp -r $1/. $2
|
IR = mkdir -p $2 && cp -r $1/. $2
|
||||||
|
B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
||||||
|
|
||||||
# install progs & libs
|
# install progs & libs
|
||||||
install-unx:
|
install-unx:
|
||||||
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
|
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
|
||||||
$(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)")
|
$(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)")
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||||
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
||||||
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
||||||
@ -310,7 +311,7 @@ uninstall-unx:
|
|||||||
install-win:
|
install-win:
|
||||||
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
|
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
|
||||||
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
||||||
$(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib")
|
$(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib")
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
||||||
|
@ -171,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s)
|
|||||||
|
|
||||||
float_abi = s->float_abi;
|
float_abi = s->float_abi;
|
||||||
#ifndef TCC_ARM_HARDFLOAT
|
#ifndef TCC_ARM_HARDFLOAT
|
||||||
tcc_warning("soft float ABI currently not supported: default to softfp");
|
# warning "soft float ABI currently not supported: default to softfp"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
22
lib/Makefile
22
lib/Makefile
@ -13,7 +13,7 @@ XCC = $(XTCC)
|
|||||||
XAR = $(XTCC) -ar
|
XAR = $(XTCC) -ar
|
||||||
XFLAGS-unx = -B$(TOPSRC)
|
XFLAGS-unx = -B$(TOPSRC)
|
||||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
||||||
XFLAGS = $(XFLAGS$(XCFG))
|
XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
|
||||||
XCFG = $(or $(findstring -win,$T),-unx)
|
XCFG = $(or $(findstring -win,$T),-unx)
|
||||||
|
|
||||||
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
||||||
@ -27,6 +27,8 @@ endif
|
|||||||
|
|
||||||
# only for native compiler
|
# only for native compiler
|
||||||
$(X)BCHECK_O = bcheck.o
|
$(X)BCHECK_O = bcheck.o
|
||||||
|
$(X)BT_O = bt-exe.o bt-log.o
|
||||||
|
$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
||||||
|
|
||||||
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
|
ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
|
||||||
BCHECK_O =
|
BCHECK_O =
|
||||||
@ -38,18 +40,18 @@ ifdef CONFIG_OSX
|
|||||||
XFLAGS += -D_ANSI_SOURCE
|
XFLAGS += -D_ANSI_SOURCE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o
|
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
|
||||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
|
||||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
|
||||||
ARM64_O = lib-arm64.o
|
ARM64_O = lib-arm64.o $(BT_O)
|
||||||
RISCV64_O = lib-arm64.o
|
RISCV64_O = lib-arm64.o $(BT_O)
|
||||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||||
|
|
||||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
||||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
||||||
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
|
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
|
||||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
|
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
|
||||||
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
||||||
OBJ-arm = $(ARM_O) $(DSO_O)
|
OBJ-arm = $(ARM_O) $(DSO_O)
|
||||||
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
||||||
@ -60,7 +62,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
|||||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||||
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
||||||
|
|
||||||
OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
|
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
|
||||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||||
|
|
||||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
||||||
@ -80,8 +82,10 @@ $(TOP)/%.o : %.c
|
|||||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||||
|
|
||||||
$(TOP)/bcheck.o : XFLAGS += -g
|
$(TOP)/bcheck.o : XFLAGS += -g
|
||||||
|
$(TOP)/bt-exe.o : $(TOP)/tccrun.c
|
||||||
|
|
||||||
$(X)crt1w.o : crt1.c
|
$(X)crt1w.o : crt1.c
|
||||||
$(X)wincrt1w.o : wincrt1.c
|
$(X)wincrt1w.o : wincrt1.c
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
rm -f *.a *.o $(ALL)
|
rm -f *.a *.o $(ALL)
|
||||||
|
161
lib/bcheck.c
161
lib/bcheck.c
@ -49,6 +49,12 @@
|
|||||||
#endif
|
#endif
|
||||||
#define FASTCALL __attribute__((regparm(3)))
|
#define FASTCALL __attribute__((regparm(3)))
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define DLL_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
# define DLL_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__FreeBSD__) \
|
#if defined(__FreeBSD__) \
|
||||||
|| defined(__FreeBSD_kernel__) \
|
|| defined(__FreeBSD_kernel__) \
|
||||||
|| defined(__DragonFly__) \
|
|| defined(__DragonFly__) \
|
||||||
@ -162,16 +168,16 @@ void splay_printtree(Tree * t, int d);
|
|||||||
/* external interface */
|
/* external interface */
|
||||||
void __bound_checking (int no_check);
|
void __bound_checking (int no_check);
|
||||||
void __bound_never_fatal (int no_check);
|
void __bound_never_fatal (int no_check);
|
||||||
void * __bound_ptr_add(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir1(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir2(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir4(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir8(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir12(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
|
||||||
void * __bound_ptr_indir16(void *p, size_t offset);
|
DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
|
||||||
void FASTCALL __bound_local_new(void *p1);
|
DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
|
||||||
void FASTCALL __bound_local_delete(void *p1);
|
DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
|
||||||
void __bound_init(void);
|
void __bound_init(size_t *);
|
||||||
void __bound_main_arg(char **p);
|
void __bound_main_arg(char **p);
|
||||||
void __bound_exit(void);
|
void __bound_exit(void);
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
@ -179,35 +185,32 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd,
|
|||||||
off_t offset);
|
off_t offset);
|
||||||
int __bound_munmap (void *start, size_t size);
|
int __bound_munmap (void *start, size_t size);
|
||||||
#endif
|
#endif
|
||||||
void __bound_new_region(void *p, size_t size);
|
DLL_EXPORT void __bound_new_region(void *p, size_t size);
|
||||||
void *__bound_memcpy(void *dst, const void *src, size_t size);
|
DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
|
||||||
int __bound_memcmp(const void *s1, const void *s2, size_t size);
|
DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
|
||||||
void *__bound_memmove(void *dst, const void *src, size_t size);
|
DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
|
||||||
void *__bound_memset(void *dst, int c, size_t size);
|
DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
|
||||||
int __bound_strlen(const char *s);
|
DLL_EXPORT int __bound_strlen(const char *s);
|
||||||
char *__bound_strcpy(char *dst, const char *src);
|
DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
|
||||||
char *__bound_strncpy(char *dst, const char *src, size_t n);
|
DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
|
||||||
int __bound_strcmp(const char *s1, const char *s2);
|
DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
|
||||||
int __bound_strncmp(const char *s1, const char *s2, size_t n);
|
DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
|
||||||
char *__bound_strcat(char *dest, const char *src);
|
DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
|
||||||
char *__bound_strchr(const char *string, int ch);
|
DLL_EXPORT char *__bound_strchr(const char *string, int ch);
|
||||||
char *__bound_strdup(const char *s);
|
DLL_EXPORT char *__bound_strdup(const char *s);
|
||||||
|
|
||||||
#if !MALLOC_REDIR
|
#if !MALLOC_REDIR
|
||||||
void *__bound_malloc(size_t size, const void *caller);
|
DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
|
||||||
void *__bound_memalign(size_t size, size_t align, const void *caller);
|
DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
|
||||||
void __bound_free(void *ptr, const void *caller);
|
DLL_EXPORT void __bound_free(void *ptr, const void *caller);
|
||||||
void *__bound_realloc(void *ptr, size_t size, const void *caller);
|
DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
|
||||||
void *__bound_calloc(size_t nmemb, size_t size);
|
DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FREE_REUSE_SIZE (100)
|
#define FREE_REUSE_SIZE (100)
|
||||||
static unsigned int free_reuse_index;
|
static unsigned int free_reuse_index;
|
||||||
static void *free_reuse_list[FREE_REUSE_SIZE];
|
static void *free_reuse_list[FREE_REUSE_SIZE];
|
||||||
|
|
||||||
/* error message, just for TCC */
|
|
||||||
const char *__bound_error_msg;
|
|
||||||
|
|
||||||
static Tree *tree = NULL;
|
static Tree *tree = NULL;
|
||||||
#define TREE_REUSE (1)
|
#define TREE_REUSE (1)
|
||||||
#if TREE_REUSE
|
#if TREE_REUSE
|
||||||
@ -296,14 +299,18 @@ void __bound_never_fatal (int neverfatal)
|
|||||||
fetch_and_add (&never_fatal, neverfatal);
|
fetch_and_add (&never_fatal, neverfatal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tcc_backtrace(const char *fmt, ...);
|
||||||
|
|
||||||
/* print a bound error message */
|
/* print a bound error message */
|
||||||
static void bound_error(const char *error)
|
#define bound_warning(...) \
|
||||||
{
|
tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__)
|
||||||
__bound_error_msg = error;
|
|
||||||
fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error);
|
#define bound_error(...) \
|
||||||
if (never_fatal == 0)
|
do { \
|
||||||
*(void **)0 = 0; /* force a runtime error */
|
bound_warning(__VA_ARGS__); \
|
||||||
}
|
if (never_fatal == 0) \
|
||||||
|
exit(255); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static void bound_alloc_error(const char *s)
|
static void bound_alloc_error(const char *s)
|
||||||
{
|
{
|
||||||
@ -317,20 +324,6 @@ static void bound_not_found_warning(const char *file, const char *function,
|
|||||||
dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
|
dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bound_ptr_add_warning(const char *file, const char *function,
|
|
||||||
void *ptr)
|
|
||||||
{
|
|
||||||
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
|
|
||||||
exec, file, function, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bound_ptr_indir_error(const char *file, const char *function,
|
|
||||||
void *ptr)
|
|
||||||
{
|
|
||||||
fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
|
|
||||||
exec, file, function, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||||
the end of a region in this case */
|
the end of a region in this case */
|
||||||
void * __bound_ptr_add(void *p, size_t offset)
|
void * __bound_ptr_add(void *p, size_t offset)
|
||||||
@ -360,8 +353,7 @@ void * __bound_ptr_add(void *p, size_t offset)
|
|||||||
if (addr <= tree->size) {
|
if (addr <= tree->size) {
|
||||||
if (tree->is_invalid || addr + offset > tree->size) {
|
if (tree->is_invalid || addr + offset > tree->size) {
|
||||||
POST_SEM ();
|
POST_SEM ();
|
||||||
if (print_warn_ptr_add)
|
bound_warning("%p is outside of the region", p + offset);
|
||||||
bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset);
|
|
||||||
if (never_fatal <= 0)
|
if (never_fatal <= 0)
|
||||||
return INVALID_POINTER; /* return an invalid pointer */
|
return INVALID_POINTER; /* return an invalid pointer */
|
||||||
return p + offset;
|
return p + offset;
|
||||||
@ -407,8 +399,7 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
|||||||
if (addr <= tree->size) { \
|
if (addr <= tree->size) { \
|
||||||
if (tree->is_invalid || addr + offset + dsize > tree->size) { \
|
if (tree->is_invalid || addr + offset + dsize > tree->size) { \
|
||||||
POST_SEM (); \
|
POST_SEM (); \
|
||||||
bound_ptr_indir_error (__FILE__, __FUNCTION__, \
|
bound_warning("%p is outside of the region", p + offset); \
|
||||||
p + offset); \
|
|
||||||
if (never_fatal <= 0) \
|
if (never_fatal <= 0) \
|
||||||
return INVALID_POINTER; /* return an invalid pointer */ \
|
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||||
return p + offset; \
|
return p + offset; \
|
||||||
@ -460,8 +451,7 @@ void FASTCALL __bound_local_new(void *p1)
|
|||||||
WAIT_SEM ();
|
WAIT_SEM ();
|
||||||
while ((addr = p[0])) {
|
while ((addr = p[0])) {
|
||||||
INCR_COUNT(bound_local_new_count);
|
INCR_COUNT(bound_local_new_count);
|
||||||
if (addr != 1)
|
tree = splay_insert(addr + fp, p[1], tree);
|
||||||
tree = splay_insert(addr + fp, p[1], tree);
|
|
||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
POST_SEM ();
|
POST_SEM ();
|
||||||
@ -498,7 +488,10 @@ void FASTCALL __bound_local_delete(void *p1)
|
|||||||
WAIT_SEM ();
|
WAIT_SEM ();
|
||||||
while ((addr = p[0])) {
|
while ((addr = p[0])) {
|
||||||
INCR_COUNT(bound_local_delete_count);
|
INCR_COUNT(bound_local_delete_count);
|
||||||
if (addr == 1) {
|
tree = splay_delete(addr + fp, tree);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
{
|
||||||
alloca_list_type *last = NULL;
|
alloca_list_type *last = NULL;
|
||||||
alloca_list_type *cur = alloca_list;
|
alloca_list_type *cur = alloca_list;
|
||||||
|
|
||||||
@ -518,11 +511,8 @@ void FASTCALL __bound_local_delete(void *p1)
|
|||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
tree = splay_delete(addr + fp, tree);
|
|
||||||
p += 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
POST_SEM ();
|
POST_SEM ();
|
||||||
while (free_list) {
|
while (free_list) {
|
||||||
alloca_list_type *next = free_list->next;
|
alloca_list_type *next = free_list->next;
|
||||||
@ -607,14 +597,14 @@ void __bound_new_region(void *p, size_t size)
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __attribute__((constructor)) __bound_init(void)
|
void __bound_init(size_t *p)
|
||||||
{
|
{
|
||||||
extern size_t __bounds_start[];
|
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
|
||||||
size_t *p;
|
|
||||||
|
|
||||||
if (inited)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
if (inited) {
|
||||||
|
WAIT_SEM();
|
||||||
|
goto add_bounds;
|
||||||
|
}
|
||||||
inited = 1;
|
inited = 1;
|
||||||
|
|
||||||
print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
|
print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
|
||||||
@ -623,8 +613,6 @@ void __attribute__((constructor)) __bound_init(void)
|
|||||||
print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
|
print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
|
||||||
never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
|
never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
|
||||||
|
|
||||||
dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
|
|
||||||
|
|
||||||
INIT_SEM ();
|
INIT_SEM ();
|
||||||
|
|
||||||
#if MALLOC_REDIR
|
#if MALLOC_REDIR
|
||||||
@ -724,27 +712,26 @@ void __attribute__((constructor)) __bound_init(void)
|
|||||||
tree = splay_insert((size_t) (&errno), sizeof (int), tree);
|
tree = splay_insert((size_t) (&errno), sizeof (int), tree);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
add_bounds:
|
||||||
|
if (!p)
|
||||||
|
goto no_bounds;
|
||||||
|
|
||||||
/* add all static bound check values */
|
/* add all static bound check values */
|
||||||
p = __bounds_start;
|
|
||||||
while (p[0] != 0) {
|
while (p[0] != 0) {
|
||||||
tree = splay_insert(p[0], p[1], tree);
|
tree = splay_insert(p[0], p[1], tree);
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
POST_SEM ();
|
|
||||||
#if BOUND_DEBUG
|
#if BOUND_DEBUG
|
||||||
if (print_calls) {
|
if (print_calls) {
|
||||||
p = __bounds_start;
|
|
||||||
while (p[0] != 0) {
|
|
||||||
dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
|
dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
|
||||||
__FILE__, __FUNCTION__,
|
__FILE__, __FUNCTION__,
|
||||||
(void *) p[0], (unsigned long) p[1]);
|
(void *) p[0], (unsigned long) p[1]);
|
||||||
p += 2;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
no_bounds:
|
||||||
|
|
||||||
|
POST_SEM ();
|
||||||
no_checking = 0;
|
no_checking = 0;
|
||||||
|
|
||||||
dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
|
dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,7 +918,7 @@ void *__bound_malloc(size_t size, const void *caller)
|
|||||||
#if MALLOC_REDIR
|
#if MALLOC_REDIR
|
||||||
/* This will catch the first dlsym call from __bound_init */
|
/* This will catch the first dlsym call from __bound_init */
|
||||||
if (malloc_redir == NULL) {
|
if (malloc_redir == NULL) {
|
||||||
__bound_init ();
|
__bound_init (0);
|
||||||
if (malloc_redir == NULL) {
|
if (malloc_redir == NULL) {
|
||||||
ptr = &initial_pool[pool_index];
|
ptr = &initial_pool[pool_index];
|
||||||
pool_index = (pool_index + size + 15) & ~15;
|
pool_index = (pool_index + size + 15) & ~15;
|
||||||
@ -1113,7 +1100,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
|||||||
#if MALLOC_REDIR
|
#if MALLOC_REDIR
|
||||||
/* This will catch the first dlsym call from __bound_init */
|
/* This will catch the first dlsym call from __bound_init */
|
||||||
if (malloc_redir == NULL) {
|
if (malloc_redir == NULL) {
|
||||||
__bound_init ();
|
__bound_init (0);
|
||||||
if (malloc_redir == NULL) {
|
if (malloc_redir == NULL) {
|
||||||
ptr = &initial_pool[pool_index];
|
ptr = &initial_pool[pool_index];
|
||||||
pool_index = (pool_index + size + 15) & ~15;
|
pool_index = (pool_index + size + 15) & ~15;
|
||||||
@ -1190,10 +1177,8 @@ static void __bound_check(const void *p, size_t size, const char *function)
|
|||||||
{
|
{
|
||||||
if (no_checking == 0 && size != 0 &&
|
if (no_checking == 0 && size != 0 &&
|
||||||
__bound_ptr_add((void *)p, size) == INVALID_POINTER) {
|
__bound_ptr_add((void *)p, size) == INVALID_POINTER) {
|
||||||
static char line[100];
|
bound_error("invalid pointer %p, size 0x%lx in %s",
|
||||||
sprintf(line, "invalid pointer %p, size 0x%lx in %s",
|
|
||||||
p, (unsigned long)size, function);
|
p, (unsigned long)size, function);
|
||||||
bound_error(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1207,10 +1192,8 @@ static int check_overlap (const void *p1, size_t n1,
|
|||||||
if (no_checking == 0 && n1 != 0 && n2 !=0 &&
|
if (no_checking == 0 && n1 != 0 && n2 !=0 &&
|
||||||
((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
|
((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
|
||||||
(p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
|
(p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
|
||||||
static char line[100];
|
bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
|
||||||
sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s",
|
|
||||||
p1, (unsigned long)n1, p2, (unsigned long)n2, function);
|
p1, (unsigned long)n1, p2, (unsigned long)n2, function);
|
||||||
bound_error(line);
|
|
||||||
return never_fatal < 0;
|
return never_fatal < 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
67
lib/bt-dll.c
Normal file
67
lib/bt-dll.c
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
/* stubs for calling bcheck functions from a dll. */
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define REDIR_ALL \
|
||||||
|
REDIR(__bt_init) \
|
||||||
|
REDIR(tcc_backtrace) \
|
||||||
|
\
|
||||||
|
REDIR(__bound_ptr_add) \
|
||||||
|
REDIR(__bound_ptr_indir1) \
|
||||||
|
REDIR(__bound_ptr_indir2) \
|
||||||
|
REDIR(__bound_ptr_indir4) \
|
||||||
|
REDIR(__bound_ptr_indir8) \
|
||||||
|
REDIR(__bound_ptr_indir12) \
|
||||||
|
REDIR(__bound_ptr_indir16) \
|
||||||
|
REDIR(__bound_local_new) \
|
||||||
|
REDIR(__bound_local_delete) \
|
||||||
|
REDIR(__bound_new_region) \
|
||||||
|
\
|
||||||
|
REDIR(__bound_free) \
|
||||||
|
REDIR(__bound_malloc) \
|
||||||
|
REDIR(__bound_realloc) \
|
||||||
|
REDIR(__bound_memcpy) \
|
||||||
|
REDIR(__bound_memcmp) \
|
||||||
|
REDIR(__bound_memmove) \
|
||||||
|
REDIR(__bound_memset) \
|
||||||
|
REDIR(__bound_strlen) \
|
||||||
|
REDIR(__bound_strcpy) \
|
||||||
|
REDIR(__bound_strncpy) \
|
||||||
|
REDIR(__bound_strcmp) \
|
||||||
|
REDIR(__bound_strncmp) \
|
||||||
|
REDIR(__bound_strcat) \
|
||||||
|
REDIR(__bound_strchr) \
|
||||||
|
REDIR(__bound_strdup)
|
||||||
|
|
||||||
|
#define REDIR(s) void *s;
|
||||||
|
static struct { REDIR_ALL } all_ptrs;
|
||||||
|
#undef REDIR
|
||||||
|
#define REDIR(s) #s"\0"
|
||||||
|
static const char all_names[] = REDIR_ALL;
|
||||||
|
#undef REDIR
|
||||||
|
#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
|
||||||
|
static void all_jmps() { REDIR_ALL }
|
||||||
|
#undef REDIR
|
||||||
|
|
||||||
|
void __bt_init_dll(int bcheck)
|
||||||
|
{
|
||||||
|
const char *s = all_names;
|
||||||
|
void **p = (void**)&all_ptrs;
|
||||||
|
do {
|
||||||
|
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
|
||||||
|
if (NULL == *p) {
|
||||||
|
char buf[100];
|
||||||
|
sprintf(buf,
|
||||||
|
"Error: function '%s()' not found in executable. "
|
||||||
|
"(Need -bt or -b for linking the exe.)", s);
|
||||||
|
if (GetStdHandle(STD_ERROR_HANDLE))
|
||||||
|
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
|
||||||
|
else
|
||||||
|
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
s = strchr(s,'\0') + 1, ++p;
|
||||||
|
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
|
||||||
|
}
|
43
lib/bt-exe.c
Normal file
43
lib/bt-exe.c
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
/* for linking rt_printline and the signal/exception handler
|
||||||
|
from tccrun.c into executables. */
|
||||||
|
|
||||||
|
#define CONFIG_TCC_BACKTRACE_ONLY
|
||||||
|
#include "../tccrun.c"
|
||||||
|
|
||||||
|
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
# define __declspec(n)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__declspec(dllexport)
|
||||||
|
void __bt_init(rt_context *p, int num_callers)
|
||||||
|
{
|
||||||
|
__attribute__((weak)) int main();
|
||||||
|
__attribute__((weak)) void __bound_init(void*);
|
||||||
|
struct rt_context *rc = &g_rtctxt;
|
||||||
|
//fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
|
||||||
|
if (num_callers) {
|
||||||
|
memcpy(rc, p, offsetof(rt_context, next));
|
||||||
|
rc->num_callers = num_callers - 1;
|
||||||
|
rc->top_func = main;
|
||||||
|
__rt_error = _rt_error;
|
||||||
|
set_exception_handler();
|
||||||
|
} else {
|
||||||
|
p->next = rc->next, rc->next = p;
|
||||||
|
}
|
||||||
|
if (__bound_init && p->bounds_start)
|
||||||
|
__bound_init(p->bounds_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy a string and truncate it. */
|
||||||
|
static char *pstrcpy(char *buf, size_t buf_size, const char *s)
|
||||||
|
{
|
||||||
|
int l = strlen(s);
|
||||||
|
if (l >= buf_size)
|
||||||
|
l = buf_size - 1;
|
||||||
|
memcpy(buf, s, l);
|
||||||
|
buf[l] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
36
lib/bt-log.c
Normal file
36
lib/bt-log.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
/* function to get a stack backtrace on demand with a message */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int (*__rt_error)(void*, void*, const char *, va_list);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define DLL_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
# define DLL_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (__rt_error) {
|
||||||
|
void *fp = __builtin_frame_address(1);
|
||||||
|
void *ip = __builtin_return_address(0);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = __rt_error(fp, ip, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
} else {
|
||||||
|
const char *p;
|
||||||
|
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
|
||||||
|
fmt = p + 1;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fprintf(stderr, "\n"), fflush(stderr);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
8
libtcc.c
8
libtcc.c
@ -776,9 +776,6 @@ LIBTCCAPI TCCState *tcc_new(void)
|
|||||||
/* enable this if you want symbols with leading underscore on windows: */
|
/* enable this if you want symbols with leading underscore on windows: */
|
||||||
#if 0 /* def TCC_TARGET_PE */
|
#if 0 /* def TCC_TARGET_PE */
|
||||||
s->leading_underscore = 1;
|
s->leading_underscore = 1;
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
|
||||||
s->rt_num_callers = 6;
|
|
||||||
#endif
|
#endif
|
||||||
s->ppfp = stdout;
|
s->ppfp = stdout;
|
||||||
/* might be used in error() before preprocess_start() */
|
/* might be used in error() before preprocess_start() */
|
||||||
@ -1556,7 +1553,7 @@ static const TCCOption tcc_options[] = {
|
|||||||
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
|
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
|
||||||
{ "bench", TCC_OPTION_bench, 0 },
|
{ "bench", TCC_OPTION_bench, 0 },
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
|
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
{ "b", TCC_OPTION_b, 0 },
|
{ "b", TCC_OPTION_b, 0 },
|
||||||
@ -1809,11 +1806,14 @@ reparse:
|
|||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
case TCC_OPTION_bt:
|
case TCC_OPTION_bt:
|
||||||
s->rt_num_callers = atoi(optarg);
|
s->rt_num_callers = atoi(optarg);
|
||||||
|
s->do_backtrace = 1;
|
||||||
|
s->do_debug = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
case TCC_OPTION_b:
|
case TCC_OPTION_b:
|
||||||
s->do_bounds_check = 1;
|
s->do_bounds_check = 1;
|
||||||
|
s->do_backtrace = 1;
|
||||||
s->do_debug = 1;
|
s->do_debug = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -372,9 +372,12 @@ Try to continue in case of a bound checking error.
|
|||||||
|
|
||||||
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
|
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
|
||||||
|
|
||||||
@item -bt N
|
@item -bt[N]
|
||||||
Display N callers in stack traces. This is useful with @option{-g} or
|
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
|
||||||
@option{-b}.
|
With executables, additional support for stack traces is included.
|
||||||
|
|
||||||
|
A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
|
||||||
|
to trigger a stack trace with a message on demand.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
2
tcc.c
2
tcc.c
@ -61,7 +61,7 @@ static const char help[] =
|
|||||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
" -bt N show N callers in stack traces\n"
|
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
|
||||||
#endif
|
#endif
|
||||||
"Misc. options:\n"
|
"Misc. options:\n"
|
||||||
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
|
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
|
||||||
|
26
tcc.h
26
tcc.h
@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||||||
#ifndef TCC_LIBTCC1
|
#ifndef TCC_LIBTCC1
|
||||||
# define TCC_LIBTCC1 "libtcc1.a"
|
# define TCC_LIBTCC1 "libtcc1.a"
|
||||||
#endif
|
#endif
|
||||||
#ifndef TCC_LIBBCHECK
|
|
||||||
# define TCC_LIBBCHECK "bcheck.o"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
|
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
|
||||||
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
|
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
|
||||||
@ -475,7 +472,7 @@ struct SymAttr {
|
|||||||
nodecorate : 1,
|
nodecorate : 1,
|
||||||
dllimport : 1,
|
dllimport : 1,
|
||||||
addrtaken : 1,
|
addrtaken : 1,
|
||||||
unused : 3;
|
xxxx : 3; /* not used */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function attributes or temporary attributes for parsing */
|
/* function attributes or temporary attributes for parsing */
|
||||||
@ -484,7 +481,8 @@ struct FuncAttr {
|
|||||||
func_call : 3, /* calling convention (0..5), see below */
|
func_call : 3, /* calling convention (0..5), see below */
|
||||||
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
|
||||||
func_noreturn : 1, /* attribute((noreturn)) */
|
func_noreturn : 1, /* attribute((noreturn)) */
|
||||||
xxxx : 2,
|
func_ctor : 1, /* attribute((constructor)) */
|
||||||
|
func_dtor : 1, /* attribute((destructor)) */
|
||||||
func_args : 8; /* PE __stdcall args */
|
func_args : 8; /* PE __stdcall args */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -619,8 +617,6 @@ typedef struct TokenString {
|
|||||||
typedef struct AttributeDef {
|
typedef struct AttributeDef {
|
||||||
struct SymAttr a;
|
struct SymAttr a;
|
||||||
struct FuncAttr f;
|
struct FuncAttr f;
|
||||||
unsigned short constructor:1;
|
|
||||||
unsigned short destructor:1;
|
|
||||||
struct Section *section;
|
struct Section *section;
|
||||||
Sym *cleanup_func;
|
Sym *cleanup_func;
|
||||||
int alias_target; /* token */
|
int alias_target; /* token */
|
||||||
@ -718,6 +714,7 @@ struct TCCState {
|
|||||||
|
|
||||||
/* compile with debug symbol (and use them if error during execution) */
|
/* compile with debug symbol (and use them if error during execution) */
|
||||||
unsigned char do_debug;
|
unsigned char do_debug;
|
||||||
|
unsigned char do_backtrace;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* compile with built-in memory and bounds checker */
|
/* compile with built-in memory and bounds checker */
|
||||||
unsigned char do_bounds_check;
|
unsigned char do_bounds_check;
|
||||||
@ -884,11 +881,7 @@ struct TCCState {
|
|||||||
const char *runtime_main;
|
const char *runtime_main;
|
||||||
void **runtime_mem;
|
void **runtime_mem;
|
||||||
int nb_runtime_mem;
|
int nb_runtime_mem;
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
|
||||||
int rt_num_callers;
|
int rt_num_callers;
|
||||||
const char **rt_bound_error_msg;
|
|
||||||
void *rt_prog_main;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int fd, cc; /* used by tcc_load_ldscript */
|
int fd, cc; /* used by tcc_load_ldscript */
|
||||||
@ -1259,6 +1252,9 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
|
|||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
ST_FUNC void tcc_add_btstub(TCCState *s1);
|
||||||
|
#endif
|
||||||
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
|
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
|
||||||
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
|
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
|
||||||
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
|
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
|
||||||
@ -1485,9 +1481,6 @@ ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
|
|||||||
#endif
|
#endif
|
||||||
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
|
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
|
||||||
|
|
||||||
ST_FUNC void add_init_array (TCCState *s1, Sym *sym);
|
|
||||||
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym);
|
|
||||||
|
|
||||||
ST_FUNC int put_elf_str(Section *s, const char *sym);
|
ST_FUNC int put_elf_str(Section *s, const char *sym);
|
||||||
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
|
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
|
||||||
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
|
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
|
||||||
@ -1506,7 +1499,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s);
|
|||||||
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
|
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
|
||||||
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
|
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
|
||||||
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
|
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
|
||||||
ST_FUNC void tcc_add_runtime(TCCState *s1);
|
ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
|
||||||
|
|
||||||
#ifndef ELF_OBJ_ONLY
|
#ifndef ELF_OBJ_ONLY
|
||||||
ST_FUNC void build_got_entries(TCCState *s1);
|
ST_FUNC void build_got_entries(TCCState *s1);
|
||||||
@ -1521,9 +1514,12 @@ ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
|
|||||||
ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
|
ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs);
|
||||||
|
|
||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
|
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
|
||||||
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
|
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
|
||||||
|
ST_FUNC void tcc_add_runtime(TCCState *s1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ xxx-link.c ------------ */
|
/* ------------ xxx-link.c ------------ */
|
||||||
|
261
tccelf.c
261
tccelf.c
@ -85,33 +85,21 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
|
|||||||
lbounds_section = new_section(s, ".lbounds",
|
lbounds_section = new_section(s, ".lbounds",
|
||||||
SHT_PROGBITS, SHF_ALLOC);
|
SHT_PROGBITS, SHF_ALLOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
|
||||||
{
|
|
||||||
addr_t *ptr;
|
|
||||||
|
|
||||||
if (0 == s1->do_bounds_check)
|
|
||||||
return;
|
|
||||||
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
|
|
||||||
*ptr = 0;
|
|
||||||
set_elf_sym(symtab_section, 0, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
bounds_section->sh_num, "__bounds_start");
|
|
||||||
/* pull bcheck.o from libtcc1.a */
|
|
||||||
set_elf_sym(symtab_section, 0, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
SHN_UNDEF, "__bound_init");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ST_FUNC void tccelf_stab_new(TCCState *s)
|
ST_FUNC void tccelf_stab_new(TCCState *s)
|
||||||
{
|
{
|
||||||
TCCState *s1 = s;
|
TCCState *s1 = s;
|
||||||
stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
|
int shf = 0;
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
/* include stab info with standalone backtrace support */
|
||||||
|
if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
|
||||||
|
shf = SHF_ALLOC;
|
||||||
|
#endif
|
||||||
|
stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
|
||||||
stab_section->sh_entsize = sizeof(Stab_Sym);
|
stab_section->sh_entsize = sizeof(Stab_Sym);
|
||||||
stab_section->sh_addralign = 4;
|
stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
|
||||||
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0);
|
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
|
||||||
put_elf_str(stab_section->link, "");
|
|
||||||
/* put first entry */
|
/* put first entry */
|
||||||
put_stabs(s, "", 0, 0, 0, 0);
|
put_stabs(s, "", 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
@ -803,6 +791,17 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d
|
|||||||
{
|
{
|
||||||
Stab_Sym *sym;
|
Stab_Sym *sym;
|
||||||
|
|
||||||
|
unsigned offset;
|
||||||
|
if (type == N_SLINE
|
||||||
|
&& (offset = stab_section->data_offset)
|
||||||
|
&& (sym = (Stab_Sym*)(stab_section->data + offset) - 1)
|
||||||
|
&& sym->n_type == type
|
||||||
|
&& sym->n_value == value) {
|
||||||
|
/* just update line_number in previous entry */
|
||||||
|
sym->n_desc = desc;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
|
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
|
||||||
if (str) {
|
if (str) {
|
||||||
sym->n_strx = put_elf_str(stab_section->link, str);
|
sym->n_strx = put_elf_str(stab_section->link, str);
|
||||||
@ -818,10 +817,11 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d
|
|||||||
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
|
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
|
||||||
unsigned long value, Section *sec, int sym_index)
|
unsigned long value, Section *sec, int sym_index)
|
||||||
{
|
{
|
||||||
put_stabs(s1, str, type, other, desc, value);
|
|
||||||
put_elf_reloc(symtab_section, stab_section,
|
put_elf_reloc(symtab_section, stab_section,
|
||||||
stab_section->data_offset - sizeof(unsigned int),
|
stab_section->data_offset + 8,
|
||||||
R_DATA_32, sym_index);
|
sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32,
|
||||||
|
sym_index);
|
||||||
|
put_stabs(s1, str, type, other, desc, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
|
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
|
||||||
@ -990,8 +990,16 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
|||||||
relocate(s1, rel, type, ptr, addr, tgt);
|
relocate(s1, rel, type, ptr, addr, tgt);
|
||||||
}
|
}
|
||||||
/* if the relocation is allocated, we change its symbol table */
|
/* if the relocation is allocated, we change its symbol table */
|
||||||
if (sr->sh_flags & SHF_ALLOC)
|
if (sr->sh_flags & SHF_ALLOC) {
|
||||||
sr->link = s1->dynsym;
|
sr->link = s1->dynsym;
|
||||||
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||||
|
size_t r = (uint8_t*)qrel - sr->data;
|
||||||
|
if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE
|
||||||
|
&& 0 == strcmp(s->name, ".stab"))
|
||||||
|
r = 0; /* cannot apply 64bit relocation to 32bit value */
|
||||||
|
sr->data_offset = sr->sh_size = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ELF_OBJ_ONLY
|
#ifndef ELF_OBJ_ONLY
|
||||||
@ -1268,16 +1276,20 @@ static void put_dt(Section *dynamic, int dt, addr_t val)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs)
|
||||||
|
{
|
||||||
|
int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
|
||||||
|
if (sec && offs == -1)
|
||||||
|
offs = sec->data_offset;
|
||||||
|
return set_elf_sym(symtab_section, offs, 0,
|
||||||
|
ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
|
||||||
|
}
|
||||||
|
|
||||||
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
||||||
{
|
{
|
||||||
Section *s;
|
Section *s;
|
||||||
long end_offset;
|
long end_offset;
|
||||||
char sym_start[1024];
|
char buf[1024];
|
||||||
char sym_end[1024];
|
|
||||||
|
|
||||||
snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
|
|
||||||
snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
|
|
||||||
|
|
||||||
s = find_section(s1, section_name);
|
s = find_section(s1, section_name);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
end_offset = 0;
|
end_offset = 0;
|
||||||
@ -1285,15 +1297,10 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
|
|||||||
} else {
|
} else {
|
||||||
end_offset = s->data_offset;
|
end_offset = s->data_offset;
|
||||||
}
|
}
|
||||||
|
snprintf(buf, sizeof(buf), "__%s_start", section_name + 1);
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, buf, s, 0);
|
||||||
0, 0,
|
snprintf(buf, sizeof(buf), "__%s_end", section_name + 1);
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
set_global_sym(s1, buf, s, end_offset);
|
||||||
s->sh_num, sym_start);
|
|
||||||
set_elf_sym(symtab_section,
|
|
||||||
end_offset, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
s->sh_num, sym_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
@ -1305,33 +1312,92 @@ static int tcc_add_support(TCCState *s1, const char *filename)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
|
ST_FUNC void add_array (TCCState *s1, const char *sec, int c)
|
||||||
{
|
{
|
||||||
Section *s;
|
Section *s;
|
||||||
unsigned char *ptr;
|
s = find_section(s1, sec);
|
||||||
|
s->sh_flags |= SHF_WRITE;
|
||||||
s = find_section(s1, section);
|
|
||||||
if (s) {
|
|
||||||
s->sh_flags |= SHF_WRITE;
|
|
||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
s->sh_type = sh_type;
|
s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY;
|
||||||
#endif
|
#endif
|
||||||
ptr = section_ptr_add(s, PTR_SIZE);
|
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
|
||||||
memset (ptr, 0, PTR_SIZE);
|
section_ptr_add(s, PTR_SIZE);
|
||||||
put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||||
|
{
|
||||||
|
if (0 == s1->do_bounds_check)
|
||||||
|
return;
|
||||||
|
section_ptr_add(bounds_section, sizeof(addr_t));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
static void put_ptr(TCCState *s1, Section *s, int offs)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
c = set_global_sym(s1, NULL, s, offs);
|
||||||
|
s = data_section;
|
||||||
|
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
|
||||||
|
section_ptr_add(s, PTR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set symbol to STB_LOCAL and resolve. The point is to not export it as
|
||||||
|
a dynamic symbol to allow so's to have one each with a different value. */
|
||||||
|
static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset)
|
||||||
|
{
|
||||||
|
int c = find_elf_sym(s1->symtab, name);
|
||||||
|
if (c) {
|
||||||
|
ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c;
|
||||||
|
esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE);
|
||||||
|
esym->st_value = offset;
|
||||||
|
esym->st_shndx = s->sh_num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
|
ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||||
{
|
{
|
||||||
add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
|
Section *s;
|
||||||
}
|
int n, o, b;
|
||||||
|
CString cstr;
|
||||||
|
|
||||||
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
|
s = data_section;
|
||||||
{
|
o = s->data_offset;
|
||||||
add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
|
/* create (part of) a struct rt_context (see tccrun.c) */
|
||||||
}
|
put_ptr(s1, stab_section, 0);
|
||||||
|
put_ptr(s1, stab_section, -1);
|
||||||
|
put_ptr(s1, stab_section->link, 0);
|
||||||
|
section_ptr_add(s, 3 * PTR_SIZE);
|
||||||
|
/* prog_base */
|
||||||
|
put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
|
||||||
|
section_ptr_add(s, PTR_SIZE);
|
||||||
|
n = 2 * PTR_SIZE, b = 0;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
if (s1->do_bounds_check) {
|
||||||
|
put_ptr(s1, bounds_section, 0);
|
||||||
|
n -= PTR_SIZE, b = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
section_ptr_add(s, n);
|
||||||
|
|
||||||
|
cstr_new(&cstr);
|
||||||
|
cstr_printf(&cstr,
|
||||||
|
" extern void __bt_init(),*__rt_info[],__bt_init_dll();"
|
||||||
|
"__attribute__((constructor)) static void __bt_init_rt(){");
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||||
|
cstr_printf(&cstr, "__bt_init_dll(%d);", b);
|
||||||
|
#endif
|
||||||
|
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
|
||||||
|
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
|
||||||
|
tcc_compile_string(s1, cstr.data);
|
||||||
|
cstr_free(&cstr);
|
||||||
|
set_local_sym(s1, "__rt_info", s, o);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TCC_TARGET_PE
|
||||||
/* add tcc runtime libraries */
|
/* add tcc runtime libraries */
|
||||||
ST_FUNC void tcc_add_runtime(TCCState *s1)
|
ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||||
{
|
{
|
||||||
@ -1340,7 +1406,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
|||||||
tcc_add_bcheck(s1);
|
tcc_add_bcheck(s1);
|
||||||
#endif
|
#endif
|
||||||
tcc_add_pragma_libs(s1);
|
tcc_add_pragma_libs(s1);
|
||||||
#ifndef TCC_TARGET_PE
|
|
||||||
/* add libc */
|
/* add libc */
|
||||||
if (!s1->nostdlib) {
|
if (!s1->nostdlib) {
|
||||||
tcc_add_library_err(s1, "c");
|
tcc_add_library_err(s1, "c");
|
||||||
@ -1356,7 +1421,17 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
|||||||
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
|
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
|
||||||
tcc_add_library_err(s1, "pthread");
|
tcc_add_library_err(s1, "pthread");
|
||||||
tcc_add_library_err(s1, "dl");
|
tcc_add_library_err(s1, "dl");
|
||||||
tcc_add_support(s1, TCC_LIBBCHECK);
|
tcc_add_support(s1, "bcheck.o");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
if (s1->do_backtrace) {
|
||||||
|
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||||
|
tcc_add_support(s1, "bt-exe.o");
|
||||||
|
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||||
|
tcc_add_support(s1, "bt-log.o");
|
||||||
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||||
|
tcc_add_btstub(s1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
tcc_add_support(s1, TCC_LIBTCC1);
|
tcc_add_support(s1, TCC_LIBTCC1);
|
||||||
@ -1364,8 +1439,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
|||||||
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||||
tcc_add_crt(s1, "crtn.o");
|
tcc_add_crt(s1, "crtn.o");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* add various standard linker symbols (must be done after the
|
/* add various standard linker symbols (must be done after the
|
||||||
sections are filled (for example after allocating common
|
sections are filled (for example after allocating common
|
||||||
@ -1376,59 +1451,39 @@ static void tcc_add_linker_symbols(TCCState *s1)
|
|||||||
int i;
|
int i;
|
||||||
Section *s;
|
Section *s;
|
||||||
|
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, "_etext", text_section, -1);
|
||||||
text_section->data_offset, 0,
|
set_global_sym(s1, "_edata", data_section, -1);
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
set_global_sym(s1, "_end", bss_section, -1);
|
||||||
text_section->sh_num, "_etext");
|
|
||||||
set_elf_sym(symtab_section,
|
|
||||||
data_section->data_offset, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
data_section->sh_num, "_edata");
|
|
||||||
set_elf_sym(symtab_section,
|
|
||||||
bss_section->data_offset, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
bss_section->sh_num, "_end");
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
/* XXX should be .sdata+0x800, not .data+0x800 */
|
/* XXX should be .sdata+0x800, not .data+0x800 */
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, "__global_pointer$", data_section, 0x800);
|
||||||
0x800, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
data_section->sh_num, "__global_pointer$");
|
|
||||||
#endif
|
#endif
|
||||||
/* horrible new standard ldscript defines */
|
/* horrible new standard ldscript defines */
|
||||||
add_init_array_defines(s1, ".preinit_array");
|
add_init_array_defines(s1, ".preinit_array");
|
||||||
add_init_array_defines(s1, ".init_array");
|
add_init_array_defines(s1, ".init_array");
|
||||||
add_init_array_defines(s1, ".fini_array");
|
add_init_array_defines(s1, ".fini_array");
|
||||||
|
|
||||||
/* add start and stop symbols for sections whose name can be
|
/* add start and stop symbols for sections whose name can be
|
||||||
expressed in C */
|
expressed in C */
|
||||||
for(i = 1; i < s1->nb_sections; i++) {
|
for(i = 1; i < s1->nb_sections; i++) {
|
||||||
s = s1->sections[i];
|
s = s1->sections[i];
|
||||||
if (s->sh_type == SHT_PROGBITS &&
|
if ((s->sh_flags & SHF_ALLOC)
|
||||||
(s->sh_flags & SHF_ALLOC)) {
|
&& (s->sh_type == SHT_PROGBITS
|
||||||
|
|| s->sh_type == SHT_STRTAB)) {
|
||||||
const char *p;
|
const char *p;
|
||||||
int ch;
|
|
||||||
|
|
||||||
/* check if section name can be expressed in C */
|
/* check if section name can be expressed in C */
|
||||||
p = s->name;
|
p = s->name;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
ch = *p;
|
int c = *p;
|
||||||
if (!ch)
|
if (!c)
|
||||||
break;
|
break;
|
||||||
if (!isid(ch) && !isnum(ch))
|
if (!isid(c) && !isnum(c))
|
||||||
goto next_sec;
|
goto next_sec;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
snprintf(buf, sizeof(buf), "__start_%s", s->name);
|
snprintf(buf, sizeof(buf), "__start_%s", s->name);
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, buf, s, 0);
|
||||||
0, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
s->sh_num, buf);
|
|
||||||
snprintf(buf, sizeof(buf), "__stop_%s", s->name);
|
snprintf(buf, sizeof(buf), "__stop_%s", s->name);
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, buf, s, -1);
|
||||||
s->data_offset, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
s->sh_num, buf);
|
|
||||||
}
|
}
|
||||||
next_sec: ;
|
next_sec: ;
|
||||||
}
|
}
|
||||||
@ -1699,8 +1754,8 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
|||||||
!(s->sh_flags & SHF_ALLOC) &&
|
!(s->sh_flags & SHF_ALLOC) &&
|
||||||
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
|
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
|
||||||
prepare_dynamic_rel(s1, s)) {
|
prepare_dynamic_rel(s1, s)) {
|
||||||
if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
|
if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
|
||||||
textrel = 1;
|
textrel = 1;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
if ((s1->do_debug && s->sh_type != SHT_RELX) ||
|
if ((s1->do_debug && s->sh_type != SHT_RELX) ||
|
||||||
@ -1814,9 +1869,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
|
|||||||
if (s == interp) {
|
if (s == interp) {
|
||||||
if (k != 0)
|
if (k != 0)
|
||||||
continue;
|
continue;
|
||||||
} else if (s->sh_type == SHT_DYNSYM ||
|
} else if ((s->sh_type == SHT_DYNSYM ||
|
||||||
s->sh_type == SHT_STRTAB ||
|
s->sh_type == SHT_STRTAB ||
|
||||||
s->sh_type == SHT_HASH) {
|
s->sh_type == SHT_HASH)
|
||||||
|
&& !strstr(s->name, ".stab")) {
|
||||||
if (k != 1)
|
if (k != 1)
|
||||||
continue;
|
continue;
|
||||||
} else if (s->sh_type == SHT_RELX) {
|
} else if (s->sh_type == SHT_RELX) {
|
||||||
@ -2060,7 +2116,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
|||||||
Section *s;
|
Section *s;
|
||||||
ElfW(Ehdr) ehdr;
|
ElfW(Ehdr) ehdr;
|
||||||
ElfW(Shdr) shdr, *sh;
|
ElfW(Shdr) shdr, *sh;
|
||||||
ElfW(Sym) *sym;
|
|
||||||
|
|
||||||
file_type = s1->output_type;
|
file_type = s1->output_type;
|
||||||
shnum = s1->nb_sections;
|
shnum = s1->nb_sections;
|
||||||
@ -2131,10 +2186,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
|||||||
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
|
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
|
||||||
|
|
||||||
sort_syms(s1, symtab_section);
|
sort_syms(s1, symtab_section);
|
||||||
if (s1->dynsym)
|
|
||||||
for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
|
|
||||||
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
|
||||||
s1->dynsym->sh_info++;
|
|
||||||
for(i = 1; i < s1->nb_sections; i++) {
|
for(i = 1; i < s1->nb_sections; i++) {
|
||||||
s = s1->sections[sec_order[i]];
|
s = s1->sections[sec_order[i]];
|
||||||
if (s->sh_type != SHT_NOBITS) {
|
if (s->sh_type != SHT_NOBITS) {
|
||||||
@ -2842,12 +2893,6 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
|
|||||||
for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
||||||
Section *s = symtab_section;
|
Section *s = symtab_section;
|
||||||
sym_index = find_elf_sym(s, p);
|
sym_index = find_elf_sym(s, p);
|
||||||
#ifdef TCC_TARGET_PE /* windows DLL's don't have UNDEF syms */
|
|
||||||
if (sym_index == 0) {
|
|
||||||
s = s1->dynsymtab_section;
|
|
||||||
sym_index = find_elf_sym(s, p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!sym_index)
|
if (!sym_index)
|
||||||
continue;
|
continue;
|
||||||
sym = &((ElfW(Sym) *)s->data)[sym_index];
|
sym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||||
|
86
tccgen.c
86
tccgen.c
@ -103,7 +103,7 @@ ST_DATA struct switch_t {
|
|||||||
struct scope *scope;
|
struct scope *scope;
|
||||||
} *cur_switch; /* current switch */
|
} *cur_switch; /* current switch */
|
||||||
|
|
||||||
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
|
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
|
||||||
/*list of temporary local variables on the stack in current function. */
|
/*list of temporary local variables on the stack in current function. */
|
||||||
ST_DATA struct temp_local_variable {
|
ST_DATA struct temp_local_variable {
|
||||||
int location; //offset on stack. Svalue.c.i
|
int location; //offset on stack. Svalue.c.i
|
||||||
@ -375,11 +375,10 @@ static BufferedFile* put_new_file(TCCState *s1)
|
|||||||
ST_FUNC void tcc_debug_line(TCCState *s1)
|
ST_FUNC void tcc_debug_line(TCCState *s1)
|
||||||
{
|
{
|
||||||
BufferedFile *f;
|
BufferedFile *f;
|
||||||
if (!s1->do_debug || !(f = put_new_file(s1)))
|
if (!s1->do_debug
|
||||||
return;
|
|| cur_text_section != text_section
|
||||||
if (last_line_num == f->line_num)
|
|| !(f = put_new_file(s1))
|
||||||
return;
|
|| last_line_num == f->line_num)
|
||||||
if (text_section != cur_text_section)
|
|
||||||
return;
|
return;
|
||||||
if (func_ind != -1) {
|
if (func_ind != -1) {
|
||||||
put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind);
|
put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind);
|
||||||
@ -409,9 +408,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
|
|||||||
{
|
{
|
||||||
if (!s1->do_debug)
|
if (!s1->do_debug)
|
||||||
return;
|
return;
|
||||||
#if 0 // this seems to confuse gnu tools
|
|
||||||
put_stabn(s1, N_FUN, 0, 0, size);
|
put_stabn(s1, N_FUN, 0, 0, size);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put alternative filename */
|
/* put alternative filename */
|
||||||
@ -2592,7 +2589,6 @@ redo:
|
|||||||
vswap();
|
vswap();
|
||||||
gen_op('-');
|
gen_op('-');
|
||||||
}
|
}
|
||||||
vtop[-1].r &= ~VT_MUSTBOUND;
|
|
||||||
gen_bounded_ptr_add();
|
gen_bounded_ptr_add();
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
@ -3428,6 +3424,10 @@ ST_FUNC void vstore(void)
|
|||||||
|
|
||||||
/* destination */
|
/* destination */
|
||||||
vswap();
|
vswap();
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
if (vtop->r & VT_MUSTBOUND)
|
||||||
|
gbound(); /* check would be wrong after gaddrof() */
|
||||||
|
#endif
|
||||||
vtop->type.t = VT_PTR;
|
vtop->type.t = VT_PTR;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
|
|
||||||
@ -3444,8 +3444,11 @@ ST_FUNC void vstore(void)
|
|||||||
|
|
||||||
vswap();
|
vswap();
|
||||||
/* source */
|
/* source */
|
||||||
vtop->r &= ~VT_MUSTBOUND;
|
|
||||||
vpushv(vtop - 2);
|
vpushv(vtop - 2);
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
if (vtop->r & VT_MUSTBOUND)
|
||||||
|
gbound();
|
||||||
|
#endif
|
||||||
vtop->type.t = VT_PTR;
|
vtop->type.t = VT_PTR;
|
||||||
gaddrof();
|
gaddrof();
|
||||||
/* type size */
|
/* type size */
|
||||||
@ -3662,11 +3665,11 @@ redo:
|
|||||||
}
|
}
|
||||||
case TOK_CONSTRUCTOR1:
|
case TOK_CONSTRUCTOR1:
|
||||||
case TOK_CONSTRUCTOR2:
|
case TOK_CONSTRUCTOR2:
|
||||||
ad->constructor = 1;
|
ad->f.func_ctor = 1;
|
||||||
break;
|
break;
|
||||||
case TOK_DESTRUCTOR1:
|
case TOK_DESTRUCTOR1:
|
||||||
case TOK_DESTRUCTOR2:
|
case TOK_DESTRUCTOR2:
|
||||||
ad->destructor = 1;
|
ad->f.func_dtor = 1;
|
||||||
break;
|
break;
|
||||||
case TOK_SECTION1:
|
case TOK_SECTION1:
|
||||||
case TOK_SECTION2:
|
case TOK_SECTION2:
|
||||||
@ -4958,6 +4961,10 @@ ST_FUNC void unary(void)
|
|||||||
Sym *s;
|
Sym *s;
|
||||||
AttributeDef ad;
|
AttributeDef ad;
|
||||||
|
|
||||||
|
/* generate line number info */
|
||||||
|
if (tcc_state->do_debug)
|
||||||
|
tcc_debug_line(tcc_state);
|
||||||
|
|
||||||
sizeof_caller = in_sizeof;
|
sizeof_caller = in_sizeof;
|
||||||
in_sizeof = 0;
|
in_sizeof = 0;
|
||||||
type.ref = NULL;
|
type.ref = NULL;
|
||||||
@ -5522,7 +5529,7 @@ special_math_val:
|
|||||||
vtop->r |= VT_LVAL;
|
vtop->r |= VT_LVAL;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* if bound checking, the referenced pointer must be checked */
|
/* if bound checking, the referenced pointer must be checked */
|
||||||
if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL)
|
if (tcc_state->do_bounds_check)
|
||||||
vtop->r |= VT_MUSTBOUND;
|
vtop->r |= VT_MUSTBOUND;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -5538,15 +5545,6 @@ special_math_val:
|
|||||||
Sym *sa;
|
Sym *sa;
|
||||||
int nb_args, ret_nregs, ret_align, regsize, variadic;
|
int nb_args, ret_nregs, ret_align, regsize, variadic;
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
|
||||||
if (tcc_state->do_bounds_check && (vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
|
|
||||||
addr_t *bounds_ptr;
|
|
||||||
|
|
||||||
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
|
|
||||||
bounds_ptr[0] = 1; /* marks alloca/vla used */
|
|
||||||
bounds_ptr[1] = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* function call */
|
/* function call */
|
||||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||||
/* pointer test (no array accepted) */
|
/* pointer test (no array accepted) */
|
||||||
@ -6514,10 +6512,10 @@ again:
|
|||||||
}
|
}
|
||||||
|
|
||||||
prev_scope(&o, is_expr);
|
prev_scope(&o, is_expr);
|
||||||
|
if (local_scope)
|
||||||
if (0 == local_scope && !nocode_wanted)
|
next();
|
||||||
|
else if (!nocode_wanted)
|
||||||
check_func_return();
|
check_func_return();
|
||||||
next();
|
|
||||||
|
|
||||||
} else if (t == TOK_RETURN) {
|
} else if (t == TOK_RETURN) {
|
||||||
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
||||||
@ -7582,16 +7580,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
gen_vla_sp_save(addr);
|
gen_vla_sp_save(addr);
|
||||||
cur_scope->vla.loc = addr;
|
cur_scope->vla.loc = addr;
|
||||||
cur_scope->vla.num++;
|
cur_scope->vla.num++;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
|
||||||
if (bcheck) {
|
|
||||||
addr_t *bounds_ptr;
|
|
||||||
|
|
||||||
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
|
|
||||||
bounds_ptr[0] = 1; /* marks alloca/vla used */
|
|
||||||
bounds_ptr[1] = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else if (has_init) {
|
} else if (has_init) {
|
||||||
size_t oldreloc_offset = 0;
|
size_t oldreloc_offset = 0;
|
||||||
if (sec && sec->reloc)
|
if (sec && sec->reloc)
|
||||||
@ -7617,7 +7605,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
|
|
||||||
/* parse a function defined by symbol 'sym' and generate its code in
|
/* parse a function defined by symbol 'sym' and generate its code in
|
||||||
'cur_text_section' */
|
'cur_text_section' */
|
||||||
static void gen_function(Sym *sym, AttributeDef *ad)
|
static void gen_function(Sym *sym)
|
||||||
{
|
{
|
||||||
/* Initialize VLA state */
|
/* Initialize VLA state */
|
||||||
struct scope f = { 0 };
|
struct scope f = { 0 };
|
||||||
@ -7632,17 +7620,12 @@ static void gen_function(Sym *sym, AttributeDef *ad)
|
|||||||
}
|
}
|
||||||
/* NOTE: we patch the symbol size later */
|
/* NOTE: we patch the symbol size later */
|
||||||
put_extern_sym(sym, cur_text_section, ind, 0);
|
put_extern_sym(sym, cur_text_section, ind, 0);
|
||||||
|
if (sym->type.ref->f.func_ctor)
|
||||||
if (ad && ad->constructor) {
|
add_array (tcc_state, ".init_array", sym->c);
|
||||||
add_init_array (tcc_state, sym);
|
if (sym->type.ref->f.func_dtor)
|
||||||
}
|
add_array (tcc_state, ".fini_array", sym->c);
|
||||||
if (ad && ad->destructor) {
|
|
||||||
add_fini_array (tcc_state, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
funcname = get_tok_str(sym->v, NULL);
|
funcname = get_tok_str(sym->v, NULL);
|
||||||
func_ind = ind;
|
func_ind = ind;
|
||||||
|
|
||||||
/* put debug symbol */
|
/* put debug symbol */
|
||||||
tcc_debug_funcstart(tcc_state, sym);
|
tcc_debug_funcstart(tcc_state, sym);
|
||||||
/* push a dummy symbol to enable local sym storage */
|
/* push a dummy symbol to enable local sym storage */
|
||||||
@ -7675,6 +7658,8 @@ static void gen_function(Sym *sym, AttributeDef *ad)
|
|||||||
ind = 0; /* for safety */
|
ind = 0; /* for safety */
|
||||||
nocode_wanted = 0x80000000;
|
nocode_wanted = 0x80000000;
|
||||||
check_vstack();
|
check_vstack();
|
||||||
|
/* do this after funcend debug info */
|
||||||
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_inline_functions(TCCState *s)
|
static void gen_inline_functions(TCCState *s)
|
||||||
@ -7698,7 +7683,7 @@ static void gen_inline_functions(TCCState *s)
|
|||||||
begin_macro(fn->func_str, 1);
|
begin_macro(fn->func_str, 1);
|
||||||
next();
|
next();
|
||||||
cur_text_section = text_section;
|
cur_text_section = text_section;
|
||||||
gen_function(sym, NULL);
|
gen_function(sym);
|
||||||
end_macro();
|
end_macro();
|
||||||
|
|
||||||
inline_generated = 1;
|
inline_generated = 1;
|
||||||
@ -7866,11 +7851,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
|||||||
the compilation unit only if they are used */
|
the compilation unit only if they are used */
|
||||||
if (sym->type.t & VT_INLINE) {
|
if (sym->type.t & VT_INLINE) {
|
||||||
struct InlineFunc *fn;
|
struct InlineFunc *fn;
|
||||||
const char *filename;
|
fn = tcc_malloc(sizeof *fn + strlen(file->filename));
|
||||||
|
strcpy(fn->filename, file->filename);
|
||||||
filename = file ? file->filename : "";
|
|
||||||
fn = tcc_malloc(sizeof *fn + strlen(filename));
|
|
||||||
strcpy(fn->filename, filename);
|
|
||||||
fn->sym = sym;
|
fn->sym = sym;
|
||||||
skip_or_save_block(&fn->func_str);
|
skip_or_save_block(&fn->func_str);
|
||||||
dynarray_add(&tcc_state->inline_fns,
|
dynarray_add(&tcc_state->inline_fns,
|
||||||
@ -7880,7 +7862,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
|||||||
cur_text_section = ad.section;
|
cur_text_section = ad.section;
|
||||||
if (!cur_text_section)
|
if (!cur_text_section)
|
||||||
cur_text_section = text_section;
|
cur_text_section = text_section;
|
||||||
gen_function(sym, &ad);
|
gen_function(sym);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
324
tccpe.c
324
tccpe.c
@ -239,8 +239,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
|
|||||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||||
#define IMAGE_SCN_TYPE_NOLOAD 0x00000002
|
|
||||||
#define IMAGE_SCN_LNK_REMOVE 0x00000800
|
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
@ -299,6 +297,7 @@ enum {
|
|||||||
sec_other ,
|
sec_other ,
|
||||||
sec_rsrc ,
|
sec_rsrc ,
|
||||||
sec_stab ,
|
sec_stab ,
|
||||||
|
sec_stabstr ,
|
||||||
sec_reloc ,
|
sec_reloc ,
|
||||||
sec_last
|
sec_last
|
||||||
};
|
};
|
||||||
@ -318,12 +317,12 @@ static const DWORD pe_sec_flags[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct section_info {
|
struct section_info {
|
||||||
int cls, ord;
|
int cls;
|
||||||
char name[32];
|
char name[32];
|
||||||
DWORD sh_addr;
|
DWORD sh_addr;
|
||||||
DWORD sh_size;
|
DWORD sh_size;
|
||||||
DWORD pe_flags;
|
DWORD pe_flags;
|
||||||
unsigned char *data;
|
Section *sec;
|
||||||
DWORD data_size;
|
DWORD data_size;
|
||||||
IMAGE_SECTION_HEADER ish;
|
IMAGE_SECTION_HEADER ish;
|
||||||
};
|
};
|
||||||
@ -359,7 +358,7 @@ struct pe_info {
|
|||||||
int subsystem;
|
int subsystem;
|
||||||
DWORD section_align;
|
DWORD section_align;
|
||||||
DWORD file_align;
|
DWORD file_align;
|
||||||
struct section_info *sec_info;
|
struct section_info **sec_info;
|
||||||
int sec_count;
|
int sec_count;
|
||||||
struct pe_import_info **imp_info;
|
struct pe_import_info **imp_info;
|
||||||
int imp_count;
|
int imp_count;
|
||||||
@ -432,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static DWORD umin(DWORD a, DWORD b)
|
||||||
ST_FN DWORD umin(DWORD a, DWORD b)
|
|
||||||
{
|
{
|
||||||
return a < b ? a : b;
|
return a < b ? a : b;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static DWORD umax(DWORD a, DWORD b)
|
static DWORD umax(DWORD a, DWORD b)
|
||||||
{
|
{
|
||||||
@ -467,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
|
|||||||
hdr->opthdr.DataDirectory[dir].Size = size;
|
hdr->opthdr.DataDirectory[dir].Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
|
struct pe_file {
|
||||||
|
FILE *op;
|
||||||
|
DWORD sum;
|
||||||
|
unsigned pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pe_fwrite(void *data, int len, struct pe_file *pf)
|
||||||
{
|
{
|
||||||
if (psum) {
|
WORD *p = data;
|
||||||
DWORD sum = *psum;
|
DWORD sum;
|
||||||
WORD *p = data;
|
int ret, i;
|
||||||
int i;
|
pf->pos += (ret = fwrite(data, 1, len, pf->op));
|
||||||
for (i = len; i > 0; i -= 2) {
|
sum = pf->sum;
|
||||||
sum += (i >= 2) ? *p++ : *(BYTE*)p;
|
for (i = len; i > 0; i -= 2) {
|
||||||
sum = (sum + (sum >> 16)) & 0xFFFF;
|
sum += (i >= 2) ? *p++ : *(BYTE*)p;
|
||||||
}
|
sum = (sum + (sum >> 16)) & 0xFFFF;
|
||||||
*psum = sum;
|
|
||||||
}
|
}
|
||||||
return len == fwrite(data, 1, len, fp) ? 0 : -1;
|
pf->sum = sum;
|
||||||
|
return len == ret ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pe_fpad(FILE *fp, DWORD new_pos)
|
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
|
||||||
{
|
{
|
||||||
DWORD pos = ftell(fp);
|
char buf[256];
|
||||||
while (++pos <= new_pos)
|
int n, diff = new_pos - pf->pos;
|
||||||
fputc(0, fp);
|
memset(buf, 0, sizeof buf);
|
||||||
|
while (diff > 0) {
|
||||||
|
diff -= n = umin(diff, sizeof buf);
|
||||||
|
fwrite(buf, n, 1, pf->op);
|
||||||
|
}
|
||||||
|
pf->pos = new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
@ -598,14 +606,14 @@ static int pe_write(struct pe_info *pe)
|
|||||||
struct pe_header pe_header = pe_template;
|
struct pe_header pe_header = pe_template;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
FILE *op;
|
struct pe_file pf = {0};
|
||||||
DWORD file_offset, sum;
|
DWORD file_offset;
|
||||||
struct section_info *si;
|
struct section_info *si;
|
||||||
IMAGE_SECTION_HEADER *psh;
|
IMAGE_SECTION_HEADER *psh;
|
||||||
TCCState *s1 = pe->s1;
|
TCCState *s1 = pe->s1;
|
||||||
|
|
||||||
op = fopen(pe->filename, "wb");
|
pf.op = fopen(pe->filename, "wb");
|
||||||
if (NULL == op) {
|
if (NULL == pf.op) {
|
||||||
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
|
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -624,7 +632,7 @@ static int pe_write(struct pe_info *pe)
|
|||||||
DWORD addr, size;
|
DWORD addr, size;
|
||||||
const char *sh_name;
|
const char *sh_name;
|
||||||
|
|
||||||
si = pe->sec_info + i;
|
si = pe->sec_info[i];
|
||||||
sh_name = si->name;
|
sh_name = si->name;
|
||||||
addr = si->sh_addr - pe->imagebase;
|
addr = si->sh_addr - pe->imagebase;
|
||||||
size = si->sh_size;
|
size = si->sh_size;
|
||||||
@ -663,20 +671,18 @@ static int pe_write(struct pe_info *pe)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe->thunk == pe->s1->sections[si->ord]) {
|
if (pe->imp_size) {
|
||||||
if (pe->imp_size) {
|
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
|
||||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
|
pe->imp_offs, pe->imp_size);
|
||||||
pe->imp_offs + addr, pe->imp_size);
|
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
|
||||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
|
pe->iat_offs, pe->iat_size);
|
||||||
pe->iat_offs + addr, pe->iat_size);
|
}
|
||||||
}
|
if (pe->exp_size) {
|
||||||
if (pe->exp_size) {
|
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
||||||
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
|
pe->exp_offs, pe->exp_size);
|
||||||
pe->exp_offs + addr, pe->exp_size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
|
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
|
||||||
|
|
||||||
psh->Characteristics = si->pe_flags;
|
psh->Characteristics = si->pe_flags;
|
||||||
psh->VirtualAddress = addr;
|
psh->VirtualAddress = addr;
|
||||||
@ -707,25 +713,29 @@ static int pe_write(struct pe_info *pe)
|
|||||||
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
||||||
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
|
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
|
||||||
|
|
||||||
sum = 0;
|
pe_fwrite(&pe_header, sizeof pe_header, &pf);
|
||||||
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
|
|
||||||
for (i = 0; i < pe->sec_count; ++i)
|
for (i = 0; i < pe->sec_count; ++i)
|
||||||
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
|
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
|
||||||
pe_fpad(op, pe->sizeofheaders);
|
|
||||||
|
file_offset = pe->sizeofheaders;
|
||||||
for (i = 0; i < pe->sec_count; ++i) {
|
for (i = 0; i < pe->sec_count; ++i) {
|
||||||
si = pe->sec_info + i;
|
Section *s;
|
||||||
psh = &si->ish;
|
si = pe->sec_info[i];
|
||||||
if (si->data_size) {
|
for (s = si->sec; s; s = s->prev) {
|
||||||
pe_fwrite(si->data, si->data_size, op, &sum);
|
pe_fpad(&pf, file_offset);
|
||||||
file_offset = psh->PointerToRawData + psh->SizeOfRawData;
|
pe_fwrite(s->data, s->data_offset, &pf);
|
||||||
pe_fpad(op, file_offset);
|
if (s->prev)
|
||||||
|
file_offset += s->prev->sh_addr - s->sh_addr;
|
||||||
}
|
}
|
||||||
|
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
|
||||||
|
pe_fpad(&pf, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pe_header.opthdr.CheckSum = sum + file_offset;
|
pf.sum += file_offset;
|
||||||
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
|
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
|
||||||
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
|
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
|
||||||
fclose (op);
|
|
||||||
|
fclose (pf.op);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
chmod(pe->filename, 0777);
|
chmod(pe->filename, 0777);
|
||||||
#endif
|
#endif
|
||||||
@ -796,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
pe_align_section(pe->thunk, 16);
|
pe_align_section(pe->thunk, 16);
|
||||||
|
|
||||||
pe->imp_offs = dll_ptr = pe->thunk->data_offset;
|
|
||||||
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
||||||
pe->iat_offs = dll_ptr + pe->imp_size;
|
|
||||||
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
|
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
|
||||||
|
dll_ptr = pe->thunk->data_offset;
|
||||||
|
thk_ptr = dll_ptr + pe->imp_size;
|
||||||
|
ent_ptr = thk_ptr + pe->iat_size;
|
||||||
|
pe->imp_offs = dll_ptr + rva_base;
|
||||||
|
pe->iat_offs = thk_ptr + rva_base;
|
||||||
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
|
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
|
||||||
|
|
||||||
thk_ptr = pe->iat_offs;
|
|
||||||
ent_ptr = pe->iat_offs + pe->iat_size;
|
|
||||||
|
|
||||||
for (i = 0; i < pe->imp_count; ++i) {
|
for (i = 0; i < pe->imp_count; ++i) {
|
||||||
IMAGE_IMPORT_DESCRIPTOR *hdr;
|
IMAGE_IMPORT_DESCRIPTOR *hdr;
|
||||||
int k, n, dllindex;
|
int k, n, dllindex;
|
||||||
@ -895,7 +904,7 @@ static void pe_build_exports(struct pe_info *pe)
|
|||||||
{
|
{
|
||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
int sym_index, sym_end;
|
int sym_index, sym_end;
|
||||||
DWORD rva_base, func_o, name_o, ord_o, str_o;
|
DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
|
||||||
IMAGE_EXPORT_DIRECTORY *hdr;
|
IMAGE_EXPORT_DIRECTORY *hdr;
|
||||||
int sym_count, ord;
|
int sym_count, ord;
|
||||||
struct pe_sort_sym **sorted, *p;
|
struct pe_sort_sym **sorted, *p;
|
||||||
@ -937,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe)
|
|||||||
pe_align_section(pe->thunk, 16);
|
pe_align_section(pe->thunk, 16);
|
||||||
dllname = tcc_basename(pe->filename);
|
dllname = tcc_basename(pe->filename);
|
||||||
|
|
||||||
pe->exp_offs = pe->thunk->data_offset;
|
base_o = pe->thunk->data_offset;
|
||||||
func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
|
func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
|
||||||
name_o = func_o + sym_count * sizeof (DWORD);
|
name_o = func_o + sym_count * sizeof (DWORD);
|
||||||
ord_o = name_o + sym_count * sizeof (DWORD);
|
ord_o = name_o + sym_count * sizeof (DWORD);
|
||||||
str_o = ord_o + sym_count * sizeof(WORD);
|
str_o = ord_o + sym_count * sizeof(WORD);
|
||||||
|
|
||||||
hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
|
hdr = section_ptr_add(pe->thunk, str_o - base_o);
|
||||||
hdr->Characteristics = 0;
|
hdr->Characteristics = 0;
|
||||||
hdr->Base = 1;
|
hdr->Base = 1;
|
||||||
hdr->NumberOfFunctions = sym_count;
|
hdr->NumberOfFunctions = sym_count;
|
||||||
@ -985,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe)
|
|||||||
if (op)
|
if (op)
|
||||||
fprintf(op, "%s\n", name);
|
fprintf(op, "%s\n", name);
|
||||||
}
|
}
|
||||||
pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
|
|
||||||
|
pe->exp_offs = base_o + rva_base;
|
||||||
|
pe->exp_size = pe->thunk->data_offset - base_o;
|
||||||
dynarray_reset(&sorted, &sym_count);
|
dynarray_reset(&sorted, &sym_count);
|
||||||
if (op)
|
if (op)
|
||||||
fclose(op);
|
fclose(op);
|
||||||
@ -994,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe)
|
|||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
static void pe_build_reloc (struct pe_info *pe)
|
static void pe_build_reloc (struct pe_info *pe)
|
||||||
{
|
{
|
||||||
DWORD offset, block_ptr, addr;
|
DWORD offset, block_ptr, sh_addr, addr;
|
||||||
int count, i;
|
int count, i;
|
||||||
ElfW_Rel *rel, *rel_end;
|
ElfW_Rel *rel, *rel_end;
|
||||||
Section *s = NULL, *sr;
|
Section *s = NULL, *sr;
|
||||||
|
struct pe_reloc_header *hdr;
|
||||||
|
|
||||||
offset = addr = block_ptr = count = i = 0;
|
sh_addr = offset = block_ptr = count = i = 0;
|
||||||
rel = rel_end = NULL;
|
rel = rel_end = NULL;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (rel < rel_end) {
|
if (rel < rel_end) {
|
||||||
int type = ELFW(R_TYPE)(rel->r_info);
|
int type = ELFW(R_TYPE)(rel->r_info);
|
||||||
addr = rel->r_offset + s->sh_addr;
|
addr = rel->r_offset + sh_addr;
|
||||||
++ rel;
|
++ rel;
|
||||||
if (type != REL_TYPE_DIRECT)
|
if (type != REL_TYPE_DIRECT)
|
||||||
continue;
|
continue;
|
||||||
@ -1022,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe)
|
|||||||
}
|
}
|
||||||
-- rel;
|
-- rel;
|
||||||
|
|
||||||
} else if (i < pe->sec_count) {
|
} else if (s) {
|
||||||
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
|
sr = s->reloc;
|
||||||
if (sr) {
|
if (sr) {
|
||||||
rel = (ElfW_Rel *)sr->data;
|
rel = (ElfW_Rel *)sr->data;
|
||||||
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
|
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
|
||||||
|
sh_addr = s->sh_addr;
|
||||||
}
|
}
|
||||||
|
s = s->prev;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (count) {
|
} else if (i < pe->sec_count) {
|
||||||
/* store the last block and ready for a new one */
|
s = pe->sec_info[i]->sec, ++i;
|
||||||
struct pe_reloc_header *hdr;
|
continue;
|
||||||
if (count & 1) /* align for DWORDS */
|
|
||||||
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
|
|
||||||
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
|
|
||||||
hdr -> offset = offset - pe->imagebase;
|
|
||||||
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rel >= rel_end)
|
} else if (!count)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* fill the last block and ready for a new one */
|
||||||
|
if (count & 1) /* align for DWORDS */
|
||||||
|
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
|
||||||
|
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
|
||||||
|
hdr -> offset = offset - pe->imagebase;
|
||||||
|
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
|
||||||
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,13 +1086,14 @@ static int pe_section_class(Section *s)
|
|||||||
if (flags & SHF_WRITE)
|
if (flags & SHF_WRITE)
|
||||||
return sec_bss;
|
return sec_bss;
|
||||||
}
|
}
|
||||||
return sec_other;
|
|
||||||
} else {
|
} else {
|
||||||
if (0 == strcmp(name, ".reloc"))
|
if (0 == strcmp(name, ".reloc"))
|
||||||
return sec_reloc;
|
return sec_reloc;
|
||||||
if (0 == memcmp(name, ".stab", 5))
|
|
||||||
return sec_stab;
|
|
||||||
}
|
}
|
||||||
|
if (0 == memcmp(name, ".stab", 5))
|
||||||
|
return name[5] ? sec_stabstr : sec_stab;
|
||||||
|
if (flags & SHF_ALLOC)
|
||||||
|
return sec_other;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,47 +1107,62 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
|
|
||||||
if (PE_DLL == pe->type)
|
if (PE_DLL == pe->type)
|
||||||
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
|
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
|
||||||
|
|
||||||
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
||||||
|
|
||||||
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
|
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
|
||||||
for (o = k = 0 ; k < sec_last; ++k) {
|
for (o = k = 0 ; k < sec_last; ++k) {
|
||||||
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
||||||
s = pe->s1->sections[i];
|
s = pe->s1->sections[i];
|
||||||
if (k == pe_section_class(s)) {
|
if (k == pe_section_class(s))
|
||||||
// printf("%s %d\n", s->name, k);
|
|
||||||
s->sh_addr = pe->imagebase;
|
|
||||||
section_order[o++] = i;
|
section_order[o++] = i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
|
si = NULL;
|
||||||
addr = pe->imagebase + 1;
|
addr = pe->imagebase + 1;
|
||||||
|
|
||||||
for (i = 0; i < o; ++i)
|
for (i = 0; i < o; ++i) {
|
||||||
{
|
|
||||||
k = section_order[i];
|
k = section_order[i];
|
||||||
s = pe->s1->sections[k];
|
s = pe->s1->sections[k];
|
||||||
c = pe_section_class(s);
|
c = pe_section_class(s);
|
||||||
si = &pe->sec_info[pe->sec_count];
|
|
||||||
|
if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
|
||||||
|
continue;
|
||||||
|
|
||||||
#ifdef PE_MERGE_DATA
|
#ifdef PE_MERGE_DATA
|
||||||
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
|
if (c == sec_bss)
|
||||||
/* append .bss to .data */
|
c = sec_data;
|
||||||
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
|
|
||||||
addr += s->data_offset;
|
|
||||||
si[-1].sh_size = addr - si[-1].sh_addr;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if (c == sec_stab && 0 == pe->s1->do_debug)
|
if (si && c == si->cls) {
|
||||||
|
/* merge with previous section */
|
||||||
|
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
|
||||||
|
} else {
|
||||||
|
si = NULL;
|
||||||
|
s->sh_addr = addr = pe_virtual_align(pe, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == sec_data && NULL == pe->thunk)
|
||||||
|
pe->thunk = s;
|
||||||
|
|
||||||
|
if (s == pe->thunk) {
|
||||||
|
pe_build_imports(pe);
|
||||||
|
pe_build_exports(pe);
|
||||||
|
}
|
||||||
|
if (s == pe->reloc)
|
||||||
|
pe_build_reloc (pe);
|
||||||
|
|
||||||
|
if (0 == s->data_offset)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (si)
|
||||||
|
goto add_section;
|
||||||
|
|
||||||
|
si = tcc_mallocz(sizeof *si);
|
||||||
|
dynarray_add(&pe->sec_info, &pe->sec_count, si);
|
||||||
|
|
||||||
strcpy(si->name, s->name);
|
strcpy(si->name, s->name);
|
||||||
si->cls = c;
|
si->cls = c;
|
||||||
si->ord = k;
|
si->sh_addr = addr;
|
||||||
si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
|
|
||||||
|
|
||||||
si->pe_flags = IMAGE_SCN_MEM_READ;
|
si->pe_flags = IMAGE_SCN_MEM_READ;
|
||||||
if (s->sh_flags & SHF_EXECINSTR)
|
if (s->sh_flags & SHF_EXECINSTR)
|
||||||
@ -1143,48 +1173,35 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
|
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
|
||||||
if (s->sh_flags & SHF_WRITE)
|
if (s->sh_flags & SHF_WRITE)
|
||||||
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
|
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
|
||||||
if (0 == (s->sh_flags & SHF_ALLOC)) {
|
if (0 == (s->sh_flags & SHF_ALLOC))
|
||||||
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
|
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
|
||||||
if (c == sec_stab)
|
|
||||||
si->pe_flags |= 0x802; //IMAGE_SCN_TYPE_NOLOAD|IMAGE_SCN_LNK_REMOVE
|
add_section:
|
||||||
|
addr += s->data_offset;
|
||||||
|
si->sh_size = addr - si->sh_addr;
|
||||||
|
if (s->sh_type != SHT_NOBITS) {
|
||||||
|
Section **ps = &si->sec;
|
||||||
|
while (*ps)
|
||||||
|
ps = &(*ps)->prev;
|
||||||
|
*ps = s, s->prev = NULL;
|
||||||
|
si->data_size = si->sh_size;
|
||||||
}
|
}
|
||||||
|
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
|
||||||
if (c == sec_data && NULL == pe->thunk)
|
|
||||||
pe->thunk = s;
|
|
||||||
|
|
||||||
if (s == pe->thunk) {
|
|
||||||
pe_build_imports(pe);
|
|
||||||
pe_build_exports(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == sec_reloc)
|
|
||||||
pe_build_reloc (pe);
|
|
||||||
|
|
||||||
if (s->data_offset)
|
|
||||||
{
|
|
||||||
if (s->sh_type != SHT_NOBITS) {
|
|
||||||
si->data = s->data;
|
|
||||||
si->data_size = s->data_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr += s->data_offset;
|
|
||||||
si->sh_size = s->data_offset;
|
|
||||||
++pe->sec_count;
|
|
||||||
}
|
|
||||||
//printf("%08x %05x %s %08x\n", si->sh_addr, si->sh_size, si->name, si->pe_flags);
|
|
||||||
}
|
}
|
||||||
|
tcc_free(section_order);
|
||||||
#if 0
|
#if 0
|
||||||
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
for (i = 1; i < pe->s1->nb_sections; ++i) {
|
||||||
Section *s = pe->s1->sections[i];
|
Section *s = pe->s1->sections[i];
|
||||||
int type = s->sh_type;
|
int type = s->sh_type;
|
||||||
int flags = s->sh_flags;
|
int flags = s->sh_flags;
|
||||||
printf("section %-16s %-10s %5x %s,%s,%s\n",
|
printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
|
||||||
s->name,
|
s->name,
|
||||||
type == SHT_PROGBITS ? "progbits" :
|
type == SHT_PROGBITS ? "progbits" :
|
||||||
type == SHT_NOBITS ? "nobits" :
|
type == SHT_NOBITS ? "nobits" :
|
||||||
type == SHT_SYMTAB ? "symtab" :
|
type == SHT_SYMTAB ? "symtab" :
|
||||||
type == SHT_STRTAB ? "strtab" :
|
type == SHT_STRTAB ? "strtab" :
|
||||||
type == SHT_RELX ? "rel" : "???",
|
type == SHT_RELX ? "rel" : "???",
|
||||||
|
s->sh_addr,
|
||||||
s->data_offset,
|
s->data_offset,
|
||||||
flags & SHF_ALLOC ? "alloc" : "",
|
flags & SHF_ALLOC ? "alloc" : "",
|
||||||
flags & SHF_WRITE ? "write" : "",
|
flags & SHF_WRITE ? "write" : "",
|
||||||
@ -1193,8 +1210,6 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
}
|
}
|
||||||
pe->s1->verbose = 2;
|
pe->s1->verbose = 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tcc_free(section_order);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1860,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||||||
else
|
else
|
||||||
if (TCC_OUTPUT_DLL == s1->output_type) {
|
if (TCC_OUTPUT_DLL == s1->output_type) {
|
||||||
pe_type = PE_DLL;
|
pe_type = PE_DLL;
|
||||||
/* need this for 'tccelf.c:relocate_section()' */
|
|
||||||
s1->output_type = TCC_OUTPUT_EXE;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pe_type = PE_EXE;
|
pe_type = PE_EXE;
|
||||||
@ -1881,24 +1894,34 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||||||
if (!s1->leading_underscore || strchr(start_symbol, '@'))
|
if (!s1->leading_underscore || strchr(start_symbol, '@'))
|
||||||
++start_symbol;
|
++start_symbol;
|
||||||
|
|
||||||
/* grab the startup code from libtcc1 */
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
if (s1->do_backtrace) {
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
|
||||||
|
tcc_add_support(s1, "bcheck.o");
|
||||||
|
#endif
|
||||||
|
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||||
|
tcc_add_support(s1, "bt-exe.o");
|
||||||
|
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||||
|
tcc_add_support(s1, "bt-dll.o");
|
||||||
|
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||||
|
tcc_add_support(s1, "bt-log.o");
|
||||||
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||||
|
tcc_add_btstub(s1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* grab the startup code from libtcc1.a */
|
||||||
#ifdef TCC_IS_NATIVE
|
#ifdef TCC_IS_NATIVE
|
||||||
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
|
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
|
||||||
#endif
|
#endif
|
||||||
set_elf_sym(symtab_section,
|
set_global_sym(s1, start_symbol, NULL, 0);
|
||||||
0, 0,
|
|
||||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
|
||||||
SHN_UNDEF, start_symbol);
|
|
||||||
|
|
||||||
if (0 == s1->nostdlib) {
|
if (0 == s1->nostdlib) {
|
||||||
static const char *libs[] = {
|
static const char *libs[] = {
|
||||||
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||||
};
|
};
|
||||||
const char **pp, *p;
|
const char **pp, *p;
|
||||||
#ifdef TCC_IS_NATIVE
|
|
||||||
if (s1->do_bounds_check)
|
|
||||||
tcc_add_support(s1, TCC_LIBBCHECK);
|
|
||||||
#endif
|
|
||||||
tcc_add_support(s1, TCC_LIBTCC1);
|
tcc_add_support(s1, TCC_LIBTCC1);
|
||||||
for (pp = libs; 0 != (p = *pp); ++pp) {
|
for (pp = libs; 0 != (p = *pp); ++pp) {
|
||||||
if (*p)
|
if (*p)
|
||||||
@ -1907,6 +1930,10 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* need this for 'tccelf.c:relocate_section()' */
|
||||||
|
if (TCC_OUTPUT_DLL == s1->output_type)
|
||||||
|
s1->output_type = TCC_OUTPUT_EXE;
|
||||||
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
||||||
pe_type = PE_RUN;
|
pe_type = PE_RUN;
|
||||||
pe->type = pe_type;
|
pe->type = pe_type;
|
||||||
@ -1970,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||||||
pe.filename = filename;
|
pe.filename = filename;
|
||||||
pe.s1 = s1;
|
pe.s1 = s1;
|
||||||
|
|
||||||
tcc_add_runtime(s1);
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
tcc_add_bcheck(s1);
|
||||||
|
#endif
|
||||||
|
tcc_add_pragma_libs(s1);
|
||||||
pe_add_runtime(s1, &pe);
|
pe_add_runtime(s1, &pe);
|
||||||
resolve_common_syms(s1);
|
resolve_common_syms(s1);
|
||||||
pe_set_options(s1, &pe);
|
pe_set_options(s1, &pe);
|
||||||
@ -1995,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
else
|
else
|
||||||
ret = pe_write(&pe);
|
ret = pe_write(&pe);
|
||||||
tcc_free(pe.sec_info);
|
dynarray_reset(&pe.sec_info, &pe.sec_count);
|
||||||
} else {
|
} else {
|
||||||
#ifdef TCC_IS_NATIVE
|
#ifdef TCC_IS_NATIVE
|
||||||
pe.thunk = data_section;
|
pe.thunk = data_section;
|
||||||
|
17
tccpp.c
17
tccpp.c
@ -109,9 +109,7 @@ ST_FUNC void expect(const char *msg)
|
|||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Custom allocator for tiny objects */
|
/* Custom allocator for tiny objects */
|
||||||
|
|
||||||
#ifndef __BOUNDS_CHECKING_ON
|
|
||||||
#define USE_TAL
|
#define USE_TAL
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USE_TAL
|
#ifndef USE_TAL
|
||||||
#define tal_free(al, p) tcc_free(p)
|
#define tal_free(al, p) tcc_free(p)
|
||||||
@ -250,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
|
|||||||
tail_call:
|
tail_call:
|
||||||
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
|
is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
|
||||||
if ((!p || is_own) && size <= al->limit) {
|
if ((!p || is_own) && size <= al->limit) {
|
||||||
if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
|
if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
|
||||||
header = (tal_header_t *)al->p;
|
header = (tal_header_t *)al->p;
|
||||||
header->size = adj_size;
|
header->size = adj_size;
|
||||||
#ifdef TAL_DEBUG
|
#ifdef TAL_DEBUG
|
||||||
@ -1958,7 +1956,11 @@ include_done:
|
|||||||
if (tok == TOK_STR) {
|
if (tok == TOK_STR) {
|
||||||
if (file->true_filename == file->filename)
|
if (file->true_filename == file->filename)
|
||||||
file->true_filename = tcc_strdup(file->filename);
|
file->true_filename = tcc_strdup(file->filename);
|
||||||
tcc_debug_putfile(s1, (char *)tokc.str.data);
|
/* prepend directory from real file */
|
||||||
|
pstrcpy(buf, sizeof buf, file->true_filename);
|
||||||
|
*tcc_basename(buf) = 0;
|
||||||
|
pstrcat(buf, sizeof buf, (char *)tokc.str.data);
|
||||||
|
tcc_debug_putfile(s1, buf);
|
||||||
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
} else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
@ -3529,9 +3531,6 @@ no_subst:
|
|||||||
/* return next token with macro substitution */
|
/* return next token with macro substitution */
|
||||||
ST_FUNC void next(void)
|
ST_FUNC void next(void)
|
||||||
{
|
{
|
||||||
/* generate line number info */
|
|
||||||
if (tcc_state->do_debug)
|
|
||||||
tcc_debug_line(tcc_state);
|
|
||||||
redo:
|
redo:
|
||||||
if (parse_flags & PARSE_FLAG_SPACES)
|
if (parse_flags & PARSE_FLAG_SPACES)
|
||||||
next_nomacro_spc();
|
next_nomacro_spc();
|
||||||
@ -3607,6 +3606,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
|
|||||||
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
|
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
|
||||||
if (is_asm)
|
if (is_asm)
|
||||||
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
|
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
|
||||||
|
if (s1->output_type == TCC_OUTPUT_MEMORY)
|
||||||
|
cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
|
||||||
if (s1->cmdline_incl.size)
|
if (s1->cmdline_incl.size)
|
||||||
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
|
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
|
||||||
//printf("%s\n", (char*)cstr.data);
|
//printf("%s\n", (char*)cstr.data);
|
||||||
@ -3657,7 +3658,7 @@ ST_FUNC void tccpp_new(TCCState *s)
|
|||||||
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
|
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
|
||||||
tok_str_new(&tokstr_buf);
|
tok_str_new(&tokstr_buf);
|
||||||
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
|
tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
|
||||||
|
|
||||||
tok_ident = TOK_IDENT;
|
tok_ident = TOK_IDENT;
|
||||||
p = tcc_keywords;
|
p = tcc_keywords;
|
||||||
while (*p) {
|
while (*p) {
|
||||||
|
341
tccrun.c
341
tccrun.c
@ -23,29 +23,38 @@
|
|||||||
/* only native compiler supports -run */
|
/* only native compiler supports -run */
|
||||||
#ifdef TCC_IS_NATIVE
|
#ifdef TCC_IS_NATIVE
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
typedef struct rt_context
|
||||||
|
{
|
||||||
|
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
|
||||||
|
Stab_Sym *stab_sym, *stab_sym_end;
|
||||||
|
char *stab_str;
|
||||||
|
ElfW(Sym) *esym_start, *esym_end;
|
||||||
|
char *elf_str;
|
||||||
|
addr_t prog_base;
|
||||||
|
void *bounds_start;
|
||||||
|
struct rt_context *next;
|
||||||
|
/* <-- */
|
||||||
|
int num_callers;
|
||||||
|
addr_t ip, fp, sp;
|
||||||
|
void *top_func;
|
||||||
|
jmp_buf jmp_buf;
|
||||||
|
char do_jmp;
|
||||||
|
} rt_context;
|
||||||
|
|
||||||
|
static rt_context g_rtctxt;
|
||||||
|
static void set_exception_handler(void);
|
||||||
|
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
|
||||||
|
static void rt_exit(int code);
|
||||||
|
#endif /* CONFIG_TCC_BACKTRACE */
|
||||||
|
|
||||||
|
/* defined when included from lib/bt.c */
|
||||||
|
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# include <sys/mman.h>
|
# include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
|
||||||
static void set_exception_handler(void);
|
|
||||||
#ifdef _WIN32
|
|
||||||
static DWORD s1_for_run_idx;
|
|
||||||
void set_s1_for_run(TCCState *s)
|
|
||||||
{
|
|
||||||
if (!s1_for_run_idx)
|
|
||||||
s1_for_run_idx = TlsAlloc();
|
|
||||||
TlsSetValue(s1_for_run_idx, s);
|
|
||||||
}
|
|
||||||
#define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx))
|
|
||||||
#else
|
|
||||||
/* XXX: add tls support for linux */
|
|
||||||
static TCCState *s1_for_run;
|
|
||||||
#define set_s1_for_run(s) (s1_for_run = s)
|
|
||||||
#define get_s1_for_run() s1_for_run
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
|
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
|
||||||
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
|
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
|
||||||
|
|
||||||
@ -113,72 +122,73 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
tcc_free(s1->runtime_mem);
|
tcc_free(s1->runtime_mem);
|
||||||
if (get_s1_for_run() == s1)
|
}
|
||||||
set_s1_for_run(NULL);
|
|
||||||
|
static void run_cdtors(TCCState *s1, const char *start, const char *end)
|
||||||
|
{
|
||||||
|
void **a = tcc_get_symbol(s1, start);
|
||||||
|
void **b = tcc_get_symbol(s1, end);
|
||||||
|
while (a != b)
|
||||||
|
((void(*)(void))*a++)();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* launch the compiled program with the given arguments */
|
/* launch the compiled program with the given arguments */
|
||||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
{
|
{
|
||||||
/* PE target overwrites runtime_main */
|
int (*prog_main)(int, char **), ret;
|
||||||
#ifndef TCC_TARGET_PE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
typedef void (*init_array_func)(int, char **, char **);
|
rt_context *rc = &g_rtctxt;
|
||||||
typedef void (*fini_array_func)(void);
|
|
||||||
init_array_func *__init_array_start;
|
|
||||||
init_array_func *__init_array_end;
|
|
||||||
fini_array_func *__fini_array_start;
|
|
||||||
fini_array_func *__fini_array_end;
|
|
||||||
#endif
|
#endif
|
||||||
int i;
|
|
||||||
int ret;
|
|
||||||
int (*prog_main)(int, char **);
|
|
||||||
|
|
||||||
s1->runtime_main = s1->nostdlib ? "_start" : "main";
|
s1->runtime_main = s1->nostdlib ? "_start" : "main";
|
||||||
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
|
if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
if (s1->do_debug)
|
||||||
|
tcc_add_symbol(s1, "exit", rt_exit);
|
||||||
|
#endif
|
||||||
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
|
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
memset(rc, 0, sizeof *rc);
|
||||||
if (s1->do_debug) {
|
if (s1->do_debug) {
|
||||||
|
void *p;
|
||||||
|
rc->stab_sym = (Stab_Sym *)stab_section->data;
|
||||||
|
rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
|
||||||
|
rc->stab_str = (char *)stab_section->link->data;
|
||||||
|
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
|
||||||
|
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
||||||
|
rc->elf_str = (char *)symtab_section->link->data;
|
||||||
|
rc->top_func = tcc_get_symbol(s1, "main");
|
||||||
|
rc->num_callers = s1->rt_num_callers;
|
||||||
|
rc->do_jmp = 1;
|
||||||
|
if ((p = tcc_get_symbol(s1, "__rt_error")))
|
||||||
|
*(void**)p = _rt_error;
|
||||||
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
if (s1->do_bounds_check) {
|
||||||
|
if ((p = tcc_get_symbol(s1, "__bound_init")))
|
||||||
|
((void(*)(void*))p)(bounds_section->data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
s1->rt_prog_main = prog_main;
|
|
||||||
/* set global state pointer for exception handlers*/
|
|
||||||
set_s1_for_run(s1);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errno = 0; /* clean errno value */
|
errno = 0; /* clean errno value */
|
||||||
|
fflush(stdout);
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
fflush(stderr);
|
||||||
if (s1->do_bounds_check)
|
run_cdtors(s1, "__init_array_start", "__init_array_end");
|
||||||
/* set error function */
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
|
if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
#ifndef TCC_TARGET_PE
|
ret = prog_main(argc, argv);
|
||||||
__init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
|
|
||||||
__init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
|
|
||||||
__fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
|
|
||||||
__fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
|
|
||||||
|
|
||||||
if (__init_array_start && __init_array_end) {
|
|
||||||
i = 0;
|
|
||||||
while (&__init_array_start[i] != __init_array_end)
|
|
||||||
(*__init_array_start[i++])(argc, argv, environ);
|
|
||||||
}
|
}
|
||||||
#endif
|
run_cdtors(s1, "__fini_array_start", "__fini_array_end");
|
||||||
|
if ((s1->dflag & 16) && ret)
|
||||||
ret = (*prog_main)(argc, argv);
|
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
|
||||||
|
|
||||||
#ifndef TCC_TARGET_PE
|
|
||||||
if (__fini_array_start && __fini_array_end) {
|
|
||||||
i = 0;
|
|
||||||
while (&__fini_array_end[i] != __fini_array_start)
|
|
||||||
(*__fini_array_end[--i])();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,11 +346,10 @@ static void win64_del_function_table(void *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif //ndef CONFIG_TCC_BACKTRACE_ONLY
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
|
||||||
#define INCLUDE_STACK_SIZE 32
|
|
||||||
static int rt_vprintf(const char *fmt, va_list ap)
|
static int rt_vprintf(const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int ret = vfprintf(stderr, fmt, ap);
|
int ret = vfprintf(stderr, fmt, ap);
|
||||||
@ -358,21 +367,22 @@ static int rt_printf(const char *fmt, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define INCLUDE_STACK_SIZE 32
|
||||||
|
|
||||||
/* print the position in the source file of PC value 'pc' by reading
|
/* print the position in the source file of PC value 'pc' by reading
|
||||||
the stabs debug information */
|
the stabs debug information */
|
||||||
static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
|
||||||
|
const char *msg, const char *skip)
|
||||||
{
|
{
|
||||||
char func_name[128];
|
char func_name[128];
|
||||||
addr_t func_addr, last_pc, pc;
|
addr_t func_addr, last_pc, pc;
|
||||||
const char *incl_files[INCLUDE_STACK_SIZE];
|
const char *incl_files[INCLUDE_STACK_SIZE];
|
||||||
int incl_index, last_incl_index, len, last_line_num, i;
|
int incl_index, last_incl_index, len, last_line_num, i;
|
||||||
const char *str, *p;
|
const char *str, *p;
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
Stab_Sym *sym;
|
||||||
|
|
||||||
ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
|
next:
|
||||||
Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
|
|
||||||
char *stab_str = NULL;
|
|
||||||
char *elf_str = NULL;
|
|
||||||
|
|
||||||
func_name[0] = '\0';
|
func_name[0] = '\0';
|
||||||
func_addr = 0;
|
func_addr = 0;
|
||||||
incl_index = 0;
|
incl_index = 0;
|
||||||
@ -380,19 +390,8 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
|||||||
last_line_num = 1;
|
last_line_num = 1;
|
||||||
last_incl_index = 0;
|
last_incl_index = 0;
|
||||||
|
|
||||||
if (stab_section) {
|
for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
|
||||||
stab_sym = (Stab_Sym *)stab_section->data;
|
str = rc->stab_str + sym->n_strx;
|
||||||
stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
|
|
||||||
stab_str = (char *) stab_section->link->data;
|
|
||||||
}
|
|
||||||
if (symtab_section) {
|
|
||||||
esym_start = (ElfW(Sym) *)(symtab_section->data);
|
|
||||||
esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
|
||||||
elf_str = (char *) symtab_section->link->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
|
|
||||||
str = stab_str + sym->n_strx;
|
|
||||||
pc = sym->n_value;
|
pc = sym->n_value;
|
||||||
|
|
||||||
switch(sym->n_type) {
|
switch(sym->n_type) {
|
||||||
@ -406,16 +405,18 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
|||||||
if (sym->n_strx == 0) /* end of function */
|
if (sym->n_strx == 0) /* end of function */
|
||||||
goto rel_pc;
|
goto rel_pc;
|
||||||
abs_pc:
|
abs_pc:
|
||||||
if (sizeof pc == 8)
|
if (sizeof sym->n_value < PTR_SIZE) {
|
||||||
/* Stab_Sym.n_value is only 32bits */
|
/* Stab_Sym.n_value is only 32bits */
|
||||||
pc |= wanted_pc & 0xffffffff00000000ULL;
|
//fprintf(stderr, "pc = %p %p %p\n", pc, rc->prog_base, wanted_pc), fflush(stderr);
|
||||||
|
pc += rc->prog_base;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
rel_pc:
|
rel_pc:
|
||||||
pc += func_addr;
|
pc += func_addr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc > wanted_pc && wanted_pc > last_pc)
|
if (pc >= wanted_pc && wanted_pc >= last_pc)
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
switch(sym->n_type) {
|
switch(sym->n_type) {
|
||||||
@ -434,8 +435,6 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
|||||||
last_pc = pc;
|
last_pc = pc;
|
||||||
last_line_num = sym->n_desc;
|
last_line_num = sym->n_desc;
|
||||||
last_incl_index = incl_index;
|
last_incl_index = incl_index;
|
||||||
if (pc == wanted_pc)
|
|
||||||
goto found;
|
|
||||||
break;
|
break;
|
||||||
/* include files */
|
/* include files */
|
||||||
case N_BINCL:
|
case N_BINCL:
|
||||||
@ -468,31 +467,38 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_name[0] = '\0';
|
||||||
|
func_addr = 0;
|
||||||
|
last_incl_index = 0;
|
||||||
|
|
||||||
/* we try symtab symbols (no line number info) */
|
/* we try symtab symbols (no line number info) */
|
||||||
for (esym = esym_start + 1; esym < esym_end; ++esym) {
|
for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
|
||||||
int type = ELFW(ST_TYPE)(esym->st_info);
|
int type = ELFW(ST_TYPE)(esym->st_info);
|
||||||
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
|
if (type == STT_FUNC || type == STT_GNU_IFUNC) {
|
||||||
if (wanted_pc >= esym->st_value &&
|
if (wanted_pc >= esym->st_value &&
|
||||||
wanted_pc < esym->st_value + esym->st_size) {
|
wanted_pc < esym->st_value + esym->st_size) {
|
||||||
pstrcpy(func_name, sizeof(func_name),
|
pstrcpy(func_name, sizeof(func_name),
|
||||||
elf_str + esym->st_name);
|
rc->elf_str + esym->st_name);
|
||||||
func_addr = esym->st_value;
|
func_addr = esym->st_value;
|
||||||
last_incl_index = 0;
|
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* did not find any info: */
|
|
||||||
rt_printf("%s %p ???", msg, (void*)wanted_pc);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
found:
|
if ((rc = rc->next))
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
found:
|
||||||
i = last_incl_index;
|
i = last_incl_index;
|
||||||
if (i > 0)
|
if (i > 0) {
|
||||||
rt_printf("%s:%d: ", incl_files[--i], last_line_num);
|
str = incl_files[--i];
|
||||||
rt_printf("%s %p", msg, (void*)wanted_pc);
|
if (skip[0] && strstr(str, skip))
|
||||||
if (func_name[0] != '\0')
|
return (addr_t)-1;
|
||||||
rt_printf(" %s()", func_name);
|
rt_printf("%s:%d: ", str, last_line_num);
|
||||||
|
} else
|
||||||
|
rt_printf("%08llx : ", (long long)wanted_pc);
|
||||||
|
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
|
||||||
|
#if 0
|
||||||
if (--i >= 0) {
|
if (--i >= 0) {
|
||||||
rt_printf(" (included from ");
|
rt_printf(" (included from ");
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -503,48 +509,79 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
|
|||||||
}
|
}
|
||||||
rt_printf(")");
|
rt_printf(")");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return func_addr;
|
return func_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct rt_context {
|
|
||||||
addr_t ip, fp, sp, pc;
|
|
||||||
} rt_context;
|
|
||||||
|
|
||||||
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
|
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
|
||||||
|
|
||||||
|
static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
rt_context *rc = &g_rtctxt;
|
||||||
|
addr_t pc = 0;
|
||||||
|
char skip[100];
|
||||||
|
int i, level, ret, n;
|
||||||
|
const char *a, *b, *msg;
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
/* we're called from tcc_backtrace. */
|
||||||
|
rc->fp = (addr_t)fp;
|
||||||
|
rc->ip = (addr_t)ip;
|
||||||
|
msg = "";
|
||||||
|
} else {
|
||||||
|
/* we're called from signal/exception handler */
|
||||||
|
msg = "RUNTIME ERROR: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
skip[0] = 0;
|
||||||
|
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */
|
||||||
|
if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
|
||||||
|
memcpy(skip, a, b - a), skip[b - a] = 0;
|
||||||
|
fmt = b + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = rc->num_callers ? rc->num_callers : 6;
|
||||||
|
for (i = level = 0; level < n; i++) {
|
||||||
|
ret = rt_get_caller_pc(&pc, rc, i);
|
||||||
|
a = "%s";
|
||||||
|
if (ret != -1) {
|
||||||
|
pc = rt_printline(rc, pc, level ? "by" : "at", skip);
|
||||||
|
if (pc == (addr_t)-1)
|
||||||
|
continue;
|
||||||
|
a = ": %s";
|
||||||
|
}
|
||||||
|
if (level == 0) {
|
||||||
|
rt_printf(a, msg);
|
||||||
|
rt_vprintf(fmt, ap);
|
||||||
|
} else if (ret == -1)
|
||||||
|
break;
|
||||||
|
rt_printf("\n");
|
||||||
|
if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
|
||||||
|
break;
|
||||||
|
++level;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc->ip = rc->fp = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* emit a run time error at position 'pc' */
|
/* emit a run time error at position 'pc' */
|
||||||
static void rt_error(rt_context *rc, const char *fmt, ...)
|
static int rt_error(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
addr_t pc;
|
int ret;
|
||||||
int i;
|
|
||||||
TCCState *s1;
|
|
||||||
|
|
||||||
s1 = get_s1_for_run();
|
|
||||||
if (*fmt == ' ') {
|
|
||||||
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
|
|
||||||
fmt = *s1->rt_bound_error_msg;
|
|
||||||
else
|
|
||||||
++fmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
rt_printf("Runtime error: ");
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
rt_vprintf(fmt, ap);
|
ret = _rt_error(0, 0, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
rt_printf("\n");
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (!s1)
|
static void rt_exit(int code)
|
||||||
return;
|
{
|
||||||
|
rt_context *rc = &g_rtctxt;
|
||||||
for(i=0; i<s1->rt_num_callers; i++) {
|
if (rc->do_jmp)
|
||||||
if (rt_get_caller_pc(&pc, rc, i) < 0)
|
longjmp(rc->jmp_buf, code ? code : 256);
|
||||||
break;
|
exit(code);
|
||||||
pc = rt_printline(s1, pc, i ? "by" : "at");
|
|
||||||
rt_printf("\n");
|
|
||||||
if (pc == (addr_t)s1->rt_prog_main && pc)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
@ -621,36 +658,36 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
|
|||||||
/* signal handler for fatal errors */
|
/* signal handler for fatal errors */
|
||||||
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||||
{
|
{
|
||||||
rt_context rc;
|
rt_context *rc = &g_rtctxt;
|
||||||
|
rt_getcontext(puc, rc);
|
||||||
|
|
||||||
rt_getcontext(puc, &rc);
|
|
||||||
switch(signum) {
|
switch(signum) {
|
||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
switch(siginf->si_code) {
|
switch(siginf->si_code) {
|
||||||
case FPE_INTDIV:
|
case FPE_INTDIV:
|
||||||
case FPE_FLTDIV:
|
case FPE_FLTDIV:
|
||||||
rt_error(&rc, "division by zero");
|
rt_error("division by zero");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rt_error(&rc, "floating point exception");
|
rt_error("floating point exception");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SIGBUS:
|
case SIGBUS:
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
rt_error(&rc, " dereferencing invalid pointer");
|
rt_error("invalid memory access");
|
||||||
break;
|
break;
|
||||||
case SIGILL:
|
case SIGILL:
|
||||||
rt_error(&rc, "illegal instruction");
|
rt_error("illegal instruction");
|
||||||
break;
|
break;
|
||||||
case SIGABRT:
|
case SIGABRT:
|
||||||
rt_error(&rc, "abort() called");
|
rt_error("abort() called");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rt_error(&rc, "caught signal %d", signum);
|
rt_error("caught signal %d", signum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exit(255);
|
rt_exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SA_SIGINFO
|
#ifndef SA_SIGINFO
|
||||||
@ -664,7 +701,7 @@ static void set_exception_handler(void)
|
|||||||
/* install TCC signal handlers to print debug info on fatal
|
/* install TCC signal handlers to print debug info on fatal
|
||||||
runtime errors */
|
runtime errors */
|
||||||
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||||
#ifdef SIGSTKSZ
|
#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
|
||||||
sigact.sa_flags |= SA_ONSTACK;
|
sigact.sa_flags |= SA_ONSTACK;
|
||||||
#endif
|
#endif
|
||||||
sigact.sa_sigaction = sig_error;
|
sigact.sa_sigaction = sig_error;
|
||||||
@ -674,7 +711,7 @@ static void set_exception_handler(void)
|
|||||||
sigaction(SIGSEGV, &sigact, NULL);
|
sigaction(SIGSEGV, &sigact, NULL);
|
||||||
sigaction(SIGBUS, &sigact, NULL);
|
sigaction(SIGBUS, &sigact, NULL);
|
||||||
sigaction(SIGABRT, &sigact, NULL);
|
sigaction(SIGABRT, &sigact, NULL);
|
||||||
#ifdef SIGSTKSZ
|
#if 0//def SIGSTKSZ
|
||||||
/* This allows stack overflow to be reported instead of a SEGV */
|
/* This allows stack overflow to be reported instead of a SEGV */
|
||||||
{
|
{
|
||||||
stack_t ss;
|
stack_t ss;
|
||||||
@ -689,32 +726,35 @@ static void set_exception_handler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else /* WIN32 */
|
#else /* WIN32 */
|
||||||
|
|
||||||
/* signal handler for fatal errors */
|
/* signal handler for fatal errors */
|
||||||
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||||
{
|
{
|
||||||
rt_context rc;
|
rt_context *rc = &g_rtctxt;
|
||||||
unsigned code;
|
unsigned code;
|
||||||
|
rt_getcontext(ex_info->ContextRecord, rc);
|
||||||
|
|
||||||
rt_getcontext(ex_info->ContextRecord, &rc);
|
|
||||||
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
|
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
|
||||||
case EXCEPTION_ACCESS_VIOLATION:
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
rt_error(&rc, " access violation");
|
rt_error("invalid memory access");
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_STACK_OVERFLOW:
|
case EXCEPTION_STACK_OVERFLOW:
|
||||||
rt_error(&rc, "stack overflow");
|
rt_error("stack overflow");
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||||
rt_error(&rc, "division by zero");
|
rt_error("division by zero");
|
||||||
break;
|
break;
|
||||||
case EXCEPTION_BREAKPOINT:
|
case EXCEPTION_BREAKPOINT:
|
||||||
case EXCEPTION_SINGLE_STEP:
|
case EXCEPTION_SINGLE_STEP:
|
||||||
rc.ip = *(addr_t*)rc.sp;
|
rc->ip = *(addr_t*)rc->sp;
|
||||||
rt_error(&rc, "^breakpoint/single-step exception:");
|
rt_error("breakpoint/single-step exception:");
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
default:
|
default:
|
||||||
rt_error(&rc, "caught exception %08x", code);
|
rt_error("caught exception %08x", code);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (rc->do_jmp)
|
||||||
|
rt_exit(255);
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +847,6 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif /* CONFIG_TCC_BACKTRACE */
|
#endif /* CONFIG_TCC_BACKTRACE */
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
#ifdef CONFIG_TCC_STATIC
|
#ifdef CONFIG_TCC_STATIC
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ endif
|
|||||||
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||||
DISAS = objdump -d
|
DISAS = objdump -d
|
||||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
||||||
|
Q = # >/dev/null 2>&1
|
||||||
|
|
||||||
all test :
|
all test :
|
||||||
$(MAKE) clean-s
|
$(MAKE) clean-s
|
||||||
@ -88,7 +89,7 @@ hello-run: ../examples/ex1.c
|
|||||||
|
|
||||||
libtes%: libtcc_tes%$(EXESUF)
|
libtes%: libtcc_tes%$(EXESUF)
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
./libtcc_tes$*$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES)
|
./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
|
||||||
|
|
||||||
libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC)
|
libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC)
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||||
@ -105,22 +106,24 @@ test.ref: tcctest.c
|
|||||||
# auto test
|
# auto test
|
||||||
test1 test1b: tcctest.c test.ref
|
test1 test1b: tcctest.c test.ref
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(TCC) -run $< > test.out1
|
$(TCC) -w -run $< > test.out1 $Q
|
||||||
@diff -u test.ref test.out1 && echo "Auto Test OK"
|
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
|
||||||
|
|
||||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||||
test2 test2b: tcctest.c test.ref
|
test2 test2b: tcctest.c test.ref
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
|
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2 $Q
|
||||||
@diff -u test.ref test.out2 && echo "Auto Test2 OK"
|
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
|
||||||
|
|
||||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||||
test3 test3b: tcctest.c test.ref
|
test3 test3b: tcctest.c test.ref
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
|
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3 $Q
|
||||||
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
|
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
|
||||||
|
|
||||||
test%b : TCCFLAGS += -b
|
AUTO_TEST = Auto Test
|
||||||
|
test%b : TCCFLAGS += -b -bt1
|
||||||
|
test%b : AUTO_TEST = Auto Bound-Test
|
||||||
|
|
||||||
# binary output test
|
# binary output test
|
||||||
test4: tcctest.c test.ref
|
test4: tcctest.c test.ref
|
||||||
@ -129,21 +132,21 @@ test4: tcctest.c test.ref
|
|||||||
$(TCC) -c -o tcctest3.o $<
|
$(TCC) -c -o tcctest3.o $<
|
||||||
$(TCC) -o tcctest3 tcctest3.o
|
$(TCC) -o tcctest3 tcctest3.o
|
||||||
./tcctest3 > test3.out
|
./tcctest3 > test3.out
|
||||||
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
|
||||||
# dynamic output
|
# dynamic output
|
||||||
$(TCC) -o tcctest1 $<
|
$(TCC) -o tcctest1 $<
|
||||||
./tcctest1 > test1.out
|
./tcctest1 > test1.out
|
||||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
|
||||||
# dynamic output + bound check
|
# dynamic output + bound check
|
||||||
$(TCC) -b -o tcctest4 $<
|
$(TCC) -b -o tcctest4 $<
|
||||||
./tcctest4 > test4.out
|
./tcctest4 > test4.out
|
||||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
|
||||||
|
|
||||||
test4_static: tcctest.c test.ref
|
test4_static: tcctest.c test.ref
|
||||||
# static output.
|
# static output.
|
||||||
$(TCC) -static -o tcctest2 $<
|
$(TCC) -static -o tcctest2 $<
|
||||||
./tcctest2 > test2.out
|
./tcctest2 > test2.out
|
||||||
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
|
||||||
|
|
||||||
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
||||||
dlltest:
|
dlltest:
|
||||||
@ -164,32 +167,29 @@ memtest:
|
|||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
$(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
||||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
|
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
|
||||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
|
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
|
||||||
|
|
||||||
|
|
||||||
# memory and bound check auto test
|
# memory and bound check auto test
|
||||||
BOUNDS_OK = 1 4 8 10 14 16 18
|
BOUNDS_OK = 1 4 8 10 14 16
|
||||||
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
|
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
|
||||||
|
|
||||||
btest: boundtest.c
|
btest: boundtest.c
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
@for i in $(BOUNDS_OK); do \
|
@for i in $(BOUNDS_OK); do \
|
||||||
echo ; echo --- boundtest $$i ---; \
|
|
||||||
if $(TCC) -b -run $< $$i ; then \
|
if $(TCC) -b -run $< $$i ; then \
|
||||||
echo succeeded as expected; \
|
echo "- Test $$i succeeded as expected" ; \
|
||||||
else\
|
else\
|
||||||
echo Failed positive test $$i ; exit 1 ; \
|
echo "- Failed positive test $$i" ; exit 1 ; \
|
||||||
fi ;\
|
fi ;\
|
||||||
done ;\
|
done ;\
|
||||||
for i in $(BOUNDS_FAIL); do \
|
for i in $(BOUNDS_FAIL); do \
|
||||||
echo ; echo --- boundtest $$i ---; \
|
if $(TCC) -b -bt1 -run $< $$i ; then \
|
||||||
if $(TCC) -b -run $< $$i ; then \
|
echo "- Failed negative test $$i" ; exit 1 ;\
|
||||||
echo Failed negative test $$i ; exit 1 ;\
|
|
||||||
else\
|
else\
|
||||||
echo failed as expected; \
|
echo "- Test $$i failed as expected" ; \
|
||||||
fi ;\
|
fi ;\
|
||||||
done ;\
|
done ;\
|
||||||
echo; echo Bound test OK
|
echo Bound test OK
|
||||||
|
|
||||||
# speed test
|
# speed test
|
||||||
speedtest: ex2 ex3
|
speedtest: ex2 ex3
|
||||||
|
@ -50,15 +50,12 @@ int test4(void)
|
|||||||
int i, sum = 0;
|
int i, sum = 0;
|
||||||
int *tab4;
|
int *tab4;
|
||||||
|
|
||||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
|
||||||
|
|
||||||
tab4 = malloc(20 * sizeof(int));
|
tab4 = malloc(20 * sizeof(int));
|
||||||
for(i=0;i<20;i++) {
|
for(i=0;i<20;i++) {
|
||||||
sum += tab4[i];
|
sum += tab4[i];
|
||||||
}
|
}
|
||||||
free(tab4);
|
free(tab4);
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,15 +65,12 @@ int test5(void)
|
|||||||
int i, sum = 0;
|
int i, sum = 0;
|
||||||
int *tab4;
|
int *tab4;
|
||||||
|
|
||||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
|
||||||
|
|
||||||
tab4 = malloc(20 * sizeof(int));
|
tab4 = malloc(20 * sizeof(int));
|
||||||
for(i=0;i<21;i++) {
|
for(i=0;i<21;i++) {
|
||||||
sum += tab4[i];
|
sum += tab4[i];
|
||||||
}
|
}
|
||||||
free(tab4);
|
free(tab4);
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,16 +192,12 @@ int test16()
|
|||||||
char *demo = "This is only a test.";
|
char *demo = "This is only a test.";
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
|
||||||
|
|
||||||
p = alloca(16);
|
p = alloca(16);
|
||||||
strcpy(p,"12345678901234");
|
strcpy(p,"12345678901234");
|
||||||
printf("alloca: p is %s\n", p);
|
|
||||||
|
|
||||||
/* Test alloca embedded in a larger expression */
|
/* Test alloca embedded in a larger expression */
|
||||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,211 +207,11 @@ int test17()
|
|||||||
char *demo = "This is only a test.";
|
char *demo = "This is only a test.";
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
|
||||||
|
|
||||||
p = alloca(16);
|
p = alloca(16);
|
||||||
strcpy(p,"12345678901234");
|
strcpy(p,"12345678901234");
|
||||||
printf("alloca: p is %s\n", p);
|
|
||||||
|
|
||||||
/* Test alloca embedded in a larger expression */
|
/* Test alloca embedded in a larger expression */
|
||||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
|
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
|
||||||
|
|
||||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
|
|
||||||
|
|
||||||
extern void __bound_never_fatal (int neverfatal);
|
|
||||||
extern const char *__bound_error_msg;
|
|
||||||
|
|
||||||
static void init18(char *a, char *b)
|
|
||||||
{
|
|
||||||
memset (a, 'a', 10);
|
|
||||||
a[3] = 0;
|
|
||||||
a[9] = 0;
|
|
||||||
memset (b, 'b', 10);
|
|
||||||
__bound_error_msg = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ok (catch all errors) */
|
|
||||||
int test18()
|
|
||||||
{
|
|
||||||
char pad1[10];
|
|
||||||
char a[10];
|
|
||||||
char pad2[10];
|
|
||||||
char b[10];
|
|
||||||
char pad3[10];
|
|
||||||
|
|
||||||
memset (pad1, 0, sizeof(pad1));
|
|
||||||
memset (pad2, 0, sizeof(pad2));
|
|
||||||
memset (pad3, 0, sizeof(pad3));
|
|
||||||
|
|
||||||
/* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
|
|
||||||
__bound_never_fatal (-2);
|
|
||||||
|
|
||||||
/* memcpy */
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[1],&b[0],10);
|
|
||||||
CHECK("memcpy dest");
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[0],&b[1],10);
|
|
||||||
CHECK("memcpy src");
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[0],&a[3],4);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[3],&a[0],4);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
|
|
||||||
/* memcmp */
|
|
||||||
init18(a,b);
|
|
||||||
memcmp(&b[1],&b[0],10);
|
|
||||||
CHECK("memcmp s1");
|
|
||||||
init18(a,b);
|
|
||||||
memcmp(&b[0],&b[1],10);
|
|
||||||
CHECK("memcmp s2");
|
|
||||||
|
|
||||||
/* memmove */
|
|
||||||
init18(a,b);
|
|
||||||
memmove(&b[1],&b[0],10);
|
|
||||||
CHECK("memmove dest");
|
|
||||||
init18(a,b);
|
|
||||||
memmove(&b[0],&b[1],10);
|
|
||||||
CHECK("memmove src");
|
|
||||||
|
|
||||||
/* memset */
|
|
||||||
init18(a,b);
|
|
||||||
memset(&b[1],'b',10);
|
|
||||||
CHECK("memset");
|
|
||||||
|
|
||||||
/* strlen */
|
|
||||||
init18(a,b);
|
|
||||||
strlen(&b[0]);
|
|
||||||
CHECK("strlen");
|
|
||||||
|
|
||||||
/* strcpy */
|
|
||||||
init18(a,b);
|
|
||||||
strcpy(&a[7], &a[0]);
|
|
||||||
CHECK("strcpy dest");
|
|
||||||
init18(a,b);
|
|
||||||
strcpy(&a[0], &b[7]);
|
|
||||||
CHECK("strcpy src");
|
|
||||||
init18(a,b);
|
|
||||||
strcpy(&a[0], &a[1]);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
init18(a,b);
|
|
||||||
strcpy(&a[2], &a[0]);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
|
|
||||||
/* strncpy */
|
|
||||||
init18(a,b);
|
|
||||||
strncpy(&a[7], &a[0], 10);
|
|
||||||
CHECK("strncpy dest");
|
|
||||||
init18(a,b);
|
|
||||||
strncpy(&a[0], &b[7], 10);
|
|
||||||
CHECK("strncpy src");
|
|
||||||
init18(a,b);
|
|
||||||
strncpy(&a[0], &a[1], 10);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
strncpy(&a[2], &a[0], 10);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
|
|
||||||
/* strcmp */
|
|
||||||
init18(a,b);
|
|
||||||
strcmp(&b[2], &b[0]);
|
|
||||||
CHECK("strcmp s1");
|
|
||||||
init18(a,b);
|
|
||||||
strcmp(&b[0], &b[2]);
|
|
||||||
CHECK("strcmp s2");
|
|
||||||
|
|
||||||
/* strncmp */
|
|
||||||
init18(a,b);
|
|
||||||
strncmp(&b[5], &b[0], 10);
|
|
||||||
CHECK("strncmp s1");
|
|
||||||
init18(a,b);
|
|
||||||
strncmp(&b[0], &b[5], 10);
|
|
||||||
CHECK("strncmp s2");
|
|
||||||
|
|
||||||
/* strcat */
|
|
||||||
init18(a,b);
|
|
||||||
strcat(&a[7], &a[0]);
|
|
||||||
CHECK("strcat dest");
|
|
||||||
init18(a,b);
|
|
||||||
strcat(&a[0], &b[5]);
|
|
||||||
CHECK("strcat src");
|
|
||||||
init18(a,b);
|
|
||||||
strcat(&a[0], &a[4]);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
init18(a,b);
|
|
||||||
strcat(&a[3], &a[0]);
|
|
||||||
CHECK("overlapping regions");
|
|
||||||
|
|
||||||
/* strchr */
|
|
||||||
init18(a,b);
|
|
||||||
strchr(&b[0], 'a');
|
|
||||||
CHECK("strchr");
|
|
||||||
|
|
||||||
/* strdup */
|
|
||||||
init18(a,b);
|
|
||||||
free(strdup(&b[0]));
|
|
||||||
CHECK("strdup");
|
|
||||||
|
|
||||||
__bound_never_fatal (2);
|
|
||||||
|
|
||||||
/* memcpy */
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[0],&b[0],10);
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[0],&a[3],3);
|
|
||||||
init18(a,b);
|
|
||||||
memcpy(&a[3],&a[0],3);
|
|
||||||
|
|
||||||
/* memcmp */
|
|
||||||
init18(a,b);
|
|
||||||
memcmp(&b[0],&b[0],10);
|
|
||||||
|
|
||||||
/* memmove */
|
|
||||||
init18(a,b);
|
|
||||||
memmove(&b[0],&b[5],5);
|
|
||||||
init18(a,b);
|
|
||||||
memmove(&b[5],&b[0],5);
|
|
||||||
|
|
||||||
/* memset */
|
|
||||||
init18(a,b);
|
|
||||||
memset(&b[0],'b',10);
|
|
||||||
|
|
||||||
/* strlen */
|
|
||||||
init18(a,b);
|
|
||||||
strlen (&a[0]);
|
|
||||||
|
|
||||||
/* strcpy */
|
|
||||||
init18(a,b);
|
|
||||||
strcpy (&a[0], &a[7]);
|
|
||||||
|
|
||||||
/* strncpy */
|
|
||||||
init18(a,b);
|
|
||||||
strncpy (&a[0], &a[7], 4);
|
|
||||||
|
|
||||||
/* strcmp */
|
|
||||||
init18(a,b);
|
|
||||||
strcmp (&a[0], &a[4]);
|
|
||||||
|
|
||||||
/* strncmp */
|
|
||||||
init18(a,b);
|
|
||||||
strncmp (&a[0], &a[4], 10);
|
|
||||||
|
|
||||||
/* strcat */
|
|
||||||
init18(a,b);
|
|
||||||
strcat (&a[0], &a[7]);
|
|
||||||
|
|
||||||
/* strchr */
|
|
||||||
init18(a,b);
|
|
||||||
strchr (&a[0], 0);
|
|
||||||
|
|
||||||
/* strdup */
|
|
||||||
init18(a,b);
|
|
||||||
free (strdup (&a[0]));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -443,8 +233,7 @@ int (*table_test[])(void) = {
|
|||||||
test14,
|
test14,
|
||||||
test15,
|
test15,
|
||||||
test16,
|
test16,
|
||||||
test17,
|
test17
|
||||||
test18,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -203,14 +203,11 @@ TF_TYPE(thread_test_complex, vn)
|
|||||||
|
|
||||||
sprintf(b, "%d", F(n));
|
sprintf(b, "%d", F(n));
|
||||||
|
|
||||||
argv[argc++] = "../tcc.c";
|
|
||||||
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
||||||
#if 0
|
#if 0
|
||||||
argv[argc++] = "-run";
|
argv[argc++] = "-run";
|
||||||
argv[argc++] = "../tcc.c";
|
|
||||||
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
|
||||||
#endif
|
#endif
|
||||||
argv[argc++] = "-g";
|
|
||||||
argv[argc++] = "-DFIB";
|
argv[argc++] = "-DFIB";
|
||||||
argv[argc++] = "-run";
|
argv[argc++] = "-run";
|
||||||
argv[argc++] = __FILE__;
|
argv[argc++] = __FILE__;
|
||||||
@ -221,23 +218,24 @@ TF_TYPE(thread_test_complex, vn)
|
|||||||
sleep_ms(2);
|
sleep_ms(2);
|
||||||
ret = tcc_add_file(s, argv[0]);
|
ret = tcc_add_file(s, argv[0]);
|
||||||
sleep_ms(3);
|
sleep_ms(3);
|
||||||
if (ret >= 0)
|
if (ret < 0)
|
||||||
tcc_run(s, argc, argv);
|
exit(1);
|
||||||
|
tcc_run(s, argc, argv);
|
||||||
tcc_delete(s);
|
tcc_delete(s);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void time_tcc(int n)
|
void time_tcc(int n, const char *src)
|
||||||
{
|
{
|
||||||
TCCState *s;
|
TCCState *s;
|
||||||
int ret;
|
int ret;
|
||||||
while (--n >= 0) {
|
while (--n >= 0) {
|
||||||
s = new_state(1);
|
s = new_state(1);
|
||||||
ret = tcc_add_file(s, "../tcc.c");
|
ret = tcc_add_file(s, src);
|
||||||
tcc_delete(s);
|
tcc_delete(s);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +258,11 @@ int main(int argc, char **argv)
|
|||||||
g_argc = argc;
|
g_argc = argc;
|
||||||
g_argv = argv;
|
g_argv = argv;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
printf("----- libtest : mixed calls -------\n"), fflush(stdout);
|
printf("----- libtest : mixed calls -------\n"), fflush(stdout);
|
||||||
t = getclock_ms();
|
t = getclock_ms();
|
||||||
@ -285,7 +288,7 @@ int main(int argc, char **argv)
|
|||||||
#if 1
|
#if 1
|
||||||
printf("----- compilation of tcc -----------\n"), fflush(stdout);
|
printf("----- compilation of tcc -----------\n"), fflush(stdout);
|
||||||
t = getclock_ms();
|
t = getclock_ms();
|
||||||
time_tcc(10);
|
time_tcc(10, argv[1]);
|
||||||
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
|
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1725,10 +1725,6 @@ void cast_test()
|
|||||||
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
|
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||||
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
|
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
|
||||||
|
|
||||||
#ifdef __TINYC__
|
|
||||||
# pragma comment(option, "-w")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* from pointer to integer types */
|
/* from pointer to integer types */
|
||||||
printf("%d %d %ld %ld %lld %lld\n",
|
printf("%d %d %ld %ld %lld %lld\n",
|
||||||
(int)p, (unsigned int)p,
|
(int)p, (unsigned int)p,
|
||||||
@ -1739,10 +1735,6 @@ void cast_test()
|
|||||||
printf("%p %p %p %p\n",
|
printf("%p %p %p %p\n",
|
||||||
(void *)a, (void *)b, (void *)c, (void *)d);
|
(void *)a, (void *)b, (void *)c, (void *)d);
|
||||||
|
|
||||||
#ifdef __TINYC__
|
|
||||||
# pragma comment(option, "-W")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* int to int with sign set */
|
/* int to int with sign set */
|
||||||
printf("0x%lx\n", (unsigned long)(int)ul);
|
printf("0x%lx\n", (unsigned long)(int)ul);
|
||||||
}
|
}
|
||||||
@ -3406,7 +3398,7 @@ void clobber_r12(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void test_high_clobbers(void)
|
void test_high_clobbers_really(void)
|
||||||
{
|
{
|
||||||
#if defined __x86_64__ && !defined _WIN64
|
#if defined __x86_64__ && !defined _WIN64
|
||||||
register long val asm("r12");
|
register long val asm("r12");
|
||||||
@ -3422,6 +3414,20 @@ void test_high_clobbers(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_high_clobbers(void)
|
||||||
|
{
|
||||||
|
#if defined __x86_64__ && !defined _WIN64
|
||||||
|
long x1, x2;
|
||||||
|
asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
|
||||||
|
test_high_clobbers_really();
|
||||||
|
asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
|
||||||
|
asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
|
||||||
|
/* should be 0 but tcc doesn't save r12 automatically, which has
|
||||||
|
bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
|
||||||
|
//printf("r12-clobber-diff: %lx\n", x2 - x1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static long cpu_number;
|
static long cpu_number;
|
||||||
void trace_console(long len, long len2)
|
void trace_console(long len, long len2)
|
||||||
{
|
{
|
||||||
|
165
tests/tests2/112_backtrace.c
Normal file
165
tests/tests2/112_backtrace.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#if defined test_backtrace_1
|
||||||
|
|
||||||
|
void f3()
|
||||||
|
{
|
||||||
|
printf("* f3()\n"), fflush(stdout);
|
||||||
|
*(void**)0 = 0;
|
||||||
|
}
|
||||||
|
void f2()
|
||||||
|
{
|
||||||
|
printf("* f2()\n"), fflush(stdout);
|
||||||
|
f3();
|
||||||
|
}
|
||||||
|
void f1()
|
||||||
|
{
|
||||||
|
printf("* f1()\n"), fflush(stdout);
|
||||||
|
f2();
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("* main\n"), fflush(stdout);
|
||||||
|
f1();
|
||||||
|
printf("* exit main\n"), fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#elif defined test_bcheck_1
|
||||||
|
|
||||||
|
struct s { int a,b,c,d,e; };
|
||||||
|
struct s s[3];
|
||||||
|
struct s *ps = s;
|
||||||
|
void f1()
|
||||||
|
{
|
||||||
|
printf("* f1()\n"), fflush(stdout);
|
||||||
|
ps[3] = ps[2];
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("* main\n"), fflush(stdout);
|
||||||
|
f1();
|
||||||
|
printf("* exit main\n"), fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#elif defined test_tcc_backtrace_2
|
||||||
|
|
||||||
|
/* test custom backtrace and 'exit()' redirection */
|
||||||
|
int tcc_backtrace(const char *fmt, ...);
|
||||||
|
void exit(int);
|
||||||
|
|
||||||
|
void f2()
|
||||||
|
{
|
||||||
|
printf("* f2()\n");
|
||||||
|
printf("* exit f2\n"), fflush(stdout);
|
||||||
|
exit(34);
|
||||||
|
}
|
||||||
|
void f1()
|
||||||
|
{
|
||||||
|
printf("* f1()\n"), fflush(stdout);
|
||||||
|
tcc_backtrace("Hello from %s!", "f1");
|
||||||
|
f2();
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("* main\n"), fflush(stdout);
|
||||||
|
f1();
|
||||||
|
printf("* exit main\n"), fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#elif defined test_tcc_backtrace_3
|
||||||
|
|
||||||
|
/* this test should be run despite of the exit(34) above */
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("* main\n"), fflush(stdout);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <string.h>
|
||||||
|
char *strdup();
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char pad1[10];
|
||||||
|
char a[10];
|
||||||
|
char pad2[10];
|
||||||
|
char b[10];
|
||||||
|
char pad3[10];
|
||||||
|
memset (pad1, 0, sizeof(pad1));
|
||||||
|
memset (pad2, 0, sizeof(pad2));
|
||||||
|
memset (pad3, 0, sizeof(pad3));
|
||||||
|
|
||||||
|
memset (a, 'a', 10);
|
||||||
|
a[3] = 0;
|
||||||
|
a[9] = 0;
|
||||||
|
memset (b, 'b', 10);
|
||||||
|
|
||||||
|
#if defined test_bcheck_100
|
||||||
|
memcpy(&a[1],&b[0],10);
|
||||||
|
#elif defined test_bcheck_101
|
||||||
|
memcpy(&a[0],&b[1],10);
|
||||||
|
#elif defined test_bcheck_102
|
||||||
|
memcpy(&a[0],&a[3],4);
|
||||||
|
#elif defined test_bcheck_103
|
||||||
|
memcpy(&a[3],&a[0],4);
|
||||||
|
#elif defined test_bcheck_104
|
||||||
|
memcmp(&b[1],&b[0],10);
|
||||||
|
#elif defined test_bcheck_105
|
||||||
|
memcmp(&b[0],&b[1],10);
|
||||||
|
#elif defined test_bcheck_106
|
||||||
|
memmove(&b[1],&b[0],10);
|
||||||
|
#elif defined test_bcheck_107
|
||||||
|
memmove(&b[0],&b[1],10);
|
||||||
|
#elif defined test_bcheck_108
|
||||||
|
memset(&b[1],'b',10);
|
||||||
|
#elif defined test_bcheck_109
|
||||||
|
strlen(&b[0]);
|
||||||
|
#elif defined test_bcheck_110
|
||||||
|
strcpy(&a[7], &a[0]);
|
||||||
|
#elif defined test_bcheck_111
|
||||||
|
strcpy(&a[0], &b[7]);
|
||||||
|
#elif defined test_bcheck_112
|
||||||
|
strcpy(&a[0], &a[1]);
|
||||||
|
#elif defined test_bcheck_113
|
||||||
|
strcpy(&a[2], &a[0]);
|
||||||
|
#elif defined test_bcheck_114
|
||||||
|
strncpy(&a[7], &a[0], 10);
|
||||||
|
#elif defined test_bcheck_115
|
||||||
|
strncpy(&a[0], &b[7], 10);
|
||||||
|
#elif defined test_bcheck_116
|
||||||
|
strncpy(&a[0], &a[1], 10);
|
||||||
|
#elif defined test_bcheck_117
|
||||||
|
strncpy(&a[2], &a[0], 10);
|
||||||
|
#elif defined test_bcheck_118
|
||||||
|
strcmp(&b[2], &b[0]);
|
||||||
|
#elif defined test_bcheck_119
|
||||||
|
strcmp(&b[0], &b[2]);
|
||||||
|
#elif defined test_bcheck_120
|
||||||
|
strncmp(&b[5], &b[0], 10);
|
||||||
|
#elif defined test_bcheck_121
|
||||||
|
strncmp(&b[0], &b[5], 10);
|
||||||
|
#elif defined test_bcheck_122
|
||||||
|
strcat(&a[7], &a[0]);
|
||||||
|
#elif defined test_bcheck_123
|
||||||
|
strcat(&a[0], &b[5]);
|
||||||
|
#elif defined test_bcheck_124
|
||||||
|
strcat(&a[0], &a[4]);
|
||||||
|
#elif defined test_bcheck_125
|
||||||
|
strcat(&a[3], &a[0]);
|
||||||
|
#elif defined test_bcheck_126
|
||||||
|
strchr(&b[0], 'a');
|
||||||
|
#elif defined test_bcheck_127
|
||||||
|
free(strdup(&b[0]));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* ------------------------------------------------------- */
|
||||||
|
#endif
|
164
tests/tests2/112_backtrace.expect
Normal file
164
tests/tests2/112_backtrace.expect
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
[test_backtrace_1]
|
||||||
|
* main
|
||||||
|
* f1()
|
||||||
|
* f2()
|
||||||
|
* f3()
|
||||||
|
112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
|
||||||
|
112_backtrace.c:14: by f2
|
||||||
|
112_backtrace.c:19: by f1
|
||||||
|
112_backtrace.c:24: by main
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_1]
|
||||||
|
* main
|
||||||
|
* f1()
|
||||||
|
112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:43: by main
|
||||||
|
112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x14 in memmove dest
|
||||||
|
112_backtrace.c:43: by main
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_tcc_backtrace_2]
|
||||||
|
* main
|
||||||
|
* f1()
|
||||||
|
112_backtrace.c:64: at f1: Hello from f1!
|
||||||
|
112_backtrace.c:70: by main
|
||||||
|
* f2()
|
||||||
|
* exit f2
|
||||||
|
[returns 34]
|
||||||
|
|
||||||
|
[test_tcc_backtrace_3]
|
||||||
|
* main
|
||||||
|
[returns 1]
|
||||||
|
|
||||||
|
[test_bcheck_100]
|
||||||
|
112_backtrace.c:107: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0xa in memcpy dest
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_101]
|
||||||
|
112_backtrace.c:109: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0xa in memcpy src
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_102]
|
||||||
|
112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_103]
|
||||||
|
112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_104]
|
||||||
|
112_backtrace.c:115: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s1
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_105]
|
||||||
|
112_backtrace.c:117: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s2
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_106]
|
||||||
|
112_backtrace.c:119: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0xa in memmove dest
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_107]
|
||||||
|
112_backtrace.c:121: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0xa in memmove src
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_108]
|
||||||
|
112_backtrace.c:123: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0xa in memset
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_109]
|
||||||
|
112_backtrace.c:125: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0xb in strlen
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_110]
|
||||||
|
112_backtrace.c:127: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy dest
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_111]
|
||||||
|
112_backtrace.c:129: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy src
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_112]
|
||||||
|
112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strcpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_113]
|
||||||
|
112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_114]
|
||||||
|
112_backtrace.c:135: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy dest
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_115]
|
||||||
|
112_backtrace.c:137: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy src
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_116]
|
||||||
|
112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strncpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_117]
|
||||||
|
112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strncpy
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_118]
|
||||||
|
112_backtrace.c:143: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s1
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_119]
|
||||||
|
112_backtrace.c:145: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s2
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_120]
|
||||||
|
112_backtrace.c:147: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s1
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_121]
|
||||||
|
112_backtrace.c:149: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s2
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_122]
|
||||||
|
112_backtrace.c:151: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x6 in strcat dest
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_123]
|
||||||
|
112_backtrace.c:153: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x6 in strcat src
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_124]
|
||||||
|
112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x9), ........(0x6) in strcat
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_125]
|
||||||
|
112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcat
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_126]
|
||||||
|
112_backtrace.c:159: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0xb in strchr
|
||||||
|
[returns 255]
|
||||||
|
|
||||||
|
[test_bcheck_127]
|
||||||
|
112_backtrace.c:161: at main: BCHECK: ........ is outside of the region
|
||||||
|
112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0xb in strdup
|
||||||
|
[returns 255]
|
@ -20,6 +20,7 @@
|
|||||||
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
|
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
|
||||||
|
|
||||||
[test_63_local_enumerator_redefinition]
|
[test_63_local_enumerator_redefinition]
|
||||||
|
[returns 1]
|
||||||
|
|
||||||
[test_61_undefined_enum]
|
[test_61_undefined_enum]
|
||||||
60_errors_and_warnings.c:46: error: unknown type size
|
60_errors_and_warnings.c:46: error: unknown type size
|
||||||
|
@ -24,6 +24,7 @@ ifeq (,$(filter i386,$(ARCH)))
|
|||||||
endif
|
endif
|
||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||||
SKIP += 85_asm-outside-function.test
|
SKIP += 85_asm-outside-function.test
|
||||||
|
SKIP += 112_backtrace.test
|
||||||
endif
|
endif
|
||||||
ifeq (-$(findstring gcc,$(CC))-,--)
|
ifeq (-$(findstring gcc,$(CC))-,--)
|
||||||
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
|
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
|
||||||
@ -70,12 +71,11 @@ GEN-ALWAYS =
|
|||||||
# constructor/destructor
|
# constructor/destructor
|
||||||
108_constructor.test: NORUN = true
|
108_constructor.test: NORUN = true
|
||||||
|
|
||||||
|
112_backtrace.test: FLAGS += -dt -b
|
||||||
|
112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g'
|
||||||
|
|
||||||
# Filter source directory in warnings/errors (out-of-tree builds)
|
# Filter source directory in warnings/errors (out-of-tree builds)
|
||||||
FILTER = 2>&1 | sed 's,$(SRC)/,,g'
|
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
|
||||||
# Filter some always-warning
|
|
||||||
ifeq (-$(findstring arm,$(ARCH))-,-arm-)
|
|
||||||
FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
|
|
||||||
endif
|
|
||||||
|
|
||||||
all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
|
all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ copy>nul tcc-win32.txt doc
|
|||||||
@if errorlevel 1 goto :the_end
|
@if errorlevel 1 goto :the_end
|
||||||
|
|
||||||
:libtcc1.a
|
:libtcc1.a
|
||||||
@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
|
@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o
|
||||||
.\tcc -m32 -c ../lib/libtcc1.c
|
.\tcc -m32 -c ../lib/libtcc1.c
|
||||||
.\tcc -m32 -c lib/crt1.c
|
.\tcc -m32 -c lib/crt1.c
|
||||||
.\tcc -m32 -c lib/crt1w.c
|
.\tcc -m32 -c lib/crt1w.c
|
||||||
@ -147,7 +147,6 @@ copy>nul tcc-win32.txt doc
|
|||||||
.\tcc -m32 -c lib/dllcrt1.c
|
.\tcc -m32 -c lib/dllcrt1.c
|
||||||
.\tcc -m32 -c lib/dllmain.c
|
.\tcc -m32 -c lib/dllmain.c
|
||||||
.\tcc -m32 -c lib/chkstk.S
|
.\tcc -m32 -c lib/chkstk.S
|
||||||
.\tcc -m32 -w -c ../lib/bcheck.c
|
|
||||||
.\tcc -m32 -c ../lib/alloca86.S
|
.\tcc -m32 -c ../lib/alloca86.S
|
||||||
.\tcc -m32 -c ../lib/alloca86-bt.S
|
.\tcc -m32 -c ../lib/alloca86-bt.S
|
||||||
.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
|
.\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
|
||||||
@ -160,11 +159,14 @@ copy>nul tcc-win32.txt doc
|
|||||||
.\tcc -m64 -c lib/dllcrt1.c
|
.\tcc -m64 -c lib/dllcrt1.c
|
||||||
.\tcc -m64 -c lib/dllmain.c
|
.\tcc -m64 -c lib/dllmain.c
|
||||||
.\tcc -m64 -c lib/chkstk.S
|
.\tcc -m64 -c lib/chkstk.S
|
||||||
.\tcc -m64 -w -c ../lib/bcheck.c
|
|
||||||
.\tcc -m64 -c ../lib/alloca86_64.S
|
.\tcc -m64 -c ../lib/alloca86_64.S
|
||||||
.\tcc -m64 -c ../lib/alloca86_64-bt.S
|
.\tcc -m64 -c ../lib/alloca86_64-bt.S
|
||||||
.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
|
.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
|
||||||
@if errorlevel 1 goto :the_end
|
@if errorlevel 1 goto :the_end
|
||||||
|
.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o
|
||||||
|
.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o
|
||||||
|
.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o
|
||||||
|
.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o
|
||||||
|
|
||||||
:tcc-doc.html
|
:tcc-doc.html
|
||||||
@if not (%DOC%)==(yes) goto :doc-done
|
@if not (%DOC%)==(yes) goto :doc-done
|
||||||
@ -182,7 +184,7 @@ if not exist %INST% mkdir %INST%
|
|||||||
if not exist %BIN% mkdir %BIN%
|
if not exist %BIN% mkdir %BIN%
|
||||||
for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
|
for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
|
||||||
@if not exist %INST%\lib mkdir %INST%\lib
|
@if not exist %INST%\lib mkdir %INST%\lib
|
||||||
for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f
|
for %%f in (lib\*.a lib\*.o lib\*.def) do @copy>nul %%f %INST%\%%f
|
||||||
for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
|
for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
|
||||||
|
|
||||||
:the_end
|
:the_end
|
||||||
|
@ -99,7 +99,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
|||||||
#if defined __i386__ || defined __x86_64__
|
#if defined __i386__ || defined __x86_64__
|
||||||
_controlfp(_PC_53, _MCW_PC);
|
_controlfp(_PC_53, _MCW_PC);
|
||||||
#endif
|
#endif
|
||||||
return do_main(__argc, __targv, _tenviron);
|
return _tmain(__argc, __targv, _tenviron);
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
|
@ -191,6 +191,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
|||||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||||
/* XXX: this logic may depend on TCC's codegen
|
/* XXX: this logic may depend on TCC's codegen
|
||||||
now TCC uses R_X86_64_32 even for a 64bit pointer */
|
now TCC uses R_X86_64_32 even for a 64bit pointer */
|
||||||
|
qrel->r_offset = rel->r_offset;
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
|
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
|
||||||
/* Use sign extension! */
|
/* Use sign extension! */
|
||||||
qrel->r_addend = (int)read32le(ptr) + val;
|
qrel->r_addend = (int)read32le(ptr) + val;
|
||||||
|
Loading…
Reference in New Issue
Block a user