History

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

gr committed 6 years ago

Commit ef422951 parent 4092b0527 files · +1211 −850Browse files

Unified · Split

27 files
  1. Makefile +3 −2
  2. arm-gen.c +1 −1
  3. lib/Makefile +13 −9
  4. lib/bcheck.c +72 −89
  5. lib/bt-dll.c +67 −0
  6. lib/bt-exe.c +43 −0
  7. lib/bt-log.c +36 −0
  8. libtcc.c +4 −4
  9. tcc-doc.texi +6 −3
  10. tcc.c +1 −1
  11. tcc.h +11 −15
  12. tccelf.c +151 −106
  13. tccgen.c +34 −52
  14. tccpe.c +176 −146
  15. tccpp.c +9 −8
  16. tccrun.c +188 −149
  17. tests/Makefile +23 −23
  18. tests/boundtest.c +3 −214
  19. tests/libtcc_test_mt.c +12 −9
  20. tests/tcctest.c +15 −9
  21. tests/tests2/112_backtrace.c +165 −0
  22. tests/tests2/112_backtrace.expect +164 −0
  23. tests/tests2/60_errors_and_warnings.expect +1 −0
  24. tests/tests2/Makefile +5 −5
  25. win32/build-tcc.bat +6 −4
  26. win32/lib/crt1.c +1 −1
  27. x86_64-link.c +1 −0
Makefile+3−2
@@ -281,11 +281,12 @@ IBw = $(call IB,$(wildcard $1),$2) · 280 unmodified lines
281281 IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
282282 IFw = $(call IF,$(wildcard $1),$2)
283283 IR = mkdir -p $2 && cp -r $1/. $2
284+B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
284285
285286 # install progs & libs
286287 install-unx:
287288 $(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
288− $(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)")
289+ $(call IFw,$(LIBTCC1) $(B_O) $(LIBTCC1_U),"$(tccdir)")
289290 $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
290291 $(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
291292 $(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
@@ -310,7 +311,7 @@ uninstall-unx: · 18 unmodified lines
310311 install-win:
311312 $(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
312313 $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
313− $(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib")
314+ $(call IFw,libtcc1.a $(B_O) $(LIBTCC1_W),"$(tccdir)/lib")
314315 $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
315316 $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
316317 $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
arm-gen.c+1−1
@@ -171,7 +171,7 @@ ST_FUNC void arm_init(struct TCCState *s) · 170 unmodified lines
171171
172172 float_abi = s->float_abi;
173173 #ifndef TCC_ARM_HARDFLOAT
174− tcc_warning("soft float ABI currently not supported: default to softfp");
174+# warning "soft float ABI currently not supported: default to softfp"
175175 #endif
176176 }
177177 #else
lib/Makefile+13−9
@@ -13,7 +13,7 @@ XCC = $(XTCC) · 12 unmodified lines
1313 XAR = $(XTCC) -ar
1414 XFLAGS-unx = -B$(TOPSRC)
1515 XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
16−XFLAGS = $(XFLAGS$(XCFG))
16+XFLAGS = $(XFLAGS$(XCFG)) -I$(TOP)
1717 XCFG = $(or $(findstring -win,$T),-unx)
1818
1919 # in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
@@ -27,6 +27,8 @@ endif · 7 unmodified lines
2727
2828 # only for native compiler
2929 $(X)BCHECK_O = bcheck.o
30+$(X)BT_O = bt-exe.o bt-log.o
31+$(X)B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
3032
3133 ifeq ($(CONFIG_musl)$(CONFIG_uClibc),yes)
3234 BCHECK_O =
@@ -38,18 +40,18 @@ ifdef CONFIG_OSX · 5 unmodified lines
3840 XFLAGS += -D_ANSI_SOURCE
3941 endif
4042
41−I386_O = libtcc1.o alloca86.o alloca86-bt.o
42−X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
43−ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
44−ARM64_O = lib-arm64.o
45−RISCV64_O = lib-arm64.o
43+I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
44+X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
45+ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
46+ARM64_O = lib-arm64.o $(BT_O)
47+RISCV64_O = lib-arm64.o $(BT_O)
4648 WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
4749
4850 OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
4951 OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
5052 OBJ-x86_64-osx = $(X86_64_O) va_list.o
51−OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
52−OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
53+OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
54+OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
5355 OBJ-arm64 = $(ARM64_O) $(DSO_O)
5456 OBJ-arm = $(ARM_O) $(DSO_O)
5557 OBJ-arm-fpa = $(ARM_O) $(DSO_O)
@@ -60,7 +62,7 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) · 4 unmodified lines
6062 OBJ-arm-wince = $(ARM_O) $(WIN_O)
6163 OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
6264
63−OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
65+OBJ-extra = $(filter $(B_O),$(OBJ-$T))
6466 OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
6567
6668 ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
@@ -80,8 +82,10 @@ $(TOP)/%.o : %.c · 13 unmodified lines
8082 $(XCC) -c $< -o $@ $(XFLAGS)
8183
8284 $(TOP)/bcheck.o : XFLAGS += -g
85+$(TOP)/bt-exe.o : $(TOP)/tccrun.c
8386
8487 $(X)crt1w.o : crt1.c
8588 $(X)wincrt1w.o : wincrt1.c
89+
8690 clean :
8791 rm -f *.a *.o $(ALL)
lib/bcheck.c+72−89
@@ -49,6 +49,12 @@ · 48 unmodified lines
4949 #endif
5050 #define FASTCALL __attribute__((regparm(3)))
5151
52+#ifdef _WIN32
53+# define DLL_EXPORT __declspec(dllexport)
54+#else
55+# define DLL_EXPORT
56+#endif
57+
5258 #if defined(__FreeBSD__) \
5359 || defined(__FreeBSD_kernel__) \
5460 || defined(__DragonFly__) \
@@ -162,16 +168,16 @@ void splay_printtree(Tree * t, int d); · 107 unmodified lines
162168 /* external interface */
163169 void __bound_checking (int no_check);
164170 void __bound_never_fatal (int no_check);
165−void * __bound_ptr_add(void *p, size_t offset);
166−void * __bound_ptr_indir1(void *p, size_t offset);
167−void * __bound_ptr_indir2(void *p, size_t offset);
168−void * __bound_ptr_indir4(void *p, size_t offset);
169−void * __bound_ptr_indir8(void *p, size_t offset);
170−void * __bound_ptr_indir12(void *p, size_t offset);
171−void * __bound_ptr_indir16(void *p, size_t offset);
172−void FASTCALL __bound_local_new(void *p1);
173−void FASTCALL __bound_local_delete(void *p1);
174−void __bound_init(void);
171+DLL_EXPORT void * __bound_ptr_add(void *p, size_t offset);
172+DLL_EXPORT void * __bound_ptr_indir1(void *p, size_t offset);
173+DLL_EXPORT void * __bound_ptr_indir2(void *p, size_t offset);
174+DLL_EXPORT void * __bound_ptr_indir4(void *p, size_t offset);
175+DLL_EXPORT void * __bound_ptr_indir8(void *p, size_t offset);
176+DLL_EXPORT void * __bound_ptr_indir12(void *p, size_t offset);
177+DLL_EXPORT void * __bound_ptr_indir16(void *p, size_t offset);
178+DLL_EXPORT void FASTCALL __bound_local_new(void *p1);
179+DLL_EXPORT void FASTCALL __bound_local_delete(void *p1);
180+void __bound_init(size_t *);
175181 void __bound_main_arg(char **p);
176182 void __bound_exit(void);
177183 #if !defined(_WIN32)
@@ -179,35 +185,32 @@ void *__bound_mmap (void *start, size_t size, int prot, int flags, int fd, · 1 unmodified line
179185 off_t offset);
180186 int __bound_munmap (void *start, size_t size);
181187 #endif
182−void __bound_new_region(void *p, size_t size);
183−void *__bound_memcpy(void *dst, const void *src, size_t size);
184−int __bound_memcmp(const void *s1, const void *s2, size_t size);
185−void *__bound_memmove(void *dst, const void *src, size_t size);
186−void *__bound_memset(void *dst, int c, size_t size);
187−int __bound_strlen(const char *s);
188−char *__bound_strcpy(char *dst, const char *src);
189−char *__bound_strncpy(char *dst, const char *src, size_t n);
190−int __bound_strcmp(const char *s1, const char *s2);
191−int __bound_strncmp(const char *s1, const char *s2, size_t n);
192−char *__bound_strcat(char *dest, const char *src);
193−char *__bound_strchr(const char *string, int ch);
194−char *__bound_strdup(const char *s);
188+DLL_EXPORT void __bound_new_region(void *p, size_t size);
189+DLL_EXPORT void *__bound_memcpy(void *dst, const void *src, size_t size);
190+DLL_EXPORT int __bound_memcmp(const void *s1, const void *s2, size_t size);
191+DLL_EXPORT void *__bound_memmove(void *dst, const void *src, size_t size);
192+DLL_EXPORT void *__bound_memset(void *dst, int c, size_t size);
193+DLL_EXPORT int __bound_strlen(const char *s);
194+DLL_EXPORT char *__bound_strcpy(char *dst, const char *src);
195+DLL_EXPORT char *__bound_strncpy(char *dst, const char *src, size_t n);
196+DLL_EXPORT int __bound_strcmp(const char *s1, const char *s2);
197+DLL_EXPORT int __bound_strncmp(const char *s1, const char *s2, size_t n);
198+DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
199+DLL_EXPORT char *__bound_strchr(const char *string, int ch);
200+DLL_EXPORT char *__bound_strdup(const char *s);
195201
196202 #if !MALLOC_REDIR
197−void *__bound_malloc(size_t size, const void *caller);
198−void *__bound_memalign(size_t size, size_t align, const void *caller);
199−void __bound_free(void *ptr, const void *caller);
200−void *__bound_realloc(void *ptr, size_t size, const void *caller);
201−void *__bound_calloc(size_t nmemb, size_t size);
203+DLL_EXPORT void *__bound_malloc(size_t size, const void *caller);
204+DLL_EXPORT void *__bound_memalign(size_t size, size_t align, const void *caller);
205+DLL_EXPORT void __bound_free(void *ptr, const void *caller);
206+DLL_EXPORT void *__bound_realloc(void *ptr, size_t size, const void *caller);
207+DLL_EXPORT void *__bound_calloc(size_t nmemb, size_t size);
202208 #endif
203209
204210 #define FREE_REUSE_SIZE (100)
205211 static unsigned int free_reuse_index;
206212 static void *free_reuse_list[FREE_REUSE_SIZE];
207213
208−/* error message, just for TCC */
209−const char *__bound_error_msg;
210−
211214 static Tree *tree = NULL;
212215 #define TREE_REUSE (1)
213216 #if TREE_REUSE
@@ -296,14 +299,18 @@ void __bound_never_fatal (int neverfatal) · 82 unmodified lines
296299 fetch_and_add (&never_fatal, neverfatal);
297300 }
298301
302+int tcc_backtrace(const char *fmt, ...);
303+
299304 /* print a bound error message */
300−static void bound_error(const char *error)
301−{
302− __bound_error_msg = error;
303− fprintf(stderr,"%s%s %s: %s\n", exec, __FILE__, __FUNCTION__, error);
304− if (never_fatal == 0)
305− *(void **)0 = 0; /* force a runtime error */
306−}
305+#define bound_warning(...) \
306+ tcc_backtrace("^bcheck.c^BCHECK: " __VA_ARGS__)
307+
308+#define bound_error(...) \
309+ do { \
310+ bound_warning(__VA_ARGS__); \
311+ if (never_fatal == 0) \
312+ exit(255); \
313+ } while (0)
307314
308315 static void bound_alloc_error(const char *s)
309316 {
@@ -317,20 +324,6 @@ static void bound_not_found_warning(const char *file, const char *function, · 7 unmodified lines
317324 dprintf(stderr, "%s%s, %s(): Not found %p\n", exec, file, function, ptr);
318325 }
319326
320−static void bound_ptr_add_warning(const char *file, const char *function,
321− void *ptr)
322−{
323− fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
324− exec, file, function, ptr);
325−}
326−
327−static void bound_ptr_indir_error(const char *file, const char *function,
328− void *ptr)
329−{
330− fprintf(stderr,"%s%s %s(): %p is outside of the region\n",
331− exec, file, function, ptr);
332−}
333−
334327 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
335328 the end of a region in this case */
336329 void * __bound_ptr_add(void *p, size_t offset)
@@ -360,8 +353,7 @@ void * __bound_ptr_add(void *p, size_t offset) · 23 unmodified lines
360353 if (addr <= tree->size) {
361354 if (tree->is_invalid || addr + offset > tree->size) {
362355 POST_SEM ();
363− if (print_warn_ptr_add)
364− bound_ptr_add_warning (__FILE__, __FUNCTION__, p + offset);
356+ bound_warning("%p is outside of the region", p + offset);
365357 if (never_fatal <= 0)
366358 return INVALID_POINTER; /* return an invalid pointer */
367359 return p + offset;
@@ -407,8 +399,7 @@ void * __bound_ptr_indir ## dsize (void *p, size_t offset) \ · 39 unmodified lines
407399 if (addr <= tree->size) { \
408400 if (tree->is_invalid || addr + offset + dsize > tree->size) { \
409401 POST_SEM (); \
410− bound_ptr_indir_error (__FILE__, __FUNCTION__, \
411− p + offset); \
402+ bound_warning("%p is outside of the region", p + offset); \
412403 if (never_fatal <= 0) \
413404 return INVALID_POINTER; /* return an invalid pointer */ \
414405 return p + offset; \
@@ -460,8 +451,7 @@ void FASTCALL __bound_local_new(void *p1) · 45 unmodified lines
460451 WAIT_SEM ();
461452 while ((addr = p[0])) {
462453 INCR_COUNT(bound_local_new_count);
463− if (addr != 1)
464− tree = splay_insert(addr + fp, p[1], tree);
454+ tree = splay_insert(addr + fp, p[1], tree);
465455 p += 2;
466456 }
467457 POST_SEM ();
@@ -498,7 +488,10 @@ void FASTCALL __bound_local_delete(void *p1) · 30 unmodified lines
498488 WAIT_SEM ();
499489 while ((addr = p[0])) {
500490 INCR_COUNT(bound_local_delete_count);
501− if (addr == 1) {
491+ tree = splay_delete(addr + fp, tree);
492+ p += 2;
493+ }
494+ {
502495 alloca_list_type *last = NULL;
503496 alloca_list_type *cur = alloca_list;
504497
@@ -518,11 +511,8 @@ void FASTCALL __bound_local_delete(void *p1) · 13 unmodified lines
518511 cur = cur->next;
519512 }
520513 }
521− }
522− else
523− tree = splay_delete(addr + fp, tree);
524− p += 2;
525514 }
515+
526516 POST_SEM ();
527517 while (free_list) {
528518 alloca_list_type *next = free_list->next;
@@ -607,14 +597,14 @@ void __bound_new_region(void *p, size_t size) · 78 unmodified lines
607597 #pragma GCC diagnostic pop
608598 #endif
609599
610−void __attribute__((constructor)) __bound_init(void)
600+void __bound_init(size_t *p)
611601 {
612− extern size_t __bounds_start[];
613− size_t *p;
614−
615− if (inited)
616− return;
602+ dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
617603
604+ if (inited) {
605+ WAIT_SEM();
606+ goto add_bounds;
607+ }
618608 inited = 1;
619609
620610 print_warn_ptr_add = getenv ("TCC_BOUNDS_WARN_POINTER_ADD") != NULL;
@@ -623,8 +613,6 @@ void __attribute__((constructor)) __bound_init(void) · 2 unmodified lines
623613 print_statistic = getenv ("TCC_BOUNDS_PRINT_STATISTIC") != NULL;
624614 never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL;
625615
626− dprintf(stderr, "%s, %s(): start\n", __FILE__, __FUNCTION__);
627−
628616 INIT_SEM ();
629617
630618 #if MALLOC_REDIR
@@ -724,27 +712,26 @@ void __attribute__((constructor)) __bound_init(void) · 93 unmodified lines
724712 tree = splay_insert((size_t) (&errno), sizeof (int), tree);
725713 #endif
726714
715+add_bounds:
716+ if (!p)
717+ goto no_bounds;
718+
727719 /* add all static bound check values */
728− p = __bounds_start;
729720 while (p[0] != 0) {
730721 tree = splay_insert(p[0], p[1], tree);
731− p += 2;
732− }
733− POST_SEM ();
734722 #if BOUND_DEBUG
735− if (print_calls) {
736− p = __bounds_start;
737− while (p[0] != 0) {
723+ if (print_calls) {
738724 dprintf(stderr, "%s, %s(): static var %p 0x%lx\n",
739725 __FILE__, __FUNCTION__,
740726 (void *) p[0], (unsigned long) p[1]);
741− p += 2;
742727 }
743− }
744728 #endif
729+ p += 2;
730+ }
731+no_bounds:
745732
733+ POST_SEM ();
746734 no_checking = 0;
747−
748735 dprintf(stderr, "%s, %s(): end\n\n", __FILE__, __FUNCTION__);
749736 }
750737
@@ -931,7 +918,7 @@ void *__bound_malloc(size_t size, const void *caller) · 180 unmodified lines
931918 #if MALLOC_REDIR
932919 /* This will catch the first dlsym call from __bound_init */
933920 if (malloc_redir == NULL) {
934− __bound_init ();
921+ __bound_init (0);
935922 if (malloc_redir == NULL) {
936923 ptr = &initial_pool[pool_index];
937924 pool_index = (pool_index + size + 15) & ~15;
@@ -1113,7 +1100,7 @@ void *__bound_calloc(size_t nmemb, size_t size) · 175 unmodified lines
11131100 #if MALLOC_REDIR
11141101 /* This will catch the first dlsym call from __bound_init */
11151102 if (malloc_redir == NULL) {
1116− __bound_init ();
1103+ __bound_init (0);
11171104 if (malloc_redir == NULL) {
11181105 ptr = &initial_pool[pool_index];
11191106 pool_index = (pool_index + size + 15) & ~15;
@@ -1190,10 +1177,8 @@ static void __bound_check(const void *p, size_t size, const char *function) · 70 unmodified lines
11901177 {
11911178 if (no_checking == 0 && size != 0 &&
11921179 __bound_ptr_add((void *)p, size) == INVALID_POINTER) {
1193− static char line[100];
1194− sprintf(line, "invalid pointer %p, size 0x%lx in %s",
1180+ bound_error("invalid pointer %p, size 0x%lx in %s",
11951181 p, (unsigned long)size, function);
1196− bound_error(line);
11971182 }
11981183 }
11991184
@@ -1207,10 +1192,8 @@ static int check_overlap (const void *p1, size_t n1, · 7 unmodified lines
12071192 if (no_checking == 0 && n1 != 0 && n2 !=0 &&
12081193 ((p1 <= p2 && p1e > p2) || /* p1----p2====p1e----p2e */
12091194 (p2 <= p1 && p2e > p1))) { /* p2----p1====p2e----p1e */
1210− static char line[100];
1211− sprintf(line, "overlapping regions %p(0x%lx), %p(0x%lx) in %s",
1195+ bound_error("overlapping regions %p(0x%lx), %p(0x%lx) in %s",
12121196 p1, (unsigned long)n1, p2, (unsigned long)n2, function);
1213− bound_error(line);
12141197 return never_fatal < 0;
12151198 }
12161199 return 0;
lib/bt-dll.c+67−0
@@ -0,0 +1,67 @@
1+/* ------------------------------------------------------------- */
2+/* stubs for calling bcheck functions from a dll. */
3+
4+#include <windows.h>
5+#include <stdio.h>
6+
7+#define REDIR_ALL \
8+ REDIR(__bt_init) \
9+ REDIR(tcc_backtrace) \
10+ \
11+ REDIR(__bound_ptr_add) \
12+ REDIR(__bound_ptr_indir1) \
13+ REDIR(__bound_ptr_indir2) \
14+ REDIR(__bound_ptr_indir4) \
15+ REDIR(__bound_ptr_indir8) \
16+ REDIR(__bound_ptr_indir12) \
17+ REDIR(__bound_ptr_indir16) \
18+ REDIR(__bound_local_new) \
19+ REDIR(__bound_local_delete) \
20+ REDIR(__bound_new_region) \
21+ \
22+ REDIR(__bound_free) \
23+ REDIR(__bound_malloc) \
24+ REDIR(__bound_realloc) \
25+ REDIR(__bound_memcpy) \
26+ REDIR(__bound_memcmp) \
27+ REDIR(__bound_memmove) \
28+ REDIR(__bound_memset) \
29+ REDIR(__bound_strlen) \
30+ REDIR(__bound_strcpy) \
31+ REDIR(__bound_strncpy) \
32+ REDIR(__bound_strcmp) \
33+ REDIR(__bound_strncmp) \
34+ REDIR(__bound_strcat) \
35+ REDIR(__bound_strchr) \
36+ REDIR(__bound_strdup)
37+
38+#define REDIR(s) void *s;
39+static struct { REDIR_ALL } all_ptrs;
40+#undef REDIR
41+#define REDIR(s) #s"\0"
42+static const char all_names[] = REDIR_ALL;
43+#undef REDIR
44+#define REDIR(s) __asm__(".global "#s";"#s": jmp *%0" : : "m" (all_ptrs.s) );
45+static void all_jmps() { REDIR_ALL }
46+#undef REDIR
47+
48+void __bt_init_dll(int bcheck)
49+{
50+ const char *s = all_names;
51+ void **p = (void**)&all_ptrs;
52+ do {
53+ *p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
54+ if (NULL == *p) {
55+ char buf[100];
56+ sprintf(buf,
57+ "Error: function '%s()' not found in executable. "
58+ "(Need -bt or -b for linking the exe.)", s);
59+ if (GetStdHandle(STD_ERROR_HANDLE))
60+ fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
61+ else
62+ MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
63+ ExitProcess(1);
64+ }
65+ s = strchr(s,'\0') + 1, ++p;
66+ } while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
67+}
lib/bt-exe.c+43−0
@@ -0,0 +1,43 @@
1+/* ------------------------------------------------------------- */
2+/* for linking rt_printline and the signal/exception handler
3+ from tccrun.c into executables. */
4+
5+#define CONFIG_TCC_BACKTRACE_ONLY
6+#include "../tccrun.c"
7+
8+int (*__rt_error)(void*, void*, const char *, va_list);
9+
10+#ifndef _WIN32
11+# define __declspec(n)
12+#endif
13+
14+__declspec(dllexport)
15+void __bt_init(rt_context *p, int num_callers)
16+{
17+ __attribute__((weak)) int main();
18+ __attribute__((weak)) void __bound_init(void*);
19+ struct rt_context *rc = &g_rtctxt;
20+ //fprintf(stderr, "__bt_init %d %p %p\n", num_callers, p->stab_sym, p->bounds_start), fflush(stderr);
21+ if (num_callers) {
22+ memcpy(rc, p, offsetof(rt_context, next));
23+ rc->num_callers = num_callers - 1;
24+ rc->top_func = main;
25+ __rt_error = _rt_error;
26+ set_exception_handler();
27+ } else {
28+ p->next = rc->next, rc->next = p;
29+ }
30+ if (__bound_init && p->bounds_start)
31+ __bound_init(p->bounds_start);
32+}
33+
34+/* copy a string and truncate it. */
35+static char *pstrcpy(char *buf, size_t buf_size, const char *s)
36+{
37+ int l = strlen(s);
38+ if (l >= buf_size)
39+ l = buf_size - 1;
40+ memcpy(buf, s, l);
41+ buf[l] = 0;
42+ return buf;
43+}
lib/bt-log.c+36−0
@@ -0,0 +1,36 @@
1+/* ------------------------------------------------------------- */
2+/* function to get a stack backtrace on demand with a message */
3+
4+#include <stdio.h>
5+#include <string.h>
6+
7+int (*__rt_error)(void*, void*, const char *, va_list);
8+
9+#ifdef _WIN32
10+# define DLL_EXPORT __declspec(dllexport)
11+#else
12+# define DLL_EXPORT
13+#endif
14+
15+DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
16+{
17+ va_list ap;
18+ int ret;
19+
20+ if (__rt_error) {
21+ void *fp = __builtin_frame_address(1);
22+ void *ip = __builtin_return_address(0);
23+ va_start(ap, fmt);
24+ ret = __rt_error(fp, ip, fmt, ap);
25+ va_end(ap);
26+ } else {
27+ const char *p;
28+ if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
29+ fmt = p + 1;
30+ va_start(ap, fmt);
31+ ret = vfprintf(stderr, fmt, ap);
32+ va_end(ap);
33+ fprintf(stderr, "\n"), fflush(stderr);
34+ }
35+ return ret;
36+}
libtcc.c+4−4
@@ -776,9 +776,6 @@ LIBTCCAPI TCCState *tcc_new(void) · 775 unmodified lines
776776 /* enable this if you want symbols with leading underscore on windows: */
777777 #if 0 /* def TCC_TARGET_PE */
778778 s->leading_underscore = 1;
779−#endif
780−#ifdef CONFIG_TCC_BACKTRACE
781− s->rt_num_callers = 6;
782779 #endif
783780 s->ppfp = stdout;
784781 /* might be used in error() before preprocess_start() */
@@ -1556,7 +1553,7 @@ static const TCCOption tcc_options[] = { · 771 unmodified lines
15561553 { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG },
15571554 { "bench", TCC_OPTION_bench, 0 },
15581555 #ifdef CONFIG_TCC_BACKTRACE
1559− { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
1556+ { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
15601557 #endif
15611558 #ifdef CONFIG_TCC_BCHECK
15621559 { "b", TCC_OPTION_b, 0 },
@@ -1809,11 +1806,14 @@ reparse: · 246 unmodified lines
18091806 #ifdef CONFIG_TCC_BACKTRACE
18101807 case TCC_OPTION_bt:
18111808 s->rt_num_callers = atoi(optarg);
1809+ s->do_backtrace = 1;
1810+ s->do_debug = 1;
18121811 break;
18131812 #endif
18141813 #ifdef CONFIG_TCC_BCHECK
18151814 case TCC_OPTION_b:
18161815 s->do_bounds_check = 1;
1816+ s->do_backtrace = 1;
18171817 s->do_debug = 1;
18181818 break;
18191819 #endif
tcc-doc.texi+6−3
@@ -372,9 +372,12 @@ Try to continue in case of a bound checking error. · 371 unmodified lines
372372
373373 Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
374374
375−@item -bt N
376−Display N callers in stack traces. This is useful with @option{-g} or
377−@option{-b}.
375+@item -bt[N]
376+Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
377+With executables, additional support for stack traces is included.
378+
379+A function @code{ int tcc_backtrace(const char *fmt, ...); } is provided
380+to trigger a stack trace with a message on demand.
378381
379382 @end table
380383
tcc.c+1−1
@@ -61,7 +61,7 @@ static const char help[] = · 60 unmodified lines
6161 " -b compile with built-in memory and bounds checker (implies -g)\n"
6262 #endif
6363 #ifdef CONFIG_TCC_BACKTRACE
64− " -bt N show N callers in stack traces\n"
64+ " -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
6565 #endif
6666 "Misc. options:\n"
6767 " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
tcc.h+11−15
@@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr); · 291 unmodified lines
292292 #ifndef TCC_LIBTCC1
293293 # define TCC_LIBTCC1 "libtcc1.a"
294294 #endif
295−#ifndef TCC_LIBBCHECK
296−# define TCC_LIBBCHECK "bcheck.o"
297−#endif
298295
299296 /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
300297 #if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
@@ -475,7 +472,7 @@ struct SymAttr { · 174 unmodified lines
475472 nodecorate : 1,
476473 dllimport : 1,
477474 addrtaken : 1,
478− unused : 3;
475+ xxxx : 3; /* not used */
479476 };
480477
481478 /* function attributes or temporary attributes for parsing */
@@ -484,7 +481,8 @@ struct FuncAttr { · 2 unmodified lines
484481 func_call : 3, /* calling convention (0..5), see below */
485482 func_type : 2, /* FUNC_OLD/NEW/ELLIPSIS */
486483 func_noreturn : 1, /* attribute((noreturn)) */
487− xxxx : 2,
484+ func_ctor : 1, /* attribute((constructor)) */
485+ func_dtor : 1, /* attribute((destructor)) */
488486 func_args : 8; /* PE __stdcall args */
489487 };
490488
@@ -619,8 +617,6 @@ typedef struct TokenString { · 128 unmodified lines
619617 typedef struct AttributeDef {
620618 struct SymAttr a;
621619 struct FuncAttr f;
622− unsigned short constructor:1;
623− unsigned short destructor:1;
624620 struct Section *section;
625621 Sym *cleanup_func;
626622 int alias_target; /* token */
@@ -718,6 +714,7 @@ struct TCCState { · 91 unmodified lines
718714
719715 /* compile with debug symbol (and use them if error during execution) */
720716 unsigned char do_debug;
717+ unsigned char do_backtrace;
721718 #ifdef CONFIG_TCC_BCHECK
722719 /* compile with built-in memory and bounds checker */
723720 unsigned char do_bounds_check;
@@ -884,11 +881,7 @@ struct TCCState { · 160 unmodified lines
884881 const char *runtime_main;
885882 void **runtime_mem;
886883 int nb_runtime_mem;
887−#ifdef CONFIG_TCC_BACKTRACE
888884 int rt_num_callers;
889− const char **rt_bound_error_msg;
890− void *rt_prog_main;
891−#endif
892885 #endif
893886
894887 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); · 364 unmodified lines
12591252 #ifdef CONFIG_TCC_BCHECK
12601253 ST_FUNC void tcc_add_bcheck(TCCState *s1);
12611254 #endif
1255+#ifdef CONFIG_TCC_BACKTRACE
1256+ST_FUNC void tcc_add_btstub(TCCState *s1);
1257+#endif
12621258 ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
12631259 PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
12641260 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); · 220 unmodified lines
14851481 #endif
14861482 ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, addr_t addend);
14871483
1488−ST_FUNC void add_init_array (TCCState *s1, Sym *sym);
1489−ST_FUNC void add_fini_array (TCCState *s1, Sym *sym);
1490−
14911484 ST_FUNC int put_elf_str(Section *s, const char *sym);
14921485 ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
14931486 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); · 12 unmodified lines
15061499 ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
15071500 ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
15081501 ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
1509−ST_FUNC void tcc_add_runtime(TCCState *s1);
1502+ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
15101503
15111504 #ifndef ELF_OBJ_ONLY
15121505 ST_FUNC void build_got_entries(TCCState *s1);
@@ -1521,9 +1514,12 @@ ST_FUNC void list_elf_symbols(TCCState *s, void *ctx, · 8 unmodified lines
15211514 ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
15221515 #endif
15231516
1517+ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs);
1518+
15241519 #ifndef TCC_TARGET_PE
15251520 ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
15261521 ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
1522+ST_FUNC void tcc_add_runtime(TCCState *s1);
15271523 #endif
15281524
15291525 /* ------------ xxx-link.c ------------ */
tccelf.c+151−106
@@ -85,33 +85,21 @@ ST_FUNC void tccelf_bounds_new(TCCState *s) · 84 unmodified lines
8585 lbounds_section = new_section(s, ".lbounds",
8686 SHT_PROGBITS, SHF_ALLOC);
8787 }
88−
89−ST_FUNC void tcc_add_bcheck(TCCState *s1)
90−{
91− addr_t *ptr;
92−
93− if (0 == s1->do_bounds_check)
94− return;
95− ptr = section_ptr_add(bounds_section, sizeof(*ptr));
96− *ptr = 0;
97− set_elf_sym(symtab_section, 0, 0,
98− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
99− bounds_section->sh_num, "__bounds_start");
100− /* pull bcheck.o from libtcc1.a */
101− set_elf_sym(symtab_section, 0, 0,
102− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
103− SHN_UNDEF, "__bound_init");
104−}
10588 #endif
10689
10790 ST_FUNC void tccelf_stab_new(TCCState *s)
10891 {
10992 TCCState *s1 = s;
110− stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
93+ int shf = 0;
94+#ifdef CONFIG_TCC_BACKTRACE
95+ /* include stab info with standalone backtrace support */
96+ if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
97+ shf = SHF_ALLOC;
98+#endif
99+ stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
111100 stab_section->sh_entsize = sizeof(Stab_Sym);
112− stab_section->sh_addralign = 4;
113− stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0);
114− put_elf_str(stab_section->link, "");
101+ stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
102+ stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
115103 /* put first entry */
116104 put_stabs(s, "", 0, 0, 0, 0);
117105 }
@@ -803,6 +791,17 @@ ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int d · 685 unmodified lines
803791 {
804792 Stab_Sym *sym;
805793
794+ unsigned offset;
795+ if (type == N_SLINE
796+ && (offset = stab_section->data_offset)
797+ && (sym = (Stab_Sym*)(stab_section->data + offset) - 1)
798+ && sym->n_type == type
799+ && sym->n_value == value) {
800+ /* just update line_number in previous entry */
801+ sym->n_desc = desc;
802+ return;
803+ }
804+
806805 sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
807806 if (str) {
808807 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 · 9 unmodified lines
818817 ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
819818 unsigned long value, Section *sec, int sym_index)
820819 {
821− put_stabs(s1, str, type, other, desc, value);
822820 put_elf_reloc(symtab_section, stab_section,
823− stab_section->data_offset - sizeof(unsigned int),
824− R_DATA_32, sym_index);
821+ stab_section->data_offset + 8,
822+ sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32,
823+ sym_index);
824+ put_stabs(s1, str, type, other, desc, value);
825825 }
826826
827827 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) · 162 unmodified lines
990990 relocate(s1, rel, type, ptr, addr, tgt);
991991 }
992992 /* if the relocation is allocated, we change its symbol table */
993− if (sr->sh_flags & SHF_ALLOC)
993+ if (sr->sh_flags & SHF_ALLOC) {
994994 sr->link = s1->dynsym;
995+ if (s1->output_type == TCC_OUTPUT_DLL) {
996+ size_t r = (uint8_t*)qrel - sr->data;
997+ if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE
998+ && 0 == strcmp(s->name, ".stab"))
999+ r = 0; /* cannot apply 64bit relocation to 32bit value */
1000+ sr->data_offset = sr->sh_size = r;
1001+ }
1002+ }
9951003 }
9961004
9971005 #ifndef ELF_OBJ_ONLY
@@ -1268,16 +1276,20 @@ static void put_dt(Section *dynamic, int dt, addr_t val) · 270 unmodified lines
12681276 }
12691277 #endif
12701278
1279+ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, long offs)
1280+{
1281+ int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
1282+ if (sec && offs == -1)
1283+ offs = sec->data_offset;
1284+ return set_elf_sym(symtab_section, offs, 0,
1285+ ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
1286+}
1287+
12711288 static void add_init_array_defines(TCCState *s1, const char *section_name)
12721289 {
12731290 Section *s;
12741291 long end_offset;
1275− char sym_start[1024];
1276− char sym_end[1024];
1277−
1278− snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
1279− snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
1280−
1292+ char buf[1024];
12811293 s = find_section(s1, section_name);
12821294 if (!s) {
12831295 end_offset = 0;
@@ -1285,15 +1297,10 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) · 1 unmodified line
12851297 } else {
12861298 end_offset = s->data_offset;
12871299 }
1288−
1289− set_elf_sym(symtab_section,
1290− 0, 0,
1291− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1292− s->sh_num, sym_start);
1293− set_elf_sym(symtab_section,
1294− end_offset, 0,
1295− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1296− s->sh_num, sym_end);
1300+ snprintf(buf, sizeof(buf), "__%s_start", section_name + 1);
1301+ set_global_sym(s1, buf, s, 0);
1302+ snprintf(buf, sizeof(buf), "__%s_end", section_name + 1);
1303+ set_global_sym(s1, buf, s, end_offset);
12971304 }
12981305
12991306 #ifndef TCC_TARGET_PE
@@ -1305,33 +1312,92 @@ static int tcc_add_support(TCCState *s1, const char *filename) · 5 unmodified lines
13051312 }
13061313 #endif
13071314
1308−static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
1315+ST_FUNC void add_array (TCCState *s1, const char *sec, int c)
13091316 {
13101317 Section *s;
1311− unsigned char *ptr;
1312−
1313− s = find_section(s1, section);
1314− if (s) {
1315− s->sh_flags |= SHF_WRITE;
1318+ s = find_section(s1, sec);
1319+ s->sh_flags |= SHF_WRITE;
13161320 #ifndef TCC_TARGET_PE
1317− s->sh_type = sh_type;
1321+ s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY;
13181322 #endif
1319− ptr = section_ptr_add(s, PTR_SIZE);
1320− memset (ptr, 0, PTR_SIZE);
1321− put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
1322− }
1323+ put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
1324+ section_ptr_add(s, PTR_SIZE);
13231325 }
13241326
1325−ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
1327+#ifdef CONFIG_TCC_BCHECK
1328+ST_FUNC void tcc_add_bcheck(TCCState *s1)
13261329 {
1327− add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
1330+ if (0 == s1->do_bounds_check)
1331+ return;
1332+ section_ptr_add(bounds_section, sizeof(addr_t));
1333+}
1334+#endif
1335+
1336+#ifdef CONFIG_TCC_BACKTRACE
1337+static void put_ptr(TCCState *s1, Section *s, int offs)
1338+{
1339+ int c;
1340+ c = set_global_sym(s1, NULL, s, offs);
1341+ s = data_section;
1342+ put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
1343+ section_ptr_add(s, PTR_SIZE);
1344+}
1345+
1346+/* set symbol to STB_LOCAL and resolve. The point is to not export it as
1347+ a dynamic symbol to allow so's to have one each with a different value. */
1348+static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset)
1349+{
1350+ int c = find_elf_sym(s1->symtab, name);
1351+ if (c) {
1352+ ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c;
1353+ esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE);
1354+ esym->st_value = offset;
1355+ esym->st_shndx = s->sh_num;
1356+ }
13281357 }
13291358
1330−ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
1359+ST_FUNC void tcc_add_btstub(TCCState *s1)
13311360 {
1332− add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
1361+ Section *s;
1362+ int n, o, b;
1363+ CString cstr;
1364+
1365+ s = data_section;
1366+ o = s->data_offset;
1367+ /* create (part of) a struct rt_context (see tccrun.c) */
1368+ put_ptr(s1, stab_section, 0);
1369+ put_ptr(s1, stab_section, -1);
1370+ put_ptr(s1, stab_section->link, 0);
1371+ section_ptr_add(s, 3 * PTR_SIZE);
1372+ /* prog_base */
1373+ put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
1374+ section_ptr_add(s, PTR_SIZE);
1375+ n = 2 * PTR_SIZE, b = 0;
1376+#ifdef CONFIG_TCC_BCHECK
1377+ if (s1->do_bounds_check) {
1378+ put_ptr(s1, bounds_section, 0);
1379+ n -= PTR_SIZE, b = 1;
1380+ }
1381+#endif
1382+ section_ptr_add(s, n);
1383+
1384+ cstr_new(&cstr);
1385+ cstr_printf(&cstr,
1386+ " extern void __bt_init(),*__rt_info[],__bt_init_dll();"
1387+ "__attribute__((constructor)) static void __bt_init_rt(){");
1388+#ifdef TCC_TARGET_PE
1389+ if (s1->output_type == TCC_OUTPUT_DLL)
1390+ cstr_printf(&cstr, "__bt_init_dll(%d);", b);
1391+#endif
1392+ cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
1393+ s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
1394+ tcc_compile_string(s1, cstr.data);
1395+ cstr_free(&cstr);
1396+ set_local_sym(s1, "__rt_info", s, o);
13331397 }
1398+#endif
13341399
1400+#ifndef TCC_TARGET_PE
13351401 /* add tcc runtime libraries */
13361402 ST_FUNC void tcc_add_runtime(TCCState *s1)
13371403 {
@@ -1340,7 +1406,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 2 unmodified lines
13401406 tcc_add_bcheck(s1);
13411407 #endif
13421408 tcc_add_pragma_libs(s1);
1343−#ifndef TCC_TARGET_PE
13441409 /* add libc */
13451410 if (!s1->nostdlib) {
13461411 tcc_add_library_err(s1, "c");
@@ -1356,7 +1421,17 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 9 unmodified lines
13561421 if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
13571422 tcc_add_library_err(s1, "pthread");
13581423 tcc_add_library_err(s1, "dl");
1359− tcc_add_support(s1, TCC_LIBBCHECK);
1424+ tcc_add_support(s1, "bcheck.o");
1425+ }
1426+#endif
1427+#ifdef CONFIG_TCC_BACKTRACE
1428+ if (s1->do_backtrace) {
1429+ if (s1->output_type == TCC_OUTPUT_EXE)
1430+ tcc_add_support(s1, "bt-exe.o");
1431+ if (s1->output_type != TCC_OUTPUT_DLL)
1432+ tcc_add_support(s1, "bt-log.o");
1433+ if (s1->output_type != TCC_OUTPUT_MEMORY)
1434+ tcc_add_btstub(s1);
13601435 }
13611436 #endif
13621437 tcc_add_support(s1, TCC_LIBTCC1);
@@ -1364,8 +1439,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 1 unmodified line
13641439 if (s1->output_type != TCC_OUTPUT_MEMORY)
13651440 tcc_add_crt(s1, "crtn.o");
13661441 }
1367−#endif
13681442 }
1443+#endif
13691444
13701445 /* add various standard linker symbols (must be done after the
13711446 sections are filled (for example after allocating common
@@ -1376,59 +1451,39 @@ static void tcc_add_linker_symbols(TCCState *s1) · 4 unmodified lines
13761451 int i;
13771452 Section *s;
13781453
1379− set_elf_sym(symtab_section,
1380− text_section->data_offset, 0,
1381− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1382− text_section->sh_num, "_etext");
1383− set_elf_sym(symtab_section,
1384− data_section->data_offset, 0,
1385− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1386− data_section->sh_num, "_edata");
1387− set_elf_sym(symtab_section,
1388− bss_section->data_offset, 0,
1389− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1390− bss_section->sh_num, "_end");
1454+ set_global_sym(s1, "_etext", text_section, -1);
1455+ set_global_sym(s1, "_edata", data_section, -1);
1456+ set_global_sym(s1, "_end", bss_section, -1);
13911457 #ifdef TCC_TARGET_RISCV64
13921458 /* XXX should be .sdata+0x800, not .data+0x800 */
1393− set_elf_sym(symtab_section,
1394− 0x800, 0,
1395− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1396− data_section->sh_num, "__global_pointer$");
1459+ set_global_sym(s1, "__global_pointer$", data_section, 0x800);
13971460 #endif
13981461 /* horrible new standard ldscript defines */
13991462 add_init_array_defines(s1, ".preinit_array");
14001463 add_init_array_defines(s1, ".init_array");
14011464 add_init_array_defines(s1, ".fini_array");
1402−
14031465 /* add start and stop symbols for sections whose name can be
14041466 expressed in C */
14051467 for(i = 1; i < s1->nb_sections; i++) {
14061468 s = s1->sections[i];
1407− if (s->sh_type == SHT_PROGBITS &&
1408− (s->sh_flags & SHF_ALLOC)) {
1469+ if ((s->sh_flags & SHF_ALLOC)
1470+ && (s->sh_type == SHT_PROGBITS
1471+ || s->sh_type == SHT_STRTAB)) {
14091472 const char *p;
1410− int ch;
1411−
14121473 /* check if section name can be expressed in C */
14131474 p = s->name;
14141475 for(;;) {
1415− ch = *p;
1416− if (!ch)
1476+ int c = *p;
1477+ if (!c)
14171478 break;
1418− if (!isid(ch) && !isnum(ch))
1479+ if (!isid(c) && !isnum(c))
14191480 goto next_sec;
14201481 p++;
14211482 }
14221483 snprintf(buf, sizeof(buf), "__start_%s", s->name);
1423− set_elf_sym(symtab_section,
1424− 0, 0,
1425− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1426− s->sh_num, buf);
1484+ set_global_sym(s1, buf, s, 0);
14271485 snprintf(buf, sizeof(buf), "__stop_%s", s->name);
1428− set_elf_sym(symtab_section,
1429− s->data_offset, 0,
1430− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1431− s->sh_num, buf);
1486+ set_global_sym(s1, buf, s, -1);
14321487 }
14331488 next_sec: ;
14341489 }
@@ -1699,8 +1754,8 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) · 264 unmodified lines
16991754 !(s->sh_flags & SHF_ALLOC) &&
17001755 (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
17011756 prepare_dynamic_rel(s1, s)) {
1702− if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
1703− textrel = 1;
1757+ if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
1758+ textrel = 1;
17041759 } else
17051760 #endif
17061761 if ((s1->do_debug && s->sh_type != SHT_RELX) ||
@@ -1814,9 +1869,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 107 unmodified lines
18141869 if (s == interp) {
18151870 if (k != 0)
18161871 continue;
1817− } else if (s->sh_type == SHT_DYNSYM ||
1818− s->sh_type == SHT_STRTAB ||
1819− s->sh_type == SHT_HASH) {
1872+ } else if ((s->sh_type == SHT_DYNSYM ||
1873+ s->sh_type == SHT_STRTAB ||
1874+ s->sh_type == SHT_HASH)
1875+ && !strstr(s->name, ".stab")) {
18201876 if (k != 1)
18211877 continue;
18221878 } 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, · 237 unmodified lines
20602116 Section *s;
20612117 ElfW(Ehdr) ehdr;
20622118 ElfW(Shdr) shdr, *sh;
2063− ElfW(Sym) *sym;
20642119
20652120 file_type = s1->output_type;
20662121 shnum = s1->nb_sections;
@@ -2131,10 +2186,6 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, · 64 unmodified lines
21312186 offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
21322187
21332188 sort_syms(s1, symtab_section);
2134− if (s1->dynsym)
2135− for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
2136− if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
2137− s1->dynsym->sh_info++;
21382189 for(i = 1; i < s1->nb_sections; i++) {
21392190 s = s1->sections[sec_order[i]];
21402191 if (s->sh_type != SHT_NOBITS) {
@@ -2842,12 +2893,6 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) · 701 unmodified lines
28422893 for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
28432894 Section *s = symtab_section;
28442895 sym_index = find_elf_sym(s, p);
2845−#ifdef TCC_TARGET_PE /* windows DLL's don't have UNDEF syms */
2846− if (sym_index == 0) {
2847− s = s1->dynsymtab_section;
2848− sym_index = find_elf_sym(s, p);
2849− }
2850−#endif
28512896 if (!sym_index)
28522897 continue;
28532898 sym = &((ElfW(Sym) *)s->data)[sym_index];
tccgen.c+34−52
@@ -103,7 +103,7 @@ ST_DATA struct switch_t { · 102 unmodified lines
103103 struct scope *scope;
104104 } *cur_switch; /* current switch */
105105
106−#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
106+#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
107107 /*list of temporary local variables on the stack in current function. */
108108 ST_DATA struct temp_local_variable {
109109 int location; //offset on stack. Svalue.c.i
@@ -375,11 +375,10 @@ static BufferedFile* put_new_file(TCCState *s1) · 265 unmodified lines
375375 ST_FUNC void tcc_debug_line(TCCState *s1)
376376 {
377377 BufferedFile *f;
378− if (!s1->do_debug || !(f = put_new_file(s1)))
379− return;
380− if (last_line_num == f->line_num)
381− return;
382− if (text_section != cur_text_section)
378+ if (!s1->do_debug
379+ || cur_text_section != text_section
380+ || !(f = put_new_file(s1))
381+ || last_line_num == f->line_num)
383382 return;
384383 if (func_ind != -1) {
385384 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) · 23 unmodified lines
409408 {
410409 if (!s1->do_debug)
411410 return;
412−#if 0 // this seems to confuse gnu tools
413411 put_stabn(s1, N_FUN, 0, 0, size);
414−#endif
415412 }
416413
417414 /* put alternative filename */
@@ -2592,7 +2589,6 @@ redo: · 2174 unmodified lines
25922589 vswap();
25932590 gen_op('-');
25942591 }
2595− vtop[-1].r &= ~VT_MUSTBOUND;
25962592 gen_bounded_ptr_add();
25972593 } else
25982594 #endif
@@ -3428,6 +3424,10 @@ ST_FUNC void vstore(void) · 829 unmodified lines
34283424
34293425 /* destination */
34303426 vswap();
3427+#ifdef CONFIG_TCC_BCHECK
3428+ if (vtop->r & VT_MUSTBOUND)
3429+ gbound(); /* check would be wrong after gaddrof() */
3430+#endif
34313431 vtop->type.t = VT_PTR;
34323432 gaddrof();
34333433
@@ -3444,8 +3444,11 @@ ST_FUNC void vstore(void) · 10 unmodified lines
34443444
34453445 vswap();
34463446 /* source */
3447− vtop->r &= ~VT_MUSTBOUND;
34483447 vpushv(vtop - 2);
3448+#ifdef CONFIG_TCC_BCHECK
3449+ if (vtop->r & VT_MUSTBOUND)
3450+ gbound();
3451+#endif
34493452 vtop->type.t = VT_PTR;
34503453 gaddrof();
34513454 /* type size */
@@ -3662,11 +3665,11 @@ redo: · 210 unmodified lines
36623665 }
36633666 case TOK_CONSTRUCTOR1:
36643667 case TOK_CONSTRUCTOR2:
3665− ad->constructor = 1;
3668+ ad->f.func_ctor = 1;
36663669 break;
36673670 case TOK_DESTRUCTOR1:
36683671 case TOK_DESTRUCTOR2:
3669− ad->destructor = 1;
3672+ ad->f.func_dtor = 1;
36703673 break;
36713674 case TOK_SECTION1:
36723675 case TOK_SECTION2:
@@ -4958,6 +4961,10 @@ ST_FUNC void unary(void) · 1285 unmodified lines
49584961 Sym *s;
49594962 AttributeDef ad;
49604963
4964+ /* generate line number info */
4965+ if (tcc_state->do_debug)
4966+ tcc_debug_line(tcc_state);
4967+
49614968 sizeof_caller = in_sizeof;
49624969 in_sizeof = 0;
49634970 type.ref = NULL;
@@ -5522,7 +5529,7 @@ special_math_val: · 558 unmodified lines
55225529 vtop->r |= VT_LVAL;
55235530 #ifdef CONFIG_TCC_BCHECK
55245531 /* if bound checking, the referenced pointer must be checked */
5525− if (tcc_state->do_bounds_check && (vtop->r & VT_VALMASK) != VT_LOCAL)
5532+ if (tcc_state->do_bounds_check)
55265533 vtop->r |= VT_MUSTBOUND;
55275534 #endif
55285535 }
@@ -5538,15 +5545,6 @@ special_math_val: · 9 unmodified lines
55385545 Sym *sa;
55395546 int nb_args, ret_nregs, ret_align, regsize, variadic;
55405547
5541−#ifdef CONFIG_TCC_BCHECK
5542− if (tcc_state->do_bounds_check && (vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
5543− addr_t *bounds_ptr;
5544−
5545− bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
5546− bounds_ptr[0] = 1; /* marks alloca/vla used */
5547− bounds_ptr[1] = 0;
5548− }
5549−#endif
55505548 /* function call */
55515549 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
55525550 /* pointer test (no array accepted) */
@@ -6514,10 +6512,10 @@ again: · 961 unmodified lines
65146512 }
65156513
65166514 prev_scope(&o, is_expr);
6517−
6518− if (0 == local_scope && !nocode_wanted)
6515+ if (local_scope)
6516+ next();
6517+ else if (!nocode_wanted)
65196518 check_func_return();
6520− next();
65216519
65226520 } else if (t == TOK_RETURN) {
65236521 b = (func_vt.t & VT_BTYPE) != VT_VOID;
@@ -7582,16 +7580,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 1058 unmodified lines
75827580 gen_vla_sp_save(addr);
75837581 cur_scope->vla.loc = addr;
75847582 cur_scope->vla.num++;
7585−#ifdef CONFIG_TCC_BCHECK
7586− if (bcheck) {
7587− addr_t *bounds_ptr;
7588−
7589− bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
7590− bounds_ptr[0] = 1; /* marks alloca/vla used */
7591− bounds_ptr[1] = 0;
7592− }
7593−#endif
7594−
75957583 } else if (has_init) {
75967584 size_t oldreloc_offset = 0;
75977585 if (sec && sec->reloc)
@@ -7617,7 +7605,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 19 unmodified lines
76177605
76187606 /* parse a function defined by symbol 'sym' and generate its code in
76197607 'cur_text_section' */
7620−static void gen_function(Sym *sym, AttributeDef *ad)
7608+static void gen_function(Sym *sym)
76217609 {
76227610 /* Initialize VLA state */
76237611 struct scope f = { 0 };
@@ -7632,17 +7620,12 @@ static void gen_function(Sym *sym, AttributeDef *ad) · 8 unmodified lines
76327620 }
76337621 /* NOTE: we patch the symbol size later */
76347622 put_extern_sym(sym, cur_text_section, ind, 0);
7635−
7636− if (ad && ad->constructor) {
7637− add_init_array (tcc_state, sym);
7638− }
7639− if (ad && ad->destructor) {
7640− add_fini_array (tcc_state, sym);
7641− }
7642−
7623+ if (sym->type.ref->f.func_ctor)
7624+ add_array (tcc_state, ".init_array", sym->c);
7625+ if (sym->type.ref->f.func_dtor)
7626+ add_array (tcc_state, ".fini_array", sym->c);
76437627 funcname = get_tok_str(sym->v, NULL);
76447628 func_ind = ind;
7645−
76467629 /* put debug symbol */
76477630 tcc_debug_funcstart(tcc_state, sym);
76487631 /* push a dummy symbol to enable local sym storage */
@@ -7675,6 +7658,8 @@ static void gen_function(Sym *sym, AttributeDef *ad) · 26 unmodified lines
76757658 ind = 0; /* for safety */
76767659 nocode_wanted = 0x80000000;
76777660 check_vstack();
7661+ /* do this after funcend debug info */
7662+ next();
76787663 }
76797664
76807665 static void gen_inline_functions(TCCState *s)
@@ -7698,7 +7683,7 @@ static void gen_inline_functions(TCCState *s) · 17 unmodified lines
76987683 begin_macro(fn->func_str, 1);
76997684 next();
77007685 cur_text_section = text_section;
7701− gen_function(sym, NULL);
7686+ gen_function(sym);
77027687 end_macro();
77037688
77047689 inline_generated = 1;
@@ -7866,11 +7851,8 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 161 unmodified lines
78667851 the compilation unit only if they are used */
78677852 if (sym->type.t & VT_INLINE) {
78687853 struct InlineFunc *fn;
7869− const char *filename;
7870−
7871− filename = file ? file->filename : "";
7872− fn = tcc_malloc(sizeof *fn + strlen(filename));
7873− strcpy(fn->filename, filename);
7854+ fn = tcc_malloc(sizeof *fn + strlen(file->filename));
7855+ strcpy(fn->filename, file->filename);
78747856 fn->sym = sym;
78757857 skip_or_save_block(&fn->func_str);
78767858 dynarray_add(&tcc_state->inline_fns,
@@ -7880,7 +7862,7 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym) · 3 unmodified lines
78807862 cur_text_section = ad.section;
78817863 if (!cur_text_section)
78827864 cur_text_section = text_section;
7883− gen_function(sym, &ad);
7865+ gen_function(sym);
78847866 }
78857867 break;
78867868 } else {
tccpe.c+176−146
@@ -239,8 +239,6 @@ typedef struct _IMAGE_BASE_RELOCATION { · 238 unmodified lines
239239 #define IMAGE_SCN_MEM_EXECUTE 0x20000000
240240 #define IMAGE_SCN_MEM_READ 0x40000000
241241 #define IMAGE_SCN_MEM_WRITE 0x80000000
242−#define IMAGE_SCN_TYPE_NOLOAD 0x00000002
243−#define IMAGE_SCN_LNK_REMOVE 0x00000800
244242
245243 #pragma pack(pop)
246244
@@ -299,6 +297,7 @@ enum { · 52 unmodified lines
299297 sec_other ,
300298 sec_rsrc ,
301299 sec_stab ,
300+ sec_stabstr ,
302301 sec_reloc ,
303302 sec_last
304303 };
@@ -318,12 +317,12 @@ static const DWORD pe_sec_flags[] = { · 13 unmodified lines
318317 #endif
319318
320319 struct section_info {
321− int cls, ord;
320+ int cls;
322321 char name[32];
323322 DWORD sh_addr;
324323 DWORD sh_size;
325324 DWORD pe_flags;
326− unsigned char *data;
325+ Section *sec;
327326 DWORD data_size;
328327 IMAGE_SECTION_HEADER ish;
329328 };
@@ -359,7 +358,7 @@ struct pe_info { · 29 unmodified lines
359358 int subsystem;
360359 DWORD section_align;
361360 DWORD file_align;
362− struct section_info *sec_info;
361+ struct section_info **sec_info;
363362 int sec_count;
364363 struct pe_import_info **imp_info;
365364 int imp_count;
@@ -432,12 +431,10 @@ static int dynarray_assoc(void **pp, int n, int key) · 66 unmodified lines
432431 return -1;
433432 }
434433
435−#if 0
436−ST_FN DWORD umin(DWORD a, DWORD b)
434+static DWORD umin(DWORD a, DWORD b)
437435 {
438436 return a < b ? a : b;
439437 }
440−#endif
441438
442439 static DWORD umax(DWORD a, DWORD b)
443440 {
@@ -467,26 +464,37 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz · 23 unmodified lines
467464 hdr->opthdr.DataDirectory[dir].Size = size;
468465 }
469466
470−static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
467+struct pe_file {
468+ FILE *op;
469+ DWORD sum;
470+ unsigned pos;
471+};
472+
473+static int pe_fwrite(void *data, int len, struct pe_file *pf)
471474 {
472− if (psum) {
473− DWORD sum = *psum;
474− WORD *p = data;
475− int i;
476− for (i = len; i > 0; i -= 2) {
477− sum += (i >= 2) ? *p++ : *(BYTE*)p;
478− sum = (sum + (sum >> 16)) & 0xFFFF;
479− }
480− *psum = sum;
475+ WORD *p = data;
476+ DWORD sum;
477+ int ret, i;
478+ pf->pos += (ret = fwrite(data, 1, len, pf->op));
479+ sum = pf->sum;
480+ for (i = len; i > 0; i -= 2) {
481+ sum += (i >= 2) ? *p++ : *(BYTE*)p;
482+ sum = (sum + (sum >> 16)) & 0xFFFF;
481483 }
482− return len == fwrite(data, 1, len, fp) ? 0 : -1;
484+ pf->sum = sum;
485+ return len == ret ? 0 : -1;
483486 }
484487
485−static void pe_fpad(FILE *fp, DWORD new_pos)
488+static void pe_fpad(struct pe_file *pf, DWORD new_pos)
486489 {
487− DWORD pos = ftell(fp);
488− while (++pos <= new_pos)
489− fputc(0, fp);
490+ char buf[256];
491+ int n, diff = new_pos - pf->pos;
492+ memset(buf, 0, sizeof buf);
493+ while (diff > 0) {
494+ diff -= n = umin(diff, sizeof buf);
495+ fwrite(buf, n, 1, pf->op);
496+ }
497+ pf->pos = new_pos;
490498 }
491499
492500 /*----------------------------------------------------------------------------*/
@@ -598,14 +606,14 @@ static int pe_write(struct pe_info *pe) · 105 unmodified lines
598606 struct pe_header pe_header = pe_template;
599607
600608 int i;
601− FILE *op;
602− DWORD file_offset, sum;
609+ struct pe_file pf = {0};
610+ DWORD file_offset;
603611 struct section_info *si;
604612 IMAGE_SECTION_HEADER *psh;
605613 TCCState *s1 = pe->s1;
606614
607− op = fopen(pe->filename, "wb");
608− if (NULL == op) {
615+ pf.op = fopen(pe->filename, "wb");
616+ if (NULL == pf.op) {
609617 tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
610618 return -1;
611619 }
@@ -624,7 +632,7 @@ static int pe_write(struct pe_info *pe) · 12 unmodified lines
624632 DWORD addr, size;
625633 const char *sh_name;
626634
627− si = pe->sec_info + i;
635+ si = pe->sec_info[i];
628636 sh_name = si->name;
629637 addr = si->sh_addr - pe->imagebase;
630638 size = si->sh_size;
@@ -663,20 +671,18 @@ static int pe_write(struct pe_info *pe) · 32 unmodified lines
663671 break;
664672 }
665673
666− if (pe->thunk == pe->s1->sections[si->ord]) {
667− if (pe->imp_size) {
668− pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
669− pe->imp_offs + addr, pe->imp_size);
670− pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
671− pe->iat_offs + addr, pe->iat_size);
672− }
673− if (pe->exp_size) {
674− pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
675− pe->exp_offs + addr, pe->exp_size);
676− }
674+ if (pe->imp_size) {
675+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
676+ pe->imp_offs, pe->imp_size);
677+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
678+ pe->iat_offs, pe->iat_size);
679+ }
680+ if (pe->exp_size) {
681+ pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
682+ pe->exp_offs, pe->exp_size);
677683 }
678684
679− strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
685+ memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
680686
681687 psh->Characteristics = si->pe_flags;
682688 psh->VirtualAddress = addr;
@@ -707,25 +713,29 @@ static int pe_write(struct pe_info *pe) · 24 unmodified lines
707713 pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
708714 pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
709715
710− sum = 0;
711− pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
716+ pe_fwrite(&pe_header, sizeof pe_header, &pf);
712717 for (i = 0; i < pe->sec_count; ++i)
713− pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
714− pe_fpad(op, pe->sizeofheaders);
718+ pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
719+
720+ file_offset = pe->sizeofheaders;
715721 for (i = 0; i < pe->sec_count; ++i) {
716− si = pe->sec_info + i;
717− psh = &si->ish;
718− if (si->data_size) {
719− pe_fwrite(si->data, si->data_size, op, &sum);
720− file_offset = psh->PointerToRawData + psh->SizeOfRawData;
721− pe_fpad(op, file_offset);
722+ Section *s;
723+ si = pe->sec_info[i];
724+ for (s = si->sec; s; s = s->prev) {
725+ pe_fpad(&pf, file_offset);
726+ pe_fwrite(s->data, s->data_offset, &pf);
727+ if (s->prev)
728+ file_offset += s->prev->sh_addr - s->sh_addr;
722729 }
730+ file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
731+ pe_fpad(&pf, file_offset);
723732 }
724733
725− pe_header.opthdr.CheckSum = sum + file_offset;
726− fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
727− pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
728− fclose (op);
734+ pf.sum += file_offset;
735+ fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
736+ pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
737+
738+ fclose (pf.op);
729739 #ifndef _WIN32
730740 chmod(pe->filename, 0777);
731741 #endif
@@ -796,16 +806,15 @@ static void pe_build_imports(struct pe_info *pe) · 64 unmodified lines
796806 return;
797807
798808 pe_align_section(pe->thunk, 16);
799−
800− pe->imp_offs = dll_ptr = pe->thunk->data_offset;
801809 pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
802− pe->iat_offs = dll_ptr + pe->imp_size;
803810 pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
811+ dll_ptr = pe->thunk->data_offset;
812+ thk_ptr = dll_ptr + pe->imp_size;
813+ ent_ptr = thk_ptr + pe->iat_size;
814+ pe->imp_offs = dll_ptr + rva_base;
815+ pe->iat_offs = thk_ptr + rva_base;
804816 section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
805817
806− thk_ptr = pe->iat_offs;
807− ent_ptr = pe->iat_offs + pe->iat_size;
808−
809818 for (i = 0; i < pe->imp_count; ++i) {
810819 IMAGE_IMPORT_DESCRIPTOR *hdr;
811820 int k, n, dllindex;
@@ -895,7 +904,7 @@ static void pe_build_exports(struct pe_info *pe) · 83 unmodified lines
895904 {
896905 ElfW(Sym) *sym;
897906 int sym_index, sym_end;
898− DWORD rva_base, func_o, name_o, ord_o, str_o;
907+ DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
899908 IMAGE_EXPORT_DIRECTORY *hdr;
900909 int sym_count, ord;
901910 struct pe_sort_sym **sorted, *p;
@@ -937,13 +946,13 @@ static void pe_build_exports(struct pe_info *pe) · 35 unmodified lines
937946 pe_align_section(pe->thunk, 16);
938947 dllname = tcc_basename(pe->filename);
939948
940− pe->exp_offs = pe->thunk->data_offset;
941− func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY);
949+ base_o = pe->thunk->data_offset;
950+ func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
942951 name_o = func_o + sym_count * sizeof (DWORD);
943952 ord_o = name_o + sym_count * sizeof (DWORD);
944953 str_o = ord_o + sym_count * sizeof(WORD);
945954
946− hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
955+ hdr = section_ptr_add(pe->thunk, str_o - base_o);
947956 hdr->Characteristics = 0;
948957 hdr->Base = 1;
949958 hdr->NumberOfFunctions = sym_count;
@@ -985,7 +994,9 @@ static void pe_build_exports(struct pe_info *pe) · 35 unmodified lines
985994 if (op)
986995 fprintf(op, "%s\n", name);
987996 }
988− pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
997+
998+ pe->exp_offs = base_o + rva_base;
999+ pe->exp_size = pe->thunk->data_offset - base_o;
9891000 dynarray_reset(&sorted, &sym_count);
9901001 if (op)
9911002 fclose(op);
@@ -994,18 +1005,19 @@ static void pe_build_exports(struct pe_info *pe) · 2 unmodified lines
9941005 /* ------------------------------------------------------------- */
9951006 static void pe_build_reloc (struct pe_info *pe)
9961007 {
997− DWORD offset, block_ptr, addr;
1008+ DWORD offset, block_ptr, sh_addr, addr;
9981009 int count, i;
9991010 ElfW_Rel *rel, *rel_end;
10001011 Section *s = NULL, *sr;
1012+ struct pe_reloc_header *hdr;
10011013
1002− offset = addr = block_ptr = count = i = 0;
1014+ sh_addr = offset = block_ptr = count = i = 0;
10031015 rel = rel_end = NULL;
10041016
10051017 for(;;) {
10061018 if (rel < rel_end) {
10071019 int type = ELFW(R_TYPE)(rel->r_info);
1008− addr = rel->r_offset + s->sh_addr;
1020+ addr = rel->r_offset + sh_addr;
10091021 ++ rel;
10101022 if (type != REL_TYPE_DIRECT)
10111023 continue;
@@ -1022,28 +1034,30 @@ static void pe_build_reloc (struct pe_info *pe) · 10 unmodified lines
10221034 }
10231035 -- rel;
10241036
1025− } else if (i < pe->sec_count) {
1026− sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
1037+ } else if (s) {
1038+ sr = s->reloc;
10271039 if (sr) {
10281040 rel = (ElfW_Rel *)sr->data;
10291041 rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
1042+ sh_addr = s->sh_addr;
10301043 }
1044+ s = s->prev;
10311045 continue;
1032− }
10331046
1034− if (count) {
1035− /* store the last block and ready for a new one */
1036− struct pe_reloc_header *hdr;
1037− if (count & 1) /* align for DWORDS */
1038− section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
1039− hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
1040− hdr -> offset = offset - pe->imagebase;
1041− hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
1042− count = 0;
1043− }
1047+ } else if (i < pe->sec_count) {
1048+ s = pe->sec_info[i]->sec, ++i;
1049+ continue;
10441050
1045− if (rel >= rel_end)
1051+ } else if (!count)
10461052 break;
1053+
1054+ /* fill the last block and ready for a new one */
1055+ if (count & 1) /* align for DWORDS */
1056+ section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
1057+ hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
1058+ hdr -> offset = offset - pe->imagebase;
1059+ hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
1060+ count = 0;
10471061 }
10481062 }
10491063
@@ -1072,13 +1086,14 @@ static int pe_section_class(Section *s) · 22 unmodified lines
10721086 if (flags & SHF_WRITE)
10731087 return sec_bss;
10741088 }
1075− return sec_other;
10761089 } else {
10771090 if (0 == strcmp(name, ".reloc"))
10781091 return sec_reloc;
1079− if (0 == memcmp(name, ".stab", 5))
1080− return sec_stab;
10811092 }
1093+ if (0 == memcmp(name, ".stab", 5))
1094+ return name[5] ? sec_stabstr : sec_stab;
1095+ if (flags & SHF_ALLOC)
1096+ return sec_other;
10821097 return -1;
10831098 }
10841099
@@ -1092,47 +1107,62 @@ static int pe_assign_addresses (struct pe_info *pe) · 7 unmodified lines
10921107
10931108 if (PE_DLL == pe->type)
10941109 pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
1095−
10961110 // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
10971111
10981112 section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
10991113 for (o = k = 0 ; k < sec_last; ++k) {
11001114 for (i = 1; i < pe->s1->nb_sections; ++i) {
11011115 s = pe->s1->sections[i];
1102− if (k == pe_section_class(s)) {
1103− // printf("%s %d\n", s->name, k);
1104− s->sh_addr = pe->imagebase;
1116+ if (k == pe_section_class(s))
11051117 section_order[o++] = i;
1106− }
11071118 }
11081119 }
11091120
1110− pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
1121+ si = NULL;
11111122 addr = pe->imagebase + 1;
11121123
1113− for (i = 0; i < o; ++i)
1114− {
1124+ for (i = 0; i < o; ++i) {
11151125 k = section_order[i];
11161126 s = pe->s1->sections[k];
11171127 c = pe_section_class(s);
1118− si = &pe->sec_info[pe->sec_count];
11191128
1120−#ifdef PE_MERGE_DATA
1121− if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
1122− /* append .bss to .data */
1123− s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
1124− addr += s->data_offset;
1125− si[-1].sh_size = addr - si[-1].sh_addr;
1129+ if ((c == sec_stab || c == sec_stabstr) && 0 == pe->s1->do_debug)
11261130 continue;
1127− }
1131+
1132+#ifdef PE_MERGE_DATA
1133+ if (c == sec_bss)
1134+ c = sec_data;
11281135 #endif
1129− if (c == sec_stab && 0 == pe->s1->do_debug)
1136+ if (si && c == si->cls) {
1137+ /* merge with previous section */
1138+ s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
1139+ } else {
1140+ si = NULL;
1141+ s->sh_addr = addr = pe_virtual_align(pe, addr);
1142+ }
1143+
1144+ if (c == sec_data && NULL == pe->thunk)
1145+ pe->thunk = s;
1146+
1147+ if (s == pe->thunk) {
1148+ pe_build_imports(pe);
1149+ pe_build_exports(pe);
1150+ }
1151+ if (s == pe->reloc)
1152+ pe_build_reloc (pe);
1153+
1154+ if (0 == s->data_offset)
11301155 continue;
11311156
1157+ if (si)
1158+ goto add_section;
1159+
1160+ si = tcc_mallocz(sizeof *si);
1161+ dynarray_add(&pe->sec_info, &pe->sec_count, si);
1162+
11321163 strcpy(si->name, s->name);
11331164 si->cls = c;
1134− si->ord = k;
1135− si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
1165+ si->sh_addr = addr;
11361166
11371167 si->pe_flags = IMAGE_SCN_MEM_READ;
11381168 if (s->sh_flags & SHF_EXECINSTR)
@@ -1143,48 +1173,35 @@ static int pe_assign_addresses (struct pe_info *pe) · 4 unmodified lines
11431173 si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
11441174 if (s->sh_flags & SHF_WRITE)
11451175 si->pe_flags |= IMAGE_SCN_MEM_WRITE;
1146− if (0 == (s->sh_flags & SHF_ALLOC)) {
1176+ if (0 == (s->sh_flags & SHF_ALLOC))
11471177 si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
1148− if (c == sec_stab)
1149− si->pe_flags |= 0x802; //IMAGE_SCN_TYPE_NOLOAD|IMAGE_SCN_LNK_REMOVE
1150− }
1151−
1152− if (c == sec_data && NULL == pe->thunk)
1153− pe->thunk = s;
11541178
1155− if (s == pe->thunk) {
1156− pe_build_imports(pe);
1157− pe_build_exports(pe);
1179+add_section:
1180+ addr += s->data_offset;
1181+ si->sh_size = addr - si->sh_addr;
1182+ if (s->sh_type != SHT_NOBITS) {
1183+ Section **ps = &si->sec;
1184+ while (*ps)
1185+ ps = &(*ps)->prev;
1186+ *ps = s, s->prev = NULL;
1187+ si->data_size = si->sh_size;
11581188 }
1159−
1160− if (c == sec_reloc)
1161− pe_build_reloc (pe);
1162−
1163− if (s->data_offset)
1164− {
1165− if (s->sh_type != SHT_NOBITS) {
1166− si->data = s->data;
1167− si->data_size = s->data_offset;
1168− }
1169−
1170− addr += s->data_offset;
1171− si->sh_size = s->data_offset;
1172− ++pe->sec_count;
1173− }
1174− //printf("%08x %05x %s %08x\n", si->sh_addr, si->sh_size, si->name, si->pe_flags);
1189+ //printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
11751190 }
1191+ tcc_free(section_order);
11761192 #if 0
11771193 for (i = 1; i < pe->s1->nb_sections; ++i) {
11781194 Section *s = pe->s1->sections[i];
11791195 int type = s->sh_type;
11801196 int flags = s->sh_flags;
1181− printf("section %-16s %-10s %5x %s,%s,%s\n",
1197+ printf("section %-16s %-10s %08x %04x %s,%s,%s\n",
11821198 s->name,
11831199 type == SHT_PROGBITS ? "progbits" :
11841200 type == SHT_NOBITS ? "nobits" :
11851201 type == SHT_SYMTAB ? "symtab" :
11861202 type == SHT_STRTAB ? "strtab" :
11871203 type == SHT_RELX ? "rel" : "???",
1204+ s->sh_addr,
11881205 s->data_offset,
11891206 flags & SHF_ALLOC ? "alloc" : "",
11901207 flags & SHF_WRITE ? "write" : "",
@@ -1193,8 +1210,6 @@ static int pe_assign_addresses (struct pe_info *pe) · 2 unmodified lines
11931210 }
11941211 pe->s1->verbose = 2;
11951212 #endif
1196−
1197− tcc_free(section_order);
11981213 return 0;
11991214 }
12001215
@@ -1860,8 +1875,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 659 unmodified lines
18601875 else
18611876 if (TCC_OUTPUT_DLL == s1->output_type) {
18621877 pe_type = PE_DLL;
1863− /* need this for 'tccelf.c:relocate_section()' */
1864− s1->output_type = TCC_OUTPUT_EXE;
18651878 }
18661879 else {
18671880 pe_type = PE_EXE;
@@ -1881,24 +1894,34 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 13 unmodified lines
18811894 if (!s1->leading_underscore || strchr(start_symbol, '@'))
18821895 ++start_symbol;
18831896
1884− /* grab the startup code from libtcc1 */
1897+#ifdef CONFIG_TCC_BACKTRACE
1898+ if (s1->do_backtrace) {
1899+#ifdef CONFIG_TCC_BCHECK
1900+ if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
1901+ tcc_add_support(s1, "bcheck.o");
1902+#endif
1903+ if (s1->output_type == TCC_OUTPUT_EXE)
1904+ tcc_add_support(s1, "bt-exe.o");
1905+ if (s1->output_type == TCC_OUTPUT_DLL)
1906+ tcc_add_support(s1, "bt-dll.o");
1907+ if (s1->output_type != TCC_OUTPUT_DLL)
1908+ tcc_add_support(s1, "bt-log.o");
1909+ if (s1->output_type != TCC_OUTPUT_MEMORY)
1910+ tcc_add_btstub(s1);
1911+ }
1912+#endif
1913+
1914+ /* grab the startup code from libtcc1.a */
18851915 #ifdef TCC_IS_NATIVE
18861916 if (TCC_OUTPUT_MEMORY != s1->output_type || s1->runtime_main)
18871917 #endif
1888− set_elf_sym(symtab_section,
1889− 0, 0,
1890− ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1891− SHN_UNDEF, start_symbol);
1918+ set_global_sym(s1, start_symbol, NULL, 0);
18921919
18931920 if (0 == s1->nostdlib) {
18941921 static const char *libs[] = {
18951922 "msvcrt", "kernel32", "", "user32", "gdi32", NULL
18961923 };
18971924 const char **pp, *p;
1898−#ifdef TCC_IS_NATIVE
1899− if (s1->do_bounds_check)
1900− tcc_add_support(s1, TCC_LIBBCHECK);
1901−#endif
19021925 tcc_add_support(s1, TCC_LIBTCC1);
19031926 for (pp = libs; 0 != (p = *pp); ++pp) {
19041927 if (*p)
@@ -1907,6 +1930,10 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 2 unmodified lines
19071930 break;
19081931 }
19091932 }
1933+
1934+ /* need this for 'tccelf.c:relocate_section()' */
1935+ if (TCC_OUTPUT_DLL == s1->output_type)
1936+ s1->output_type = TCC_OUTPUT_EXE;
19101937 if (TCC_OUTPUT_MEMORY == s1->output_type)
19111938 pe_type = PE_RUN;
19121939 pe->type = pe_type;
@@ -1970,7 +1997,10 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) · 57 unmodified lines
19701997 pe.filename = filename;
19711998 pe.s1 = s1;
19721999
1973− tcc_add_runtime(s1);
2000+#ifdef CONFIG_TCC_BCHECK
2001+ tcc_add_bcheck(s1);
2002+#endif
2003+ tcc_add_pragma_libs(s1);
19742004 pe_add_runtime(s1, &pe);
19752005 resolve_common_syms(s1);
19762006 pe_set_options(s1, &pe);
@@ -1995,7 +2025,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename) · 18 unmodified lines
19952025 ret = -1;
19962026 else
19972027 ret = pe_write(&pe);
1998− tcc_free(pe.sec_info);
2028+ dynarray_reset(&pe.sec_info, &pe.sec_count);
19992029 } else {
20002030 #ifdef TCC_IS_NATIVE
20012031 pe.thunk = data_section;
tccpp.c+9−8
@@ -109,9 +109,7 @@ ST_FUNC void expect(const char *msg) · 108 unmodified lines
109109 /* ------------------------------------------------------------------------- */
110110 /* Custom allocator for tiny objects */
111111
112−#ifndef __BOUNDS_CHECKING_ON
113112 #define USE_TAL
114−#endif
115113
116114 #ifndef USE_TAL
117115 #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_ · 132 unmodified lines
250248 tail_call:
251249 is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
252250 if ((!p || is_own) && size <= al->limit) {
253− if (al->p + adj_size + sizeof(tal_header_t) < al->buffer + al->size) {
251+ if (al->p - al->buffer + adj_size + sizeof(tal_header_t) < al->size) {
254252 header = (tal_header_t *)al->p;
255253 header->size = adj_size;
256254 #ifdef TAL_DEBUG
@@ -1958,7 +1956,11 @@ include_done: · 1701 unmodified lines
19581956 if (tok == TOK_STR) {
19591957 if (file->true_filename == file->filename)
19601958 file->true_filename = tcc_strdup(file->filename);
1961− tcc_debug_putfile(s1, (char *)tokc.str.data);
1959+ /* prepend directory from real file */
1960+ pstrcpy(buf, sizeof buf, file->true_filename);
1961+ *tcc_basename(buf) = 0;
1962+ pstrcat(buf, sizeof buf, (char *)tokc.str.data);
1963+ tcc_debug_putfile(s1, buf);
19621964 } else if (parse_flags & PARSE_FLAG_ASM_FILE)
19631965 break;
19641966 else
@@ -3529,9 +3531,6 @@ no_subst: · 1564 unmodified lines
35293531 /* return next token with macro substitution */
35303532 ST_FUNC void next(void)
35313533 {
3532− /* generate line number info */
3533− if (tcc_state->do_debug)
3534− tcc_debug_line(tcc_state);
35353534 redo:
35363535 if (parse_flags & PARSE_FLAG_SPACES)
35373536 next_nomacro_spc();
@@ -3607,6 +3606,8 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm) · 69 unmodified lines
36073606 cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
36083607 if (is_asm)
36093608 cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
3609+ if (s1->output_type == TCC_OUTPUT_MEMORY)
3610+ cstr_printf(&cstr, "#define __TCC_RUN__ 1\n");
36103611 if (s1->cmdline_incl.size)
36113612 cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
36123613 //printf("%s\n", (char*)cstr.data);
@@ -3657,7 +3658,7 @@ ST_FUNC void tccpp_new(TCCState *s) · 44 unmodified lines
36573658 cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
36583659 tok_str_new(&tokstr_buf);
36593660 tok_str_realloc(&tokstr_buf, TOKSTR_MAX_SIZE);
3660−
3661+
36613662 tok_ident = TOK_IDENT;
36623663 p = tcc_keywords;
36633664 while (*p) {
tccrun.c+188−149
@@ -23,27 +23,36 @@ · 22 unmodified lines
2323 /* only native compiler supports -run */
2424 #ifdef TCC_IS_NATIVE
2525
26−#ifndef _WIN32
27−# include <sys/mman.h>
28−#endif
29−
3026 #ifdef CONFIG_TCC_BACKTRACE
31−static void set_exception_handler(void);
32−#ifdef _WIN32
33−static DWORD s1_for_run_idx;
34−void set_s1_for_run(TCCState *s)
27+typedef struct rt_context
3528 {
36− if (!s1_for_run_idx)
37− s1_for_run_idx = TlsAlloc();
38− TlsSetValue(s1_for_run_idx, s);
39−}
40−#define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx))
41−#else
42−/* XXX: add tls support for linux */
43−static TCCState *s1_for_run;
44−#define set_s1_for_run(s) (s1_for_run = s)
45−#define get_s1_for_run() s1_for_run
46−#endif
29+ /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
30+ Stab_Sym *stab_sym, *stab_sym_end;
31+ char *stab_str;
32+ ElfW(Sym) *esym_start, *esym_end;
33+ char *elf_str;
34+ addr_t prog_base;
35+ void *bounds_start;
36+ struct rt_context *next;
37+ /* <-- */
38+ int num_callers;
39+ addr_t ip, fp, sp;
40+ void *top_func;
41+ jmp_buf jmp_buf;
42+ char do_jmp;
43+} rt_context;
44+
45+static rt_context g_rtctxt;
46+static void set_exception_handler(void);
47+static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
48+static void rt_exit(int code);
49+#endif /* CONFIG_TCC_BACKTRACE */
50+
51+/* defined when included from lib/bt.c */
52+#ifndef CONFIG_TCC_BACKTRACE_ONLY
53+
54+#ifndef _WIN32
55+# include <sys/mman.h>
4756 #endif
4857
4958 static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
@@ -113,72 +122,73 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 63 unmodified lines
113122 #endif
114123 }
115124 tcc_free(s1->runtime_mem);
116− if (get_s1_for_run() == s1)
117− set_s1_for_run(NULL);
125+}
126+
127+static void run_cdtors(TCCState *s1, const char *start, const char *end)
128+{
129+ void **a = tcc_get_symbol(s1, start);
130+ void **b = tcc_get_symbol(s1, end);
131+ while (a != b)
132+ ((void(*)(void))*a++)();
118133 }
119134
120135 /* launch the compiled program with the given arguments */
121136 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
122137 {
123−/* PE target overwrites runtime_main */
124−#ifndef TCC_TARGET_PE
125− typedef void (*init_array_func)(int, char **, char **);
126− typedef void (*fini_array_func)(void);
127− init_array_func *__init_array_start;
128− init_array_func *__init_array_end;
129− fini_array_func *__fini_array_start;
130− fini_array_func *__fini_array_end;
138+ int (*prog_main)(int, char **), ret;
139+#ifdef CONFIG_TCC_BACKTRACE
140+ rt_context *rc = &g_rtctxt;
131141 #endif
132− int i;
133− int ret;
134− int (*prog_main)(int, char **);
135142
136143 s1->runtime_main = s1->nostdlib ? "_start" : "main";
137144 if ((s1->dflag & 16) && !find_elf_sym(s1->symtab, s1->runtime_main))
138145 return 0;
146+#ifdef CONFIG_TCC_BACKTRACE
147+ if (s1->do_debug)
148+ tcc_add_symbol(s1, "exit", rt_exit);
149+#endif
139150 if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
140151 return -1;
141152 prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
142153
143154 #ifdef CONFIG_TCC_BACKTRACE
155+ memset(rc, 0, sizeof *rc);
144156 if (s1->do_debug) {
157+ void *p;
158+ rc->stab_sym = (Stab_Sym *)stab_section->data;
159+ rc->stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
160+ rc->stab_str = (char *)stab_section->link->data;
161+ rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
162+ rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
163+ rc->elf_str = (char *)symtab_section->link->data;
164+ rc->top_func = tcc_get_symbol(s1, "main");
165+ rc->num_callers = s1->rt_num_callers;
166+ rc->do_jmp = 1;
167+ if ((p = tcc_get_symbol(s1, "__rt_error")))
168+ *(void**)p = _rt_error;
169+#ifdef CONFIG_TCC_BCHECK
170+ if (s1->do_bounds_check) {
171+ if ((p = tcc_get_symbol(s1, "__bound_init")))
172+ ((void(*)(void*))p)(bounds_section->data);
173+ }
174+#endif
145175 set_exception_handler();
146− s1->rt_prog_main = prog_main;
147− /* set global state pointer for exception handlers*/
148− set_s1_for_run(s1);
149176 }
150177 #endif
151178
152179 errno = 0; /* clean errno value */
153−
154−#ifdef CONFIG_TCC_BCHECK
155− if (s1->do_bounds_check)
156− /* set error function */
157− s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
158−#endif
159−
160−#ifndef TCC_TARGET_PE
161− __init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
162− __init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
163− __fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
164− __fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
165−
166− if (__init_array_start && __init_array_end) {
167− i = 0;
168− while (&__init_array_start[i] != __init_array_end)
169− (*__init_array_start[i++])(argc, argv, environ);
170− }
180+ fflush(stdout);
181+ fflush(stderr);
182+ run_cdtors(s1, "__init_array_start", "__init_array_end");
183+#ifdef CONFIG_TCC_BACKTRACE
184+ if (!rc->do_jmp || !(ret = setjmp(rc->jmp_buf)))
171185 #endif
172−
173− ret = (*prog_main)(argc, argv);
174−
175−#ifndef TCC_TARGET_PE
176− if (__fini_array_start && __fini_array_end) {
177− i = 0;
178− while (&__fini_array_end[i] != __fini_array_start)
179− (*__fini_array_end[--i])();
186+ {
187+ ret = prog_main(argc, argv);
180188 }
181−#endif
189+ run_cdtors(s1, "__fini_array_start", "__fini_array_end");
190+ if ((s1->dflag & 16) && ret)
191+ fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
182192 return ret;
183193 }
184194
@@ -336,11 +346,10 @@ static void win64_del_function_table(void *p) · 151 unmodified lines
336346 }
337347 }
338348 #endif
339−
349+#endif //ndef CONFIG_TCC_BACKTRACE_ONLY
340350 /* ------------------------------------------------------------- */
341351 #ifdef CONFIG_TCC_BACKTRACE
342352
343−#define INCLUDE_STACK_SIZE 32
344353 static int rt_vprintf(const char *fmt, va_list ap)
345354 {
346355 int ret = vfprintf(stderr, fmt, ap);
@@ -358,21 +367,22 @@ static int rt_printf(const char *fmt, ...) · 11 unmodified lines
358367 return r;
359368 }
360369
370+#define INCLUDE_STACK_SIZE 32
371+
361372 /* print the position in the source file of PC value 'pc' by reading
362373 the stabs debug information */
363−static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
374+static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
375+ const char *msg, const char *skip)
364376 {
365377 char func_name[128];
366378 addr_t func_addr, last_pc, pc;
367379 const char *incl_files[INCLUDE_STACK_SIZE];
368380 int incl_index, last_incl_index, len, last_line_num, i;
369381 const char *str, *p;
382+ ElfW(Sym) *esym;
383+ Stab_Sym *sym;
370384
371− ElfW(Sym) *esym_start = NULL, *esym_end = NULL, *esym;
372− Stab_Sym *stab_sym = NULL, *stab_sym_end = NULL, *sym;
373− char *stab_str = NULL;
374− char *elf_str = NULL;
375−
385+next:
376386 func_name[0] = '\0';
377387 func_addr = 0;
378388 incl_index = 0;
@@ -380,19 +390,8 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) · 1 unmodified line
380390 last_line_num = 1;
381391 last_incl_index = 0;
382392
383− if (stab_section) {
384− stab_sym = (Stab_Sym *)stab_section->data;
385− stab_sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset);
386− stab_str = (char *) stab_section->link->data;
387− }
388− if (symtab_section) {
389− esym_start = (ElfW(Sym) *)(symtab_section->data);
390− esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
391− elf_str = (char *) symtab_section->link->data;
392− }
393−
394− for (sym = stab_sym + 1; sym < stab_sym_end; ++sym) {
395− str = stab_str + sym->n_strx;
393+ for (sym = rc->stab_sym + 1; sym < rc->stab_sym_end; ++sym) {
394+ str = rc->stab_str + sym->n_strx;
396395 pc = sym->n_value;
397396
398397 switch(sym->n_type) {
@@ -406,16 +405,18 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) · 7 unmodified lines
406405 if (sym->n_strx == 0) /* end of function */
407406 goto rel_pc;
408407 abs_pc:
409− if (sizeof pc == 8)
408+ if (sizeof sym->n_value < PTR_SIZE) {
410409 /* Stab_Sym.n_value is only 32bits */
411− pc |= wanted_pc & 0xffffffff00000000ULL;
410+ //fprintf(stderr, "pc = %p %p %p\n", pc, rc->prog_base, wanted_pc), fflush(stderr);
411+ pc += rc->prog_base;
412+ }
412413 break;
413414 rel_pc:
414415 pc += func_addr;
415416 break;
416417 }
417418
418− if (pc > wanted_pc && wanted_pc > last_pc)
419+ if (pc >= wanted_pc && wanted_pc >= last_pc)
419420 goto found;
420421
421422 switch(sym->n_type) {
@@ -434,8 +435,6 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) · 12 unmodified lines
434435 last_pc = pc;
435436 last_line_num = sym->n_desc;
436437 last_incl_index = incl_index;
437− if (pc == wanted_pc)
438− goto found;
439438 break;
440439 /* include files */
441440 case N_BINCL:
@@ -468,31 +467,38 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) · 26 unmodified lines
468467 }
469468 }
470469
470+ func_name[0] = '\0';
471+ func_addr = 0;
472+ last_incl_index = 0;
473+
471474 /* we try symtab symbols (no line number info) */
472− for (esym = esym_start + 1; esym < esym_end; ++esym) {
475+ for (esym = rc->esym_start + 1; esym < rc->esym_end; ++esym) {
473476 int type = ELFW(ST_TYPE)(esym->st_info);
474477 if (type == STT_FUNC || type == STT_GNU_IFUNC) {
475478 if (wanted_pc >= esym->st_value &&
476479 wanted_pc < esym->st_value + esym->st_size) {
477480 pstrcpy(func_name, sizeof(func_name),
478− elf_str + esym->st_name);
481+ rc->elf_str + esym->st_name);
479482 func_addr = esym->st_value;
480− last_incl_index = 0;
481483 goto found;
482484 }
483485 }
484486 }
485− /* did not find any info: */
486− rt_printf("%s %p ???", msg, (void*)wanted_pc);
487− return 0;
488487
489− found:
488+ if ((rc = rc->next))
489+ goto next;
490+
491+found:
490492 i = last_incl_index;
491− if (i > 0)
492− rt_printf("%s:%d: ", incl_files[--i], last_line_num);
493− rt_printf("%s %p", msg, (void*)wanted_pc);
494− if (func_name[0] != '\0')
495− rt_printf(" %s()", func_name);
493+ if (i > 0) {
494+ str = incl_files[--i];
495+ if (skip[0] && strstr(str, skip))
496+ return (addr_t)-1;
497+ rt_printf("%s:%d: ", str, last_line_num);
498+ } else
499+ rt_printf("%08llx : ", (long long)wanted_pc);
500+ rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
501+#if 0
496502 if (--i >= 0) {
497503 rt_printf(" (included from ");
498504 for (;;) {
@@ -503,48 +509,79 @@ static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg) · 4 unmodified lines
503509 }
504510 rt_printf(")");
505511 }
512+#endif
506513 return func_addr;
507514 }
508515
509−typedef struct rt_context {
510− addr_t ip, fp, sp, pc;
511−} rt_context;
512−
513516 static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level);
514517
515−/* emit a run time error at position 'pc' */
516−static void rt_error(rt_context *rc, const char *fmt, ...)
518+static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap)
517519 {
518− va_list ap;
519− addr_t pc;
520− int i;
521− TCCState *s1;
522−
523− s1 = get_s1_for_run();
524− if (*fmt == ' ') {
525− if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
526− fmt = *s1->rt_bound_error_msg;
527− else
528− ++fmt;
520+ rt_context *rc = &g_rtctxt;
521+ addr_t pc = 0;
522+ char skip[100];
523+ int i, level, ret, n;
524+ const char *a, *b, *msg;
525+
526+ if (fp) {
527+ /* we're called from tcc_backtrace. */
528+ rc->fp = (addr_t)fp;
529+ rc->ip = (addr_t)ip;
530+ msg = "";
531+ } else {
532+ /* we're called from signal/exception handler */
533+ msg = "RUNTIME ERROR: ";
529534 }
530535
531− rt_printf("Runtime error: ");
532− va_start(ap, fmt);
533− rt_vprintf(fmt, ap);
534− va_end(ap);
535− rt_printf("\n");
536−
537− if (!s1)
538− return;
536+ skip[0] = 0;
537+ /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
538+ if (fmt[0] == '^' && (b = strchr(a = fmt + 1, fmt[0]))) {
539+ memcpy(skip, a, b - a), skip[b - a] = 0;
540+ fmt = b + 1;
541+ }
539542
540− for(i=0; i<s1->rt_num_callers; i++) {
541− if (rt_get_caller_pc(&pc, rc, i) < 0)
543+ n = rc->num_callers ? rc->num_callers : 6;
544+ for (i = level = 0; level < n; i++) {
545+ ret = rt_get_caller_pc(&pc, rc, i);
546+ a = "%s";
547+ if (ret != -1) {
548+ pc = rt_printline(rc, pc, level ? "by" : "at", skip);
549+ if (pc == (addr_t)-1)
550+ continue;
551+ a = ": %s";
552+ }
553+ if (level == 0) {
554+ rt_printf(a, msg);
555+ rt_vprintf(fmt, ap);
556+ } else if (ret == -1)
542557 break;
543− pc = rt_printline(s1, pc, i ? "by" : "at");
544558 rt_printf("\n");
545− if (pc == (addr_t)s1->rt_prog_main && pc)
559+ if (ret == -1 || (pc == (addr_t)rc->top_func && pc))
546560 break;
561+ ++level;
547562 }
563+
564+ rc->ip = rc->fp = 0;
565+ return 0;
566+}
567+
568+/* emit a run time error at position 'pc' */
569+static int rt_error(const char *fmt, ...)
570+{
571+ va_list ap;
572+ int ret;
573+ va_start(ap, fmt);
574+ ret = _rt_error(0, 0, fmt, ap);
575+ va_end(ap);
576+ return ret;
577+}
578+
579+static void rt_exit(int code)
580+{
581+ rt_context *rc = &g_rtctxt;
582+ if (rc->do_jmp)
583+ longjmp(rc->jmp_buf, code ? code : 256);
584+ exit(code);
548585 }
549586
550587 /* ------------------------------------------------------------- */
@@ -621,36 +658,36 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc) · 70 unmodified lines
621658 /* signal handler for fatal errors */
622659 static void sig_error(int signum, siginfo_t *siginf, void *puc)
623660 {
624− rt_context rc;
661+ rt_context *rc = &g_rtctxt;
662+ rt_getcontext(puc, rc);
625663
626− rt_getcontext(puc, &rc);
627664 switch(signum) {
628665 case SIGFPE:
629666 switch(siginf->si_code) {
630667 case FPE_INTDIV:
631668 case FPE_FLTDIV:
632− rt_error(&rc, "division by zero");
669+ rt_error("division by zero");
633670 break;
634671 default:
635− rt_error(&rc, "floating point exception");
672+ rt_error("floating point exception");
636673 break;
637674 }
638675 break;
639676 case SIGBUS:
640677 case SIGSEGV:
641− rt_error(&rc, " dereferencing invalid pointer");
678+ rt_error("invalid memory access");
642679 break;
643680 case SIGILL:
644− rt_error(&rc, "illegal instruction");
681+ rt_error("illegal instruction");
645682 break;
646683 case SIGABRT:
647− rt_error(&rc, "abort() called");
684+ rt_error("abort() called");
648685 break;
649686 default:
650− rt_error(&rc, "caught signal %d", signum);
687+ rt_error("caught signal %d", signum);
651688 break;
652689 }
653− exit(255);
690+ rt_exit(255);
654691 }
655692
656693 #ifndef SA_SIGINFO
@@ -664,7 +701,7 @@ static void set_exception_handler(void) · 7 unmodified lines
664701 /* install TCC signal handlers to print debug info on fatal
665702 runtime errors */
666703 sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
667−#ifdef SIGSTKSZ
704+#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
668705 sigact.sa_flags |= SA_ONSTACK;
669706 #endif
670707 sigact.sa_sigaction = sig_error;
@@ -674,7 +711,7 @@ static void set_exception_handler(void) · 3 unmodified lines
674711 sigaction(SIGSEGV, &sigact, NULL);
675712 sigaction(SIGBUS, &sigact, NULL);
676713 sigaction(SIGABRT, &sigact, NULL);
677−#ifdef SIGSTKSZ
714+#if 0//def SIGSTKSZ
678715 /* This allows stack overflow to be reported instead of a SEGV */
679716 {
680717 stack_t ss;
@@ -689,32 +726,35 @@ static void set_exception_handler(void) · 8 unmodified lines
689726 }
690727
691728 #else /* WIN32 */
729+
692730 /* signal handler for fatal errors */
693731 static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
694732 {
695− rt_context rc;
733+ rt_context *rc = &g_rtctxt;
696734 unsigned code;
735+ rt_getcontext(ex_info->ContextRecord, rc);
697736
698− rt_getcontext(ex_info->ContextRecord, &rc);
699737 switch (code = ex_info->ExceptionRecord->ExceptionCode) {
700738 case EXCEPTION_ACCESS_VIOLATION:
701− rt_error(&rc, " access violation");
739+ rt_error("invalid memory access");
702740 break;
703741 case EXCEPTION_STACK_OVERFLOW:
704− rt_error(&rc, "stack overflow");
742+ rt_error("stack overflow");
705743 break;
706744 case EXCEPTION_INT_DIVIDE_BY_ZERO:
707− rt_error(&rc, "division by zero");
745+ rt_error("division by zero");
708746 break;
709747 case EXCEPTION_BREAKPOINT:
710748 case EXCEPTION_SINGLE_STEP:
711− rc.ip = *(addr_t*)rc.sp;
712− rt_error(&rc, "^breakpoint/single-step exception:");
749+ rc->ip = *(addr_t*)rc->sp;
750+ rt_error("breakpoint/single-step exception:");
713751 return EXCEPTION_CONTINUE_SEARCH;
714752 default:
715− rt_error(&rc, "caught exception %08x", code);
753+ rt_error("caught exception %08x", code);
716754 break;
717755 }
756+ if (rc->do_jmp)
757+ rt_exit(255);
718758 return EXCEPTION_EXECUTE_HANDLER;
719759 }
720760
@@ -807,7 +847,6 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level) · 86 unmodified lines
807847
808848 #endif
809849 #endif /* CONFIG_TCC_BACKTRACE */
810−
811850 /* ------------------------------------------------------------- */
812851 #ifdef CONFIG_TCC_STATIC
813852
tests/Makefile+23−23
@@ -73,6 +73,7 @@ endif · 72 unmodified lines
7373 RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
7474 DISAS = objdump -d
7575 DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
76+Q = # >/dev/null 2>&1
7677
7778 all test :
7879 $(MAKE) clean-s
@@ -88,7 +89,7 @@ hello-run: ../examples/ex1.c · 9 unmodified lines
8889
8990 libtes%: libtcc_tes%$(EXESUF)
9091 @echo ------------ $@ ------------
91− ./libtcc_tes$*$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES)
92+ ./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES)
9293
9394 libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC)
9495 $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
@@ -105,22 +106,24 @@ test.ref: tcctest.c · 10 unmodified lines
105106 # auto test
106107 test1 test1b: tcctest.c test.ref
107108 @echo ------------ $@ ------------
108− $(TCC) -run $< > test.out1
109− @diff -u test.ref test.out1 && echo "Auto Test OK"
109+ $(TCC) -w -run $< > test.out1 $Q
110+ @diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
110111
111112 # iterated test2 (compile tcc then compile tcctest.c !)
112113 test2 test2b: tcctest.c test.ref
113114 @echo ------------ $@ ------------
114− $(TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out2
115− @diff -u test.ref test.out2 && echo "Auto Test2 OK"
115+ $(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2 $Q
116+ @diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
116117
117118 # iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
118119 test3 test3b: tcctest.c test.ref
119120 @echo ------------ $@ ------------
120− $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
121− @diff -u test.ref test.out3 && echo "Auto Test3 OK"
121+ $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3 $Q
122+ @diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
122123
123−test%b : TCCFLAGS += -b
124+AUTO_TEST = Auto Test
125+test%b : TCCFLAGS += -b -bt1
126+test%b : AUTO_TEST = Auto Bound-Test
124127
125128 # binary output test
126129 test4: tcctest.c test.ref
@@ -129,21 +132,21 @@ test4: tcctest.c test.ref · 2 unmodified lines
129132 $(TCC) -c -o tcctest3.o $<
130133 $(TCC) -o tcctest3 tcctest3.o
131134 ./tcctest3 > test3.out
132− @if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
135+ @if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
133136 # dynamic output
134137 $(TCC) -o tcctest1 $<
135138 ./tcctest1 > test1.out
136− @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
139+ @if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
137140 # dynamic output + bound check
138141 $(TCC) -b -o tcctest4 $<
139142 ./tcctest4 > test4.out
140− @if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
143+ @if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
141144
142145 test4_static: tcctest.c test.ref
143146 # static output.
144147 $(TCC) -static -o tcctest2 $<
145148 ./tcctest2 > test2.out
146− @if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
149+ @if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
147150
148151 # use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
149152 dlltest:
@@ -164,32 +167,29 @@ memtest: · 14 unmodified lines
164167 @echo ------------ $@ ------------
165168 $(CC) $(CFLAGS) $(NATIVE_DEFINES) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
166169 ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) $(TOPSRC)/tcc.c $(LIBS)
167− ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) $(TOPSRC)/tests/tcctest.c
168−
170+ ./memtest-tcc$(EXESUF) $(TCCFLAGS) $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
169171
170172 # memory and bound check auto test
171−BOUNDS_OK = 1 4 8 10 14 16 18
173+BOUNDS_OK = 1 4 8 10 14 16
172174 BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
173175
174176 btest: boundtest.c
175177 @echo ------------ $@ ------------
176178 @for i in $(BOUNDS_OK); do \
177− echo ; echo --- boundtest $$i ---; \
178179 if $(TCC) -b -run $< $$i ; then \
179− echo succeeded as expected; \
180+ echo "- Test $$i succeeded as expected" ; \
180181 else\
181− echo Failed positive test $$i ; exit 1 ; \
182+ echo "- Failed positive test $$i" ; exit 1 ; \
182183 fi ;\
183184 done ;\
184185 for i in $(BOUNDS_FAIL); do \
185− echo ; echo --- boundtest $$i ---; \
186− if $(TCC) -b -run $< $$i ; then \
187− echo Failed negative test $$i ; exit 1 ;\
186+ if $(TCC) -b -bt1 -run $< $$i ; then \
187+ echo "- Failed negative test $$i" ; exit 1 ;\
188188 else\
189− echo failed as expected; \
189+ echo "- Test $$i failed as expected" ; \
190190 fi ;\
191191 done ;\
192− echo; echo Bound test OK
192+ echo Bound test OK
193193
194194 # speed test
195195 speedtest: ex2 ex3
tests/boundtest.c+3−214
@@ -50,15 +50,12 @@ int test4(void) · 49 unmodified lines
5050 int i, sum = 0;
5151 int *tab4;
5252
53− fprintf(stderr, "%s start\n", __FUNCTION__);
54−
5553 tab4 = malloc(20 * sizeof(int));
5654 for(i=0;i<20;i++) {
5755 sum += tab4[i];
5856 }
5957 free(tab4);
6058
61− fprintf(stderr, "%s end\n", __FUNCTION__);
6259 return sum;
6360 }
6461
@@ -68,15 +65,12 @@ int test5(void) · 3 unmodified lines
6865 int i, sum = 0;
6966 int *tab4;
7067
71− fprintf(stderr, "%s start\n", __FUNCTION__);
72−
7368 tab4 = malloc(20 * sizeof(int));
7469 for(i=0;i<21;i++) {
7570 sum += tab4[i];
7671 }
7772 free(tab4);
7873
79− fprintf(stderr, "%s end\n", __FUNCTION__);
8074 return sum;
8175 }
8276
@@ -198,16 +192,12 @@ int test16() · 115 unmodified lines
198192 char *demo = "This is only a test.";
199193 char *p;
200194
201− fprintf(stderr, "%s start\n", __FUNCTION__);
202−
203195 p = alloca(16);
204196 strcpy(p,"12345678901234");
205− printf("alloca: p is %s\n", p);
206197
207198 /* Test alloca embedded in a larger expression */
208− printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
199+ printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
209200
210− fprintf(stderr, "%s end\n", __FUNCTION__);
211201 return 0;
212202 }
213203
@@ -217,211 +207,11 @@ int test17() · 3 unmodified lines
217207 char *demo = "This is only a test.";
218208 char *p;
219209
220− fprintf(stderr, "%s start\n", __FUNCTION__);
221−
222210 p = alloca(16);
223211 strcpy(p,"12345678901234");
224− printf("alloca: p is %s\n", p);
225212
226213 /* Test alloca embedded in a larger expression */
227− printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
228−
229− fprintf(stderr, "%s end\n", __FUNCTION__);
230− return 0;
231−}
232−
233−#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
234−
235−extern void __bound_never_fatal (int neverfatal);
236−extern const char *__bound_error_msg;
237−
238−static void init18(char *a, char *b)
239−{
240− memset (a, 'a', 10);
241− a[3] = 0;
242− a[9] = 0;
243− memset (b, 'b', 10);
244− __bound_error_msg = "";
245−}
246−
247−/* ok (catch all errors) */
248−int test18()
249−{
250− char pad1[10];
251− char a[10];
252− char pad2[10];
253− char b[10];
254− char pad3[10];
255−
256− memset (pad1, 0, sizeof(pad1));
257− memset (pad2, 0, sizeof(pad2));
258− memset (pad3, 0, sizeof(pad3));
259−
260− /* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
261− __bound_never_fatal (-2);
262−
263− /* memcpy */
264− init18(a,b);
265− memcpy(&a[1],&b[0],10);
266− CHECK("memcpy dest");
267− init18(a,b);
268− memcpy(&a[0],&b[1],10);
269− CHECK("memcpy src");
270− init18(a,b);
271− memcpy(&a[0],&a[3],4);
272− CHECK("overlapping regions");
273− init18(a,b);
274− memcpy(&a[3],&a[0],4);
275− CHECK("overlapping regions");
276−
277− /* memcmp */
278− init18(a,b);
279− memcmp(&b[1],&b[0],10);
280− CHECK("memcmp s1");
281− init18(a,b);
282− memcmp(&b[0],&b[1],10);
283− CHECK("memcmp s2");
284−
285− /* memmove */
286− init18(a,b);
287− memmove(&b[1],&b[0],10);
288− CHECK("memmove dest");
289− init18(a,b);
290− memmove(&b[0],&b[1],10);
291− CHECK("memmove src");
292−
293− /* memset */
294− init18(a,b);
295− memset(&b[1],'b',10);
296− CHECK("memset");
297−
298− /* strlen */
299− init18(a,b);
300− strlen(&b[0]);
301− CHECK("strlen");
302−
303− /* strcpy */
304− init18(a,b);
305− strcpy(&a[7], &a[0]);
306− CHECK("strcpy dest");
307− init18(a,b);
308− strcpy(&a[0], &b[7]);
309− CHECK("strcpy src");
310− init18(a,b);
311− strcpy(&a[0], &a[1]);
312− CHECK("overlapping regions");
313− init18(a,b);
314− strcpy(&a[2], &a[0]);
315− CHECK("overlapping regions");
316−
317− /* strncpy */
318− init18(a,b);
319− strncpy(&a[7], &a[0], 10);
320− CHECK("strncpy dest");
321− init18(a,b);
322− strncpy(&a[0], &b[7], 10);
323− CHECK("strncpy src");
324− init18(a,b);
325− strncpy(&a[0], &a[1], 10);
326− CHECK("overlapping regions");
327− strncpy(&a[2], &a[0], 10);
328− CHECK("overlapping regions");
329−
330− /* strcmp */
331− init18(a,b);
332− strcmp(&b[2], &b[0]);
333− CHECK("strcmp s1");
334− init18(a,b);
335− strcmp(&b[0], &b[2]);
336− CHECK("strcmp s2");
337−
338− /* strncmp */
339− init18(a,b);
340− strncmp(&b[5], &b[0], 10);
341− CHECK("strncmp s1");
342− init18(a,b);
343− strncmp(&b[0], &b[5], 10);
344− CHECK("strncmp s2");
345−
346− /* strcat */
347− init18(a,b);
348− strcat(&a[7], &a[0]);
349− CHECK("strcat dest");
350− init18(a,b);
351− strcat(&a[0], &b[5]);
352− CHECK("strcat src");
353− init18(a,b);
354− strcat(&a[0], &a[4]);
355− CHECK("overlapping regions");
356− init18(a,b);
357− strcat(&a[3], &a[0]);
358− CHECK("overlapping regions");
359−
360− /* strchr */
361− init18(a,b);
362− strchr(&b[0], 'a');
363− CHECK("strchr");
364−
365− /* strdup */
366− init18(a,b);
367− free(strdup(&b[0]));
368− CHECK("strdup");
369−
370− __bound_never_fatal (2);
371−
372− /* memcpy */
373− init18(a,b);
374− memcpy(&a[0],&b[0],10);
375− init18(a,b);
376− memcpy(&a[0],&a[3],3);
377− init18(a,b);
378− memcpy(&a[3],&a[0],3);
379−
380− /* memcmp */
381− init18(a,b);
382− memcmp(&b[0],&b[0],10);
383−
384− /* memmove */
385− init18(a,b);
386− memmove(&b[0],&b[5],5);
387− init18(a,b);
388− memmove(&b[5],&b[0],5);
389−
390− /* memset */
391− init18(a,b);
392− memset(&b[0],'b',10);
393−
394− /* strlen */
395− init18(a,b);
396− strlen (&a[0]);
397−
398− /* strcpy */
399− init18(a,b);
400− strcpy (&a[0], &a[7]);
401−
402− /* strncpy */
403− init18(a,b);
404− strncpy (&a[0], &a[7], 4);
405−
406− /* strcmp */
407− init18(a,b);
408− strcmp (&a[0], &a[4]);
409−
410− /* strncmp */
411− init18(a,b);
412− strncmp (&a[0], &a[4], 10);
413−
414− /* strcat */
415− init18(a,b);
416− strcat (&a[0], &a[7]);
417−
418− /* strchr */
419− init18(a,b);
420− strchr (&a[0], 0);
421−
422− /* strdup */
423− init18(a,b);
424− free (strdup (&a[0]));
214+ printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
425215
426216 return 0;
427217 }
@@ -443,8 +233,7 @@ int (*table_test[])(void) = { · 15 unmodified lines
443233 test14,
444234 test15,
445235 test16,
446− test17,
447− test18,
236+ test17
448237 };
449238
450239 int main(int argc, char **argv)
tests/libtcc_test_mt.c+12−9
@@ -203,14 +203,11 @@ TF_TYPE(thread_test_complex, vn) · 202 unmodified lines
203203
204204 sprintf(b, "%d", F(n));
205205
206− argv[argc++] = "../tcc.c";
207206 for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
208207 #if 0
209208 argv[argc++] = "-run";
210− argv[argc++] = "../tcc.c";
211209 for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
212210 #endif
213− argv[argc++] = "-g";
214211 argv[argc++] = "-DFIB";
215212 argv[argc++] = "-run";
216213 argv[argc++] = __FILE__;
@@ -221,23 +218,24 @@ TF_TYPE(thread_test_complex, vn) · 4 unmodified lines
221218 sleep_ms(2);
222219 ret = tcc_add_file(s, argv[0]);
223220 sleep_ms(3);
224− if (ret >= 0)
225− tcc_run(s, argc, argv);
221+ if (ret < 0)
222+ exit(1);
223+ tcc_run(s, argc, argv);
226224 tcc_delete(s);
227225 fflush(stdout);
228226 return 0;
229227 }
230228
231−void time_tcc(int n)
229+void time_tcc(int n, const char *src)
232230 {
233231 TCCState *s;
234232 int ret;
235233 while (--n >= 0) {
236234 s = new_state(1);
237− ret = tcc_add_file(s, "../tcc.c");
235+ ret = tcc_add_file(s, src);
238236 tcc_delete(s);
239237 if (ret < 0)
240− break;
238+ exit(1);
241239 }
242240 }
243241
@@ -260,6 +258,11 @@ int main(int argc, char **argv) · 16 unmodified lines
260258 g_argc = argc;
261259 g_argv = argv;
262260
261+ if (argc < 2) {
262+ fprintf(stderr, "usage: libtcc_test_mt tcc.c <options>\n");
263+ return 1;
264+ }
265+
263266 #if 1
264267 printf("----- libtest : mixed calls -------\n"), fflush(stdout);
265268 t = getclock_ms();
@@ -285,7 +288,7 @@ int main(int argc, char **argv) · 19 unmodified lines
285288 #if 1
286289 printf("----- compilation of tcc -----------\n"), fflush(stdout);
287290 t = getclock_ms();
288− time_tcc(10);
291+ time_tcc(10, argv[1]);
289292 printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
290293 #endif
291294 return 0;
tests/tcctest.c+15−9
@@ -1725,10 +1725,6 @@ void cast_test() · 1724 unmodified lines
17251725 printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
17261726 printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
17271727
1728−#ifdef __TINYC__
1729−# pragma comment(option, "-w")
1730−#endif
1731−
17321728 /* from pointer to integer types */
17331729 printf("%d %d %ld %ld %lld %lld\n",
17341730 (int)p, (unsigned int)p,
@@ -1739,10 +1735,6 @@ void cast_test() · 4 unmodified lines
17391735 printf("%p %p %p %p\n",
17401736 (void *)a, (void *)b, (void *)c, (void *)d);
17411737
1742−#ifdef __TINYC__
1743−# pragma comment(option, "-W")
1744−#endif
1745−
17461738 /* int to int with sign set */
17471739 printf("0x%lx\n", (unsigned long)(int)ul);
17481740 }
@@ -3406,7 +3398,7 @@ void clobber_r12(void) · 1657 unmodified lines
34063398 }
34073399 #endif
34083400
3409−void test_high_clobbers(void)
3401+void test_high_clobbers_really(void)
34103402 {
34113403 #if defined __x86_64__ && !defined _WIN64
34123404 register long val asm("r12");
@@ -3422,6 +3414,20 @@ void test_high_clobbers(void) · 9 unmodified lines
34223414 #endif
34233415 }
34243416
3417+void test_high_clobbers(void)
3418+{
3419+#if defined __x86_64__ && !defined _WIN64
3420+ long x1, x2;
3421+ asm volatile("mov %%r12,%0" :: "m" (x1)); /* save r12 */
3422+ test_high_clobbers_really();
3423+ asm volatile("mov %%r12,%0" :: "m" (x2)); /* new r12 */
3424+ asm volatile("mov %0,%%r12" :: "m" (x1)); /* restore r12 */
3425+ /* should be 0 but tcc doesn't save r12 automatically, which has
3426+ bad effects when gcc helds TCCState *s in r12 in tcc.c:main */
3427+ //printf("r12-clobber-diff: %lx\n", x2 - x1);
3428+#endif
3429+}
3430+
34253431 static long cpu_number;
34263432 void trace_console(long len, long len2)
34273433 {
tests/tests2/112_backtrace.c+165−0
@@ -0,0 +1,165 @@
1+#include <stdio.h>
2+
3+/* ------------------------------------------------------- */
4+#if defined test_backtrace_1
5+
6+void f3()
7+{
8+ printf("* f3()\n"), fflush(stdout);
9+ *(void**)0 = 0;
10+}
11+void f2()
12+{
13+ printf("* f2()\n"), fflush(stdout);
14+ f3();
15+}
16+void f1()
17+{
18+ printf("* f1()\n"), fflush(stdout);
19+ f2();
20+}
21+int main(int argc, char **argv)
22+{
23+ printf("* main\n"), fflush(stdout);
24+ f1();
25+ printf("* exit main\n"), fflush(stdout);
26+ return 0;
27+}
28+
29+/* ------------------------------------------------------- */
30+#elif defined test_bcheck_1
31+
32+struct s { int a,b,c,d,e; };
33+struct s s[3];
34+struct s *ps = s;
35+void f1()
36+{
37+ printf("* f1()\n"), fflush(stdout);
38+ ps[3] = ps[2];
39+}
40+int main(int argc, char **argv)
41+{
42+ printf("* main\n"), fflush(stdout);
43+ f1();
44+ printf("* exit main\n"), fflush(stdout);
45+ return 0;
46+}
47+
48+/* ------------------------------------------------------- */
49+#elif defined test_tcc_backtrace_2
50+
51+/* test custom backtrace and 'exit()' redirection */
52+int tcc_backtrace(const char *fmt, ...);
53+void exit(int);
54+
55+void f2()
56+{
57+ printf("* f2()\n");
58+ printf("* exit f2\n"), fflush(stdout);
59+ exit(34);
60+}
61+void f1()
62+{
63+ printf("* f1()\n"), fflush(stdout);
64+ tcc_backtrace("Hello from %s!", "f1");
65+ f2();
66+}
67+int main(int argc, char **argv)
68+{
69+ printf("* main\n"), fflush(stdout);
70+ f1();
71+ printf("* exit main\n"), fflush(stdout);
72+ return 0;
73+}
74+
75+/* ------------------------------------------------------- */
76+#elif defined test_tcc_backtrace_3
77+
78+/* this test should be run despite of the exit(34) above */
79+int main(int argc, char **argv)
80+{
81+ printf("* main\n"), fflush(stdout);
82+ return 1;
83+}
84+
85+/* ------------------------------------------------------- */
86+#else
87+#include <malloc.h>
88+#include <string.h>
89+char *strdup();
90+int main()
91+{
92+ char pad1[10];
93+ char a[10];
94+ char pad2[10];
95+ char b[10];
96+ char pad3[10];
97+ memset (pad1, 0, sizeof(pad1));
98+ memset (pad2, 0, sizeof(pad2));
99+ memset (pad3, 0, sizeof(pad3));
100+
101+ memset (a, 'a', 10);
102+ a[3] = 0;
103+ a[9] = 0;
104+ memset (b, 'b', 10);
105+
106+#if defined test_bcheck_100
107+ memcpy(&a[1],&b[0],10);
108+#elif defined test_bcheck_101
109+ memcpy(&a[0],&b[1],10);
110+#elif defined test_bcheck_102
111+ memcpy(&a[0],&a[3],4);
112+#elif defined test_bcheck_103
113+ memcpy(&a[3],&a[0],4);
114+#elif defined test_bcheck_104
115+ memcmp(&b[1],&b[0],10);
116+#elif defined test_bcheck_105
117+ memcmp(&b[0],&b[1],10);
118+#elif defined test_bcheck_106
119+ memmove(&b[1],&b[0],10);
120+#elif defined test_bcheck_107
121+ memmove(&b[0],&b[1],10);
122+#elif defined test_bcheck_108
123+ memset(&b[1],'b',10);
124+#elif defined test_bcheck_109
125+ strlen(&b[0]);
126+#elif defined test_bcheck_110
127+ strcpy(&a[7], &a[0]);
128+#elif defined test_bcheck_111
129+ strcpy(&a[0], &b[7]);
130+#elif defined test_bcheck_112
131+ strcpy(&a[0], &a[1]);
132+#elif defined test_bcheck_113
133+ strcpy(&a[2], &a[0]);
134+#elif defined test_bcheck_114
135+ strncpy(&a[7], &a[0], 10);
136+#elif defined test_bcheck_115
137+ strncpy(&a[0], &b[7], 10);
138+#elif defined test_bcheck_116
139+ strncpy(&a[0], &a[1], 10);
140+#elif defined test_bcheck_117
141+ strncpy(&a[2], &a[0], 10);
142+#elif defined test_bcheck_118
143+ strcmp(&b[2], &b[0]);
144+#elif defined test_bcheck_119
145+ strcmp(&b[0], &b[2]);
146+#elif defined test_bcheck_120
147+ strncmp(&b[5], &b[0], 10);
148+#elif defined test_bcheck_121
149+ strncmp(&b[0], &b[5], 10);
150+#elif defined test_bcheck_122
151+ strcat(&a[7], &a[0]);
152+#elif defined test_bcheck_123
153+ strcat(&a[0], &b[5]);
154+#elif defined test_bcheck_124
155+ strcat(&a[0], &a[4]);
156+#elif defined test_bcheck_125
157+ strcat(&a[3], &a[0]);
158+#elif defined test_bcheck_126
159+ strchr(&b[0], 'a');
160+#elif defined test_bcheck_127
161+ free(strdup(&b[0]));
162+#endif
163+}
164+/* ------------------------------------------------------- */
165+#endif
tests/tests2/112_backtrace.expect+164−0
@@ -0,0 +1,164 @@
1+[test_backtrace_1]
2+* main
3+* f1()
4+* f2()
5+* f3()
6+112_backtrace.c:9: at f3: RUNTIME ERROR: invalid memory access
7+112_backtrace.c:14: by f2
8+112_backtrace.c:19: by f1
9+112_backtrace.c:24: by main
10+[returns 255]
11+
12+[test_bcheck_1]
13+* main
14+* f1()
15+112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region
16+112_backtrace.c:43: by main
17+112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x14 in memmove dest
18+112_backtrace.c:43: by main
19+[returns 255]
20+
21+[test_tcc_backtrace_2]
22+* main
23+* f1()
24+112_backtrace.c:64: at f1: Hello from f1!
25+112_backtrace.c:70: by main
26+* f2()
27+* exit f2
28+[returns 34]
29+
30+[test_tcc_backtrace_3]
31+* main
32+[returns 1]
33+
34+[test_bcheck_100]
35+112_backtrace.c:107: at main: BCHECK: ........ is outside of the region
36+112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0xa in memcpy dest
37+[returns 255]
38+
39+[test_bcheck_101]
40+112_backtrace.c:109: at main: BCHECK: ........ is outside of the region
41+112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0xa in memcpy src
42+[returns 255]
43+
44+[test_bcheck_102]
45+112_backtrace.c:111: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
46+[returns 255]
47+
48+[test_bcheck_103]
49+112_backtrace.c:113: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in memcpy
50+[returns 255]
51+
52+[test_bcheck_104]
53+112_backtrace.c:115: at main: BCHECK: ........ is outside of the region
54+112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s1
55+[returns 255]
56+
57+[test_bcheck_105]
58+112_backtrace.c:117: at main: BCHECK: ........ is outside of the region
59+112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0xa in memcmp s2
60+[returns 255]
61+
62+[test_bcheck_106]
63+112_backtrace.c:119: at main: BCHECK: ........ is outside of the region
64+112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0xa in memmove dest
65+[returns 255]
66+
67+[test_bcheck_107]
68+112_backtrace.c:121: at main: BCHECK: ........ is outside of the region
69+112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0xa in memmove src
70+[returns 255]
71+
72+[test_bcheck_108]
73+112_backtrace.c:123: at main: BCHECK: ........ is outside of the region
74+112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0xa in memset
75+[returns 255]
76+
77+[test_bcheck_109]
78+112_backtrace.c:125: at main: BCHECK: ........ is outside of the region
79+112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0xb in strlen
80+[returns 255]
81+
82+[test_bcheck_110]
83+112_backtrace.c:127: at main: BCHECK: ........ is outside of the region
84+112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy dest
85+[returns 255]
86+
87+[test_bcheck_111]
88+112_backtrace.c:129: at main: BCHECK: ........ is outside of the region
89+112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x4 in strcpy src
90+[returns 255]
91+
92+[test_bcheck_112]
93+112_backtrace.c:131: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strcpy
94+[returns 255]
95+
96+[test_bcheck_113]
97+112_backtrace.c:133: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcpy
98+[returns 255]
99+
100+[test_bcheck_114]
101+112_backtrace.c:135: at main: BCHECK: ........ is outside of the region
102+112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy dest
103+[returns 255]
104+
105+[test_bcheck_115]
106+112_backtrace.c:137: at main: BCHECK: ........ is outside of the region
107+112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x4 in strncpy src
108+[returns 255]
109+
110+[test_bcheck_116]
111+112_backtrace.c:139: at main: BCHECK: overlapping regions ........(0x3), ........(0x3) in strncpy
112+[returns 255]
113+
114+[test_bcheck_117]
115+112_backtrace.c:141: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strncpy
116+[returns 255]
117+
118+[test_bcheck_118]
119+112_backtrace.c:143: at main: BCHECK: ........ is outside of the region
120+112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s1
121+[returns 255]
122+
123+[test_bcheck_119]
124+112_backtrace.c:145: at main: BCHECK: ........ is outside of the region
125+112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x9 in strcmp s2
126+[returns 255]
127+
128+[test_bcheck_120]
129+112_backtrace.c:147: at main: BCHECK: ........ is outside of the region
130+112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s1
131+[returns 255]
132+
133+[test_bcheck_121]
134+112_backtrace.c:149: at main: BCHECK: ........ is outside of the region
135+112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x6 in strncmp s2
136+[returns 255]
137+
138+[test_bcheck_122]
139+112_backtrace.c:151: at main: BCHECK: ........ is outside of the region
140+112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x6 in strcat dest
141+[returns 255]
142+
143+[test_bcheck_123]
144+112_backtrace.c:153: at main: BCHECK: ........ is outside of the region
145+112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x6 in strcat src
146+[returns 255]
147+
148+[test_bcheck_124]
149+112_backtrace.c:155: at main: BCHECK: overlapping regions ........(0x9), ........(0x6) in strcat
150+[returns 255]
151+
152+[test_bcheck_125]
153+112_backtrace.c:157: at main: BCHECK: overlapping regions ........(0x4), ........(0x4) in strcat
154+[returns 255]
155+
156+[test_bcheck_126]
157+112_backtrace.c:159: at main: BCHECK: ........ is outside of the region
158+112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0xb in strchr
159+[returns 255]
160+
161+[test_bcheck_127]
162+112_backtrace.c:161: at main: BCHECK: ........ is outside of the region
163+112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0xb in strdup
164+[returns 255]
tests/tests2/60_errors_and_warnings.expect+1−0
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
2121
2222 [test_63_local_enumerator_redefinition]
23+[returns 1]
2324
2425 [test_61_undefined_enum]
2526 60_errors_and_warnings.c:46: error: unknown type size
tests/tests2/Makefile+5−5
@@ -24,6 +24,7 @@ ifeq (,$(filter i386,$(ARCH))) · 23 unmodified lines
2424 endif
2525 ifeq (,$(filter i386 x86_64,$(ARCH)))
2626 SKIP += 85_asm-outside-function.test
27+ SKIP += 112_backtrace.test
2728 endif
2829 ifeq (-$(findstring gcc,$(CC))-,--)
2930 SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@@ -70,12 +71,11 @@ GEN-ALWAYS = · 40 unmodified lines
7071 # constructor/destructor
7172 108_constructor.test: NORUN = true
7273
74+112_backtrace.test: FLAGS += -dt -b
75+112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g'
76+
7377 # Filter source directory in warnings/errors (out-of-tree builds)
74−FILTER = 2>&1 | sed 's,$(SRC)/,,g'
75−# Filter some always-warning
76−ifeq (-$(findstring arm,$(ARCH))-,-arm-)
77−FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
78−endif
78+FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
7979
8080 all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
8181
win32/build-tcc.bat+6−4
@@ -138,7 +138,7 @@ copy>nul tcc-win32.txt doc · 137 unmodified lines
138138 @if errorlevel 1 goto :the_end
139139
140140 :libtcc1.a
141−@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
141+@set O1=libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o
142142 .\tcc -m32 -c ../lib/libtcc1.c
143143 .\tcc -m32 -c lib/crt1.c
144144 .\tcc -m32 -c lib/crt1w.c
@@ -147,7 +147,6 @@ copy>nul tcc-win32.txt doc · 2 unmodified lines
147147 .\tcc -m32 -c lib/dllcrt1.c
148148 .\tcc -m32 -c lib/dllmain.c
149149 .\tcc -m32 -c lib/chkstk.S
150−.\tcc -m32 -w -c ../lib/bcheck.c
151150 .\tcc -m32 -c ../lib/alloca86.S
152151 .\tcc -m32 -c ../lib/alloca86-bt.S
153152 .\tcc -m32 -ar lib/libtcc1-32.a %O1% alloca86.o alloca86-bt.o
@@ -160,11 +159,14 @@ copy>nul tcc-win32.txt doc · 6 unmodified lines
160159 .\tcc -m64 -c lib/dllcrt1.c
161160 .\tcc -m64 -c lib/dllmain.c
162161 .\tcc -m64 -c lib/chkstk.S
163−.\tcc -m64 -w -c ../lib/bcheck.c
164162 .\tcc -m64 -c ../lib/alloca86_64.S
165163 .\tcc -m64 -c ../lib/alloca86_64-bt.S
166164 .\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
167165 @if errorlevel 1 goto :the_end
166+.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o
167+.\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o
168+.\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o
169+.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o
168170
169171 :tcc-doc.html
170172 @if not (%DOC%)==(yes) goto :doc-done
@@ -182,7 +184,7 @@ if not exist %INST% mkdir %INST% · 11 unmodified lines
182184 if not exist %BIN% mkdir %BIN%
183185 for %%f in (*tcc.exe *tcc.dll) do @copy>nul %%f %BIN%\%%f
184186 @if not exist %INST%\lib mkdir %INST%\lib
185−for %%f in (lib\*.a lib\*.def) do @copy>nul %%f %INST%\%%f
187+for %%f in (lib\*.a lib\*.o lib\*.def) do @copy>nul %%f %INST%\%%f
186188 for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %INST%\%%f
187189
188190 :the_end
win32/lib/crt1.c+1−1
@@ -99,7 +99,7 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) · 98 unmodified lines
9999 #if defined __i386__ || defined __x86_64__
100100 _controlfp(_PC_53, _MCW_PC);
101101 #endif
102− return do_main(__argc, __targv, _tenviron);
102+ return _tmain(__argc, __targv, _tenviron);
103103 }
104104
105105 // =============================================
x86_64-link.c+1−0
@@ -191,6 +191,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t · 190 unmodified lines
191191 if (s1->output_type == TCC_OUTPUT_DLL) {
192192 /* XXX: this logic may depend on TCC's codegen
193193 now TCC uses R_X86_64_32 even for a 64bit pointer */
194+ qrel->r_offset = rel->r_offset;
194195 qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
195196 /* Use sign extension! */
196197 qrel->r_addend = (int)read32le(ptr) + val;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t