History

tccrun: exit() via rt_longjmp()

- new LIBTCC API tcc_setjmp() to allow longjmps & signals from compiled code back to libtcc per TCCState - new LIBTCC API tcc_set_backtrace_func() to handle backtrace output - move c/dtor/atexit stuff to runtime (lib/runmain.c) - move bt-log.o into libtcc1.a - add timeouts to github action (beware, it did happen to hang infinitely in the signal handler at some point)

grischka committed 2 years ago

Commit c88b1991 parent 8d8d75c16 files · +384 −199Browse files

Unified · Split

16 files
  1. .github/workflows/build.yml +6 −0
  2. Makefile +23 −5
  3. lib/Makefile +2 −1
  4. lib/bt-exe.c +6 −6
  5. lib/bt-log.c +4 −5
  6. lib/runmain.c +87 −0
  7. libtcc.h +11 −0
  8. tcc.h +4 −0
  9. tccelf.c +0 −2
  10. tccpe.c +0 −2
  11. tccrun.c +167 −145
  12. tests/Makefile +14 −14
  13. tests/libtcc_test_mt.c +34 −8
  14. tests/tests2/128_run_atexit.c +5 −0
  15. tests/tests2/128_run_atexit.expect +2 −0
  16. win32/lib/crt1.c +19 −11
.github/workflows/build.yml+6−0
@@ -7,6 +7,7 @@ on: · 6 unmodified lines
77 jobs:
88 test-x86_64-linux:
99 runs-on: ubuntu-20.04
10+ timeout-minutes: 2
1011 steps:
1112 - uses: actions/checkout@v4
1213 - name: make & test tcc
@@ -14,6 +15,7 @@ jobs: · 1 unmodified line
1415
1516 test-x86_64-osx:
1617 runs-on: macos-11
18+ timeout-minutes: 2
1719 steps:
1820 - uses: actions/checkout@v4
1921 - name: make & test tcc
@@ -21,6 +23,7 @@ jobs: · 1 unmodified line
2123
2224 test-x86_64-win32:
2325 runs-on: windows-2019
26+ timeout-minutes: 4
2427 steps:
2528 - uses: actions/checkout@v4
2629 - name: make & test tcc
@@ -33,6 +36,7 @@ jobs: · 6 unmodified lines
3336
3437 test-armv7-linux:
3538 runs-on: ubuntu-20.04
39+ timeout-minutes: 6
3640 steps:
3741 - uses: actions/checkout@v4
3842 - uses: uraimo/run-on-arch-action@v2
@@ -49,6 +53,7 @@ jobs: · 10 unmodified lines
4953
5054 test-aarch64-linux:
5155 runs-on: ubuntu-20.04
56+ timeout-minutes: 6
5257 steps:
5358 - uses: actions/checkout@v4
5459 - uses: uraimo/run-on-arch-action@v2
@@ -65,6 +70,7 @@ jobs: · 10 unmodified lines
6570
6671 test-riscv64-linux:
6772 runs-on: ubuntu-20.04
73+ timeout-minutes: 6
6874 steps:
6975 - uses: actions/checkout@v4
7076 - uses: uraimo/run-on-arch-action@v2
Makefile+23−5
@@ -29,6 +29,9 @@ ifdef CONFIG_WIN32 · 28 unmodified lines
2929 ifneq ($(CONFIG_static),yes)
3030 LIBTCC = libtcc$(DLLSUF)
3131 LIBTCCDEF = libtcc.def
32+ -LTCC = $(bindir)/libtcc.dll
33+ else
34+ -LTCC = -ltcc -L$(libdir)
3235 endif
3336 ifneq ($(CONFIG_debug),yes)
3437 LDFLAGS += -s
@@ -70,6 +73,7 @@ else · 35 unmodified lines
7073 endif
7174 export MACOSX_DEPLOYMENT_TARGET := 10.6
7275 endif
76+ -LTCC = -ltcc
7377 endif
7478
7579 # run local version of tcc with local libraries and includes
@@ -79,6 +83,15 @@ TCCFLAGS = $(TCCFLAGS$(CFG)) · 3 unmodified lines
7983 TCC_LOCAL = $(TOP)/tcc$(EXESUF)
8084 TCC = $(TCC_LOCAL) $(TCCFLAGS)
8185
86+# run tests with the installed tcc instead
87+ifdef TESTINSTALL
88+ TCC_LOCAL = $(bindir)/tcc
89+ TCCFLAGS-unx = -I..
90+ TCCFLAGS-win = -I.. -B$(bindir)
91+ LIBTCC =
92+ LIBS += $(-LTCC)
93+endif
94+
8295 CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
8396 LIBS_P = $(LIBS)
8497 LDFLAGS_P = $(LDFLAGS)
@@ -373,7 +386,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2 · 288 unmodified lines
373386 IM = @echo "-> $2 : $1" ;
374387 BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
375388
376−B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
389+B_O = runmain.o bt-exe.o bt-dll.o bcheck.o
377390
378391 # install progs & libs
379392 install-unx:
@@ -411,7 +424,7 @@ install-win: · 31 unmodified lines
411424 $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
412425 $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
413426 $(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
414− $(call IFw,$(TOPSRC)/libtcc.h libtcc.def,"$(libdir)")
427+ $(call IFw,$(TOPSRC)/libtcc.h libtcc.def libtcc.a,"$(libdir)")
415428 $(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
416429 ifneq "$(wildcard $(LIBTCC1_U))" ""
417430 $(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
@@ -420,9 +433,9 @@ endif · 2 unmodified lines
420433
421434 # uninstall on windows
422435 uninstall-win:
423− @rm -fv $(addprefix "$(bindir)/", libtcc*.dll $(PROGS) *-tcc.exe)
424− @rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P/*")
425− @rm -frv $(addprefix "$(tccdir)/", doc examples include lib libtcc)
436+ @rm -fv $(foreach P,libtcc*.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P)
437+ @rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P/*)
438+ @rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P)
426439
427440 # the msys-git shell works to configure && make except it does not have install
428441 ifeq ($(OS),Windows_NT)
@@ -473,6 +486,9 @@ tcov-tes% : tcc_c$(EXESUF) · 44 unmodified lines
473486 @$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
474487 tcc_c$(EXESUF): $($T_FILES)
475488 $S$(TCC) tcc.c -o $@ -ftest-coverage $(DEFINES) $(LIBS)
489+# test the installed tcc instead
490+test-install: tccdefs_.h
491+ @$(MAKE) -C tests TESTINSTALL=yes #_all
476492
477493 clean:
478494 @rm -f tcc$(EXESUF) tcc_c$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF)
@@ -506,6 +522,8 @@ help: · 27 unmodified lines
506522 @echo " run all/single test(s) from tests/pp"
507523 @echo "make tcov-test / tcov-tests2... / tcov-testspp..."
508524 @echo " run tests as above with code coverage. After test(s) see tcc_c$(EXESUF).tcov"
525+ @echo "make test-install"
526+ @echo " run tests with the installed tcc"
509527 @echo "Other supported make targets:"
510528 @echo " install install-strip doc clean tags ETAGS tar distclean help"
511529 @echo "Custom configuration:"
lib/Makefile+2−1
@@ -67,7 +67,8 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) · 66 unmodified lines
6767 OBJ-arm-wince = $(ARM_O) $(WIN_O)
6868 OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
6969
70−OBJ-extra = $(filter $(B_O),$(OBJ-$T))
70+OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T)))
71+OBJ-extra += runmain.o
7172 OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
7273
7374 ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
lib/bt-exe.c+6−6
@@ -26,14 +26,14 @@ void __bt_init(rt_context *p, int is_exe) · 25 unmodified lines
2626 __bound_init(p->bounds_start, -1);
2727
2828 /* add to chain */
29− WAIT_SEM(&rt_sem);
29+ rt_wait_sem();
3030 p->next = g_rc, g_rc = p;
31− if (is_exe)
31+ rt_post_sem();
32+ if (is_exe) {
3233 /* we are the executable (not a dll) */
3334 p->top_func = main;
34− POST_SEM(&rt_sem);
35− if (is_exe)
3635 set_exception_handler();
36+ }
3737 }
3838
3939 __declspec(dllexport)
@@ -48,13 +48,13 @@ void __bt_exit(rt_context *p) · 8 unmodified lines
4848 __bound_exit_dll(p->bounds_start);
4949
5050 /* remove from chain */
51− WAIT_SEM(&rt_sem);
51+ rt_wait_sem();
5252 for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
5353 if (rc == p) {
5454 *pp = rc->next;
5555 break;
5656 }
57− POST_SEM(&rt_sem);
57+ rt_post_sem();
5858 }
5959
6060 /* copy a string and truncate it. */
lib/bt-log.c+4−5
@@ -18,25 +18,24 @@ · 17 unmodified lines
1818 #pragma GCC diagnostic ignored "-Wframe-address"
1919 #endif
2020
21−typedef struct rt_frame
22−{
21+typedef struct rt_frame {
2322 void *ip, *fp, *sp;
2423 } rt_frame;
2524
2625 __attribute__((weak))
27−int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
26+int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
2827
2928 DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
3029 {
3130 va_list ap;
3231 int ret;
3332
34− if (_rt_error) {
33+ if (__rt_dump) {
3534 rt_frame f;
3635 f.fp = __builtin_frame_address(1);
3736 f.ip = __builtin_return_address(0);
3837 va_start(ap, fmt);
39− ret = _rt_error(&f, "", fmt, ap);
38+ ret = __rt_dump(&f, NULL, fmt, ap);
4039 va_end(ap);
4140 } else {
4241 const char *p, *nl = "\n";
lib/runmain.c+87−0
@@ -0,0 +1,87 @@
1+/* ------------------------------------------------------------- */
2+/* support for tcc_run() */
3+
4+#ifdef __leading_underscore
5+# define _(s) s
6+#else
7+# define _(s) _##s
8+#endif
9+
10+#ifndef _WIN32
11+extern void (*_(_init_array_start)[]) (int argc, char **argv, char **envp);
12+extern void (*_(_init_array_end)[]) (int argc, char **argv, char **envp);
13+static void run_ctors(int argc, char **argv, char **env)
14+{
15+ int i = 0;
16+ while (&_(_init_array_start)[i] != _(_init_array_end))
17+ (*_(_init_array_start)[i++])(argc, argv, env);
18+}
19+#endif
20+
21+extern void (*_(_fini_array_start)[]) (void);
22+extern void (*_(_fini_array_end)[]) (void);
23+static void run_dtors(void)
24+{
25+ int i = 0;
26+ while (&_(_fini_array_end)[i] != _(_fini_array_start))
27+ (*_(_fini_array_end)[--i])();
28+}
29+
30+static void *rt_exitfunc[32];
31+static void *rt_exitarg[32];
32+int __rt_nr_exit;
33+
34+void __run_on_exit(int ret)
35+{
36+ int n = __rt_nr_exit;
37+ while (n)
38+ --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
39+}
40+
41+int on_exit(void *function, void *arg)
42+{
43+ int n = __rt_nr_exit;
44+ if (n < 32) {
45+ rt_exitfunc[n] = function;
46+ rt_exitarg[n] = arg;
47+ __rt_nr_exit = n + 1;
48+ return 0;
49+ }
50+ return 1;
51+}
52+
53+int atexit(void (*function)(void))
54+{
55+ return on_exit(function, 0);
56+}
57+
58+typedef struct rt_frame {
59+ void *ip, *fp, *sp;
60+} rt_frame;
61+
62+void __rt_longjmp(rt_frame *, int);
63+
64+void exit(int code)
65+{
66+ rt_frame f;
67+ run_dtors();
68+ __run_on_exit(code);
69+ f.fp = __builtin_frame_address(1);
70+ f.ip = __builtin_return_address(0);
71+ __rt_longjmp(&f, code);
72+}
73+
74+#ifndef _WIN32
75+int main(int, char**, char**);
76+
77+int _runmain(int argc, char **argv, char **envp)
78+{
79+ int ret;
80+ __rt_nr_exit = 0;
81+ run_ctors(argc, argv, envp);
82+ ret = main(argc, argv, envp);
83+ run_dtors();
84+ __run_on_exit(ret);
85+ return ret;
86+}
87+#endif
libtcc.h+11−0
@@ -100,6 +100,17 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); · 99 unmodified lines
100100 LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
101101 void (*symbol_cb)(void *ctx, const char *name, const void *val));
102102
103+/* experimental/advanced section (see libtcc_test_mt.c for an example) */
104+
105+/* catch runtime exceptions (optionally limit backtraces at top_func),
106+ when using tcc_set_options("-bt") and when not using tcc_run() */
107+LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *longjmp, void *jmp_buf, void *top_func);
108+#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, longjmp, jb, f))
109+
110+/* set custom error printer for runtime exceptions */
111+typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func);
112+LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*);
113+
103114 #ifdef __cplusplus
104115 }
105116 #endif
tcc.h+4−0
@@ -1000,6 +1000,10 @@ struct TCCState { · 999 unmodified lines
10001000 #ifdef _WIN64
10011001 void *run_function_table; /* unwind data */
10021002 #endif
1003+ struct TCCState *next;
1004+ struct rt_context *rc; /* pointer to backtrace info block */
1005+ void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */
1006+ void (*bt_func)(void *, const char*, int, const char*);
10031007 #endif
10041008
10051009 #ifdef CONFIG_TCC_BACKTRACE
tccelf.c+0−2
@@ -1778,8 +1778,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) · 1777 unmodified lines
17781778 if (s1->do_backtrace) {
17791779 if (s1->output_type & TCC_OUTPUT_EXE)
17801780 tcc_add_support(s1, "bt-exe.o");
1781− if (s1->output_type != TCC_OUTPUT_DLL)
1782− tcc_add_support(s1, "bt-log.o");
17831781 tcc_add_btstub(s1);
17841782 lpthread = 1;
17851783 }
tccpe.c+0−2
@@ -1961,8 +1961,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) · 1960 unmodified lines
19611961 tcc_add_support(s1, "bt-exe.o");
19621962 if (s1->output_type == TCC_OUTPUT_DLL)
19631963 tcc_add_support(s1, "bt-dll.o");
1964− if (s1->output_type != TCC_OUTPUT_DLL)
1965− tcc_add_support(s1, "bt-log.o");
19661964 tcc_add_btstub(s1);
19671965 }
19681966 #endif
tccrun.c+167−145
@@ -26,7 +26,7 @@ · 25 unmodified lines
2626 #ifdef CONFIG_TCC_BACKTRACE
2727 typedef struct rt_context
2828 {
29− /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
29+ /* tccelf.c:tcc_add_btstub() wants these in that order: */
3030 union {
3131 struct {
3232 Stab_Sym *stab_sym;
@@ -42,55 +42,33 @@ typedef struct rt_context · 9 unmodified lines
4242 ElfW(Sym) *esym_start;
4343 ElfW(Sym) *esym_end;
4444 char *elf_str;
45−
45+ // 6
4646 addr_t prog_base;
4747 void *bounds_start;
4848 void *top_func;
4949 TCCState *s1;
5050 struct rt_context *next;
51−
51+ // 11
5252 int num_callers;
5353 int dwarf;
54− /* <-- */
5554 } rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
5655
57−typedef struct rt_frame
58−{
56+typedef struct rt_frame {
5957 addr_t ip, fp, sp;
6058 } rt_frame;
6159
6260 /* linked list of rt_contexts */
6361 static rt_context *g_rc;
62+static TCCState *g_s1;
6463 /* semaphore to protect it */
6564 TCC_SEM(static rt_sem);
6665 static int signal_set;
6766 static void set_exception_handler(void);
68−
69−#ifdef _WIN32
70−#define ATTR_WEAK
71−#else
72−#define ATTR_WEAK __attribute__((weak))
73−#endif
74−int ATTR_WEAK _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
75−void ATTR_WEAK rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
76−void ATTR_WEAK rt_post_sem(void) { POST_SEM(&rt_sem); }
77−#undef ATTR_WEAK
67+static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
68+static void rt_post_sem(void) { POST_SEM(&rt_sem); }
69+static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
7870 #endif /* def CONFIG_TCC_BACKTRACE */
7971
80−/* handle exit/atexit for tcc_run() -- thread-unsafe */
81−static jmp_buf rt_jb;
82−static int rt_do_jmp;
83−static int rt_nr_exit;
84−static void *rt_exitfunc[32];
85−static void *rt_exitarg[32];
86−
87−static void rt_exit(int code)
88−{
89− if (rt_do_jmp)
90− longjmp(rt_jb, code ? code : 256);
91− exit(code);
92−}
93−
9472 /* ------------------------------------------------------------- */
9573 /* defined when included from lib/bt-exe.c */
9674 #ifndef CONFIG_TCC_BACKTRACE_ONLY
@@ -101,7 +79,8 @@ static void rt_exit(int code) · 4 unmodified lines
10179
10280 static int protect_pages(void *ptr, unsigned long length, int mode);
10381 static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
104−
82+static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
83+static void rt_longjmp(rt_frame *f, int code);
10584 #ifdef _WIN64
10685 static void *win64_add_function_table(TCCState *s1);
10786 static void win64_del_function_table(void *);
@@ -118,12 +97,9 @@ static void bt_link(TCCState *s1) · 10 unmodified lines
11897 rc = tcc_get_symbol(s1, "__rt_info");
11998 if (!rc)
12099 return;
121− rt_wait_sem();
122− rc->next = g_rc, g_rc = rc, rc->s1 = s1;
123100 rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
124101 rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
125102 rc->elf_str = (char *)symtab_section->link->data;
126− rc->top_func = tcc_get_symbol(s1, "main");
127103 if (PTR_SIZE == 8 && !s1->dwarf)
128104 rc->prog_base &= 0xffffffff00000000ULL;
129105 #ifdef CONFIG_TCC_BCHECK
@@ -132,7 +108,7 @@ static void bt_link(TCCState *s1) · 2 unmodified lines
132108 ((void(*)(void*,int))p)(rc->bounds_start, 1);
133109 }
134110 #endif
135− rt_post_sem();
111+ rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc;
136112 if (0 == signal_set)
137113 set_exception_handler(), signal_set = 1;
138114 #endif
@@ -142,16 +118,35 @@ static void bt_unlink(TCCState *s1) · 3 unmodified lines
142118 {
143119 #ifdef CONFIG_TCC_BACKTRACE
144120 rt_context *rc, **pp;
145− rt_wait_sem();
146121 for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
147122 if (rc->s1 == s1) {
148123 *pp = rc->next;
149124 break;
150125 }
151− rt_post_sem();
152126 #endif
153127 }
154128
129+static void st_link(TCCState *s1)
130+{
131+ rt_wait_sem();
132+ s1->next = g_s1, g_s1 = s1;
133+ bt_link(s1);
134+ rt_post_sem();
135+}
136+
137+static void st_unlink(TCCState *s1)
138+{
139+ TCCState *s2, **pp;
140+ rt_wait_sem();
141+ bt_unlink(s1);
142+ for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next)
143+ if (s2 == s1) {
144+ *pp = s2->next;
145+ break;
146+ }
147+ rt_post_sem();
148+}
149+
155150 #if !_WIN32 && !__APPLE__
156151 //#define HAVE_SELINUX 1
157152 #endif
@@ -196,9 +191,8 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) · 38 unmodified lines
196191 exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
197192
198193 #ifdef CONFIG_TCC_BACKTRACE
199− /* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
200− if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error"))
201− tcc_add_symbol(s1, "_rt_error", _rt_error);
194+ if (s1->do_backtrace)
195+ tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */
202196 #endif
203197
204198 size = tcc_relocate_ex(s1, NULL, 0);
@@ -209,7 +203,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1) · 4 unmodified lines
209203 return -1;
210204 ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
211205 if (ret == 0)
212− bt_link(s1);
206+ st_link(s1);
213207 return ret;
214208 }
215209
@@ -231,12 +225,11 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 15 unmodified lines
231225 }
232226 /* free loaded dlls array */
233227 dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
234−
235228 /* unmap or unprotect and free memory */
236229 ptr = s1->run_ptr;
237230 if (NULL == ptr)
238231 return;
239− bt_unlink(s1);
232+ st_unlink(s1);
240233 size = s1->run_size;
241234 #ifdef HAVE_SELINUX
242235 munmap(ptr, size * 2);
@@ -250,41 +243,25 @@ ST_FUNC void tcc_run_free(TCCState *s1) · 7 unmodified lines
250243 #endif
251244 }
252245
253−static void run_cdtors(TCCState *s1, const char *start, const char *end,
254− int argc, char **argv, char **envp)
246+LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func)
255247 {
256− void **a = (void **)get_sym_addr(s1, start, 0, 0);
257− void **b = (void **)get_sym_addr(s1, end, 0, 0);
258− while (a != b)
259− ((void(*)(int, char **, char **))*a++)(argc, argv, envp);
248+ s1->run_lj = p_longjmp;
249+ s1->run_jb = p_jmp_buf;
250+ if (func && s1->rc)
251+ s1->rc->top_func = func;
252+ return p_jmp_buf;
260253 }
261254
262−static void run_on_exit(int ret)
255+LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func)
263256 {
264− int n = rt_nr_exit;
265− while (n)
266− --n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
267−}
268−
269−static int rt_on_exit(void *function, void *arg)
270−{
271− if (rt_nr_exit < countof(rt_exitfunc)) {
272− rt_exitfunc[rt_nr_exit] = function;
273− rt_exitarg[rt_nr_exit++] = arg;
274− return 0;
275− }
276− return 1;
277−}
278−
279−static int rt_atexit(void *function)
280−{
281− return rt_on_exit(function, NULL);
257+ s1->bt_func = func;
282258 }
283259
284260 /* launch the compiled program with the given arguments */
285261 LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
286262 {
287263 int (*prog_main)(int, char **, char **), ret;
264+ jmp_buf main_jb;
288265
289266 #if defined(__APPLE__) || defined(__FreeBSD__)
290267 char **envp = NULL;
@@ -295,35 +272,29 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 4 unmodified lines
295272 char **envp = environ;
296273 #endif
297274
298− s1->run_main = s1->nostdlib ? "_start" : "main";
299− if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1))
275+ /* tcc -dt -run ... nothing to do if no main() */
276+ if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1))
300277 return 0;
301278
302− tcc_add_symbol(s1, "exit", rt_exit);
303− tcc_add_symbol(s1, "atexit", rt_atexit);
304− tcc_add_symbol(s1, "on_exit", rt_on_exit);
279+ tcc_add_support(s1, "runmain.o");
280+ tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp);
281+ s1->run_main = (s1->nostdlib ? "_start" : "_runmain");
305282 if (tcc_relocate(s1) < 0)
306283 return -1;
307284
308285 prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
309286 if ((addr_t)-1 == (addr_t)prog_main)
310287 return -1;
311−
312288 errno = 0; /* clean errno value */
313289 fflush(stdout);
314290 fflush(stderr);
315− rt_do_jmp = 1;
316− rt_nr_exit = 0;
317291
318− /* These aren't C symbols, so don't need leading underscore handling. */
319− run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
320− ret = setjmp(rt_jb);
292+ ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main"));
321293 if (0 == ret)
322294 ret = prog_main(argc, argv, envp);
323295 else if (256 == ret)
324296 ret = 0;
325− run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL);
326− run_on_exit(ret);
297+
327298 if (s1->dflag & 16 && ret) /* tcc -dt -run ... */
328299 fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
329300 return ret;
@@ -385,7 +356,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff) · 55 unmodified lines
385356 addr_t mem, addr;
386357
387358 if (NULL == ptr) {
388− s1->nb_errors = 0;
389359 #ifdef TCC_TARGET_PE
390360 pe_output_file(s1, NULL);
391361 #else
@@ -616,7 +586,7 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr) · 224 unmodified lines
616586 /* print the position in the source file of PC value 'pc' by reading
617587 the stabs debug information */
618588 static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
619− const char *msg, const char *skip)
589+ rt_context** prc, const char *msg, const char *skip)
620590 {
621591 char func_name[128];
622592 addr_t func_addr, last_pc, pc;
@@ -726,14 +696,21 @@ next: · 103 unmodified lines
726696
727697 found:
728698 i = last_incl_index;
699+ str = NULL;
729700 if (i > 0) {
730701 str = incl_files[--i];
731702 if (skip[0] && strstr(str, skip))
732703 return (addr_t)-1;
733− rt_printf("%s:%d: ", str, last_line_num);
734− } else
735− rt_printf("%08llx : ", (long long)wanted_pc);
736− rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
704+ }
705+ if (rc && rc->s1 && rc->s1->bt_func) {
706+ rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL);
707+ } else {
708+ if (str)
709+ rt_printf("%s:%d: ", str, last_line_num);
710+ else
711+ rt_printf("%08llx : ", (long long)wanted_pc);
712+ rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
713+ }
737714 #if 0
738715 if (--i >= 0) {
739716 rt_printf(" (included from ");
@@ -746,6 +723,7 @@ found: · 6 unmodified lines
746723 rt_printf(")");
747724 }
748725 #endif
726+ *prc = rc;
749727 return func_addr;
750728 }
751729
@@ -816,7 +794,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end) · 64 unmodified lines
816794 }
817795
818796 static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
819− const char *msg, const char *skip)
797+ rt_context** prc, const char *msg, const char *skip)
820798 {
821799 unsigned char *ln;
822800 unsigned char *cp;
@@ -859,6 +837,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc, · 36 unmodified lines
859837 next:
860838 filename = NULL;
861839 func_addr = 0;
840+ line = 0;
862841 if (NULL == rc)
863842 goto found;
864843
@@ -1102,29 +1081,33 @@ next_line: · 237 unmodified lines
11021081 goto next;
11031082
11041083 found:
1105− if (filename) {
1106− if (skip[0] && strstr(filename, skip))
1107− return (addr_t)-1;
1108− rt_printf("%s:%d: ", filename, line);
1084+ if (rc && rc->s1 && rc->s1->bt_func) {
1085+ rc->s1->bt_func((void*)wanted_pc, filename, line, function);
1086+ } else {
1087+ if (filename) {
1088+ if (skip[0] && strstr(filename, skip))
1089+ return (addr_t)-1;
1090+ rt_printf("%s:%d: ", filename, line);
1091+ }
1092+ else
1093+ rt_printf("0x%08llx : ", (long long)wanted_pc);
1094+ rt_printf("%s %s", msg, function ? function : "???");
11091095 }
1110− else
1111− rt_printf("0x%08llx : ", (long long)wanted_pc);
1112− rt_printf("%s %s", msg, function ? function : "???");
1096+ *prc = rc;
11131097 return (addr_t)func_addr;
11141098 }
11151099 /* ------------------------------------------------------------- */
1116−
1117−static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
1118−
1119−int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)
1100+#ifndef CONFIG_TCC_BACKTRACE_ONLY
1101+static
1102+#endif
1103+int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap)
11201104 {
1121− rt_context *rc;
1105+ rt_context *rc, *rd;
11221106 addr_t pc = 0;
11231107 char skip[100];
11241108 int i, level, ret, n, one;
11251109 const char *a, *b;
1126− addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
1127− addr_t top_func = 0;
1110+ addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*);
11281111
11291112 skip[0] = 0;
11301113 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
@@ -1145,27 +1128,28 @@ int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap) · 14 unmodified lines
11451128 printline = rt_printline_dwarf;
11461129 if (rc->num_callers)
11471130 n = rc->num_callers;
1148− top_func = (addr_t)rc->top_func;
11491131 }
1150−
11511132 for (i = level = 0; level < n; i++) {
11521133 ret = rt_get_caller_pc(&pc, f, i);
1153− a = "%s";
11541134 if (ret != -1) {
1155− pc = printline(rc, pc, level ? "by" : "at", skip);
1135+ pc = printline(rc, pc, &rd, level ? "by" : "at", skip);
11561136 if (pc == (addr_t)-1)
11571137 continue;
1158− a = ": %s";
11591138 }
11601139 if (level == 0) {
1161− rt_printf(a, msg);
1140+ if (rd && rd->s1 && rd->s1->bt_func)
1141+ break;
1142+ if (ret != -1)
1143+ rt_printf(": ");
1144+ if (msg)
1145+ rt_printf("%s: ", msg);
11621146 rt_vprintf(fmt, ap);
11631147 } else if (ret == -1)
11641148 break;
11651149 if (one)
11661150 break;
11671151 rt_printf("\n");
1168− if (ret == -1 || (pc == top_func && pc))
1152+ if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc))
11691153 break;
11701154 ++level;
11711155 }
@@ -1180,11 +1164,46 @@ static int rt_error(rt_frame *f, const char *fmt, ...) · 8 unmodified lines
11801164 va_list ap;
11811165 int ret;
11821166 va_start(ap, fmt);
1183− ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
1167+ ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap);
11841168 va_end(ap);
11851169 return ret;
11861170 }
11871171
1172+static TCCState *rt_find_state(rt_frame *f)
1173+{
1174+ TCCState *s;
1175+ int level;
1176+ addr_t pc;
1177+
1178+ rt_wait_sem();
1179+ for (s = g_s1; s; s = s->next) {
1180+ if (0 == s->run_lj)
1181+ continue;
1182+ for (level = 0; level < 8; ++level) {
1183+ if (rt_get_caller_pc(&pc, f, level) < 0)
1184+ break;
1185+ if (pc >= (addr_t)s->run_ptr
1186+ && pc < (addr_t)s->run_ptr + s->run_size)
1187+ goto found;
1188+ }
1189+ }
1190+found:
1191+ rt_post_sem();
1192+ //fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr);
1193+ return s;
1194+}
1195+
1196+static void rt_longjmp(rt_frame *f, int code)
1197+{
1198+ TCCState *s = rt_find_state(f);
1199+ if (s && s->run_lj) {
1200+ if (code == 0)
1201+ code = 256;
1202+ ((void(*)(void*,int))s->run_lj)(s->run_jb, code);
1203+ }
1204+ exit(code);
1205+}
1206+
11881207 /* ------------------------------------------------------------- */
11891208
11901209 #ifndef _WIN32
@@ -1319,7 +1338,8 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) · 128 unmodified lines
13191338 rt_error(&f, "caught signal %d", signum);
13201339 break;
13211340 }
1322− rt_exit(255);
1341+ set_exception_handler();
1342+ rt_longjmp(&f, 255);
13231343 }
13241344
13251345 #ifndef SA_SIGINFO
@@ -1333,7 +1353,7 @@ static void set_exception_handler(void) · 7 unmodified lines
13331353 /* install TCC signal handlers to print debug info on fatal
13341354 runtime errors */
13351355 sigemptyset (&sigact.sa_mask);
1336− sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
1356+ sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER;
13371357 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
13381358 sigact.sa_flags |= SA_ONSTACK;
13391359 #endif
@@ -1365,7 +1385,6 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) · 25 unmodified lines
13651385 {
13661386 rt_frame f;
13671387 unsigned code;
1368−
13691388 rt_getcontext(ex_info->ContextRecord, &f);
13701389
13711390 switch (code = ex_info->ExceptionRecord->ExceptionCode) {
@@ -1387,8 +1406,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) · 15 unmodified lines
13871406 rt_error(&f, "caught exception %08x", code);
13881407 break;
13891408 }
1390− if (rt_do_jmp)
1391− rt_exit(255);
1409+ rt_longjmp(&f, 255);
13921410 return EXCEPTION_EXECUTE_HANDLER;
13931411 }
13941412
@@ -1405,45 +1423,41 @@ static void set_exception_handler(void) · 10 unmodified lines
14051423 #if defined(__i386__) || defined(__x86_64__)
14061424 static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
14071425 {
1408− addr_t ip, fp;
14091426 if (level == 0) {
1410− ip = rc->ip;
1427+ *paddr = rc->ip;
14111428 } else {
1412− ip = 0;
1413− fp = rc->fp;
1414− while (--level) {
1415− /* XXX: check address validity with program info */
1416− if (fp <= 0x1000)
1429+ addr_t fp = rc->fp;
1430+ while (1) {
1431+ if (fp < 0x1000)
1432+ return -1;
1433+ if (0 == --level)
14171434 break;
1435+ /* XXX: check address validity with program info */
14181436 fp = ((addr_t *)fp)[0];
14191437 }
1420− if (fp > 0x1000)
1421− ip = ((addr_t *)fp)[1];
1438+ *paddr = ((addr_t *)fp)[1];
14221439 }
1423− if (ip <= 0x1000)
1424− return -1;
1425− *paddr = ip;
14261440 return 0;
14271441 }
14281442
1429−#elif defined(__arm__)
1443+/* XXX: only supports linux/bsd */
1444+#elif defined(__arm__) && !defined(_WIN32)
14301445 static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
14311446 {
1432− /* XXX: only supports linux/bsd */
1433−#if !defined(__linux__) && \
1434− !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1435− return -1;
1436−#else
14371447 if (level == 0) {
14381448 *paddr = rc->ip;
14391449 } else {
14401450 addr_t fp = rc->fp;
1441− while (--level)
1451+ while (1) {
1452+ if (fp < 0x1000)
1453+ return -1;
1454+ if (0 == --level)
1455+ break;
14421456 fp = ((addr_t *)fp)[0];
1457+ }
14431458 *paddr = ((addr_t *)fp)[2];
14441459 }
14451460 return 0;
1446−#endif
14471461 }
14481462
14491463 #elif defined(__aarch64__)
@@ -1452,10 +1466,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) · 2 unmodified lines
14521466 if (level == 0) {
14531467 *paddr = rc->ip;
14541468 } else {
1455− addr_t *fp = (addr_t*)rc->fp;
1456− while (--level)
1457− fp = (addr_t *)fp[0];
1458− *paddr = fp[1];
1469+ addr_t fp = rc->fp;
1470+ while (1) {
1471+ if (fp < 0x1000)
1472+ return -1;
1473+ if (0 == --level)
1474+ break;
1475+ fp = ((addr_t *)fp)[0];
1476+ }
1477+ *paddr = ((addr_t *)fp)[1];
14591478 }
14601479 return 0;
14611480 }
@@ -1466,12 +1485,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level) · 4 unmodified lines
14661485 if (level == 0) {
14671486 *paddr = rc->ip;
14681487 } else {
1469− addr_t *fp = (addr_t*)rc->fp;
1470− while (--level && fp >= (addr_t*)0x1000)
1471− fp = (addr_t *)fp[-2];
1472− if (fp < (addr_t*)0x1000)
1473− return -1;
1474− *paddr = fp[-1];
1488+ addr_t fp = rc->fp;
1489+ while (1) {
1490+ if (fp < 0x1000)
1491+ return -1;
1492+ if (0 == --level)
1493+ break;
1494+ fp = ((addr_t *)fp)[-2];
1495+ }
1496+ *paddr = ((addr_t *)fp)[-1];
14751497 }
14761498 return 0;
14771499 }
tests/Makefile+14−14
@@ -14,23 +14,20 @@ TESTS = \ · 13 unmodified lines
1414 libtest \
1515 libtest_mt \
1616 test3 \
17− memtest \
18− dlltest \
1917 abitest \
2018 asm-c-connect-test \
2119 vla_test-run \
22− cross-test \
2320 tests2-dir \
24− pp-dir
21+ pp-dir \
22+ memtest \
23+ dlltest \
24+ cross-test
2525
2626 # test4_static -- Not all relocation types are implemented yet.
2727 # asmtest / asmtest2 -- minor differences with gcc
2828
2929 ifneq ($(CONFIG_bcheck),no)
30− TESTS += btest test1b
31− ifndef CONFIG_WIN32
32− TESTS += tccb
33− endif
30+ TESTS += btest test1b tccb
3431 endif
3532 ifeq ($(CONFIG_dll),no)
3633 TESTS := $(filter-out dlltest, $(TESTS))
@@ -82,7 +79,9 @@ all test : · 45 unmodified lines
8279 @echo ------------ version ------------
8380 @$(TCC_LOCAL) -v
8481 @$(MAKE) --no-print-directory -s clean
85− @$(MAKE) --no-print-directory -s -r $(TESTS)
82+ @$(MAKE) --no-print-directory -s -r _all
83+
84+_all : $(TESTS)
8685
8786 hello-exe: ../examples/ex1.c
8887 @echo ------------ $@ ------------
@@ -199,14 +198,15 @@ btest: boundtest.c · 110 unmodified lines
199198 echo "Test $$i failed as expected" ; \
200199 fi ;\
201200 done ;\
202− echo Bound test OK
201+ echo Bound-Test OK
203202
204203 tccb:
205204 @echo ------------ $@ ------------
206− $(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
207− mv v1-tcc$(EXESUF) v2-tcc$(EXESUF)
208− ./v2-tcc$(EXESUF) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
209− cmp -s v1-tcc$(EXESUF) v2-tcc$(EXESUF) && echo "Bound-Test tcc OK"
205+ $(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
206+ mv tccb1.exe tccb2.exe
207+ ./tccb2.exe -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
208+ cmp -s tccb1.exe tccb2.exe && echo "Exe Bound-Rest OK"
209+
210210
211211 # speed test
212212 speedtest: ex2 ex3
tests/libtcc_test_mt.c+34−8
@@ -6,6 +6,7 @@ · 5 unmodified lines
66 #include <stdlib.h>
77 #include <stdio.h>
88 #include <string.h>
9+#include <setjmp.h>
910 #include "libtcc.h"
1011
1112 #define M 20 /* number of states */
@@ -84,6 +85,8 @@ PROG(my_program) · 72 unmodified lines
8485 "\n"
8586 "int foo(int n)\n"
8687 "{\n"
88+" if (n >= N_CRASH && n < N_CRASH + 3)\n"
89+" *(void**)0 = 0;\n"
8790 " printf(\" %d\", fib(n));\n"
8891 " return 0;\n"
8992 "# warning is this the correct file:line...\n"
@@ -110,6 +113,11 @@ void parse_args(TCCState *s) · 20 unmodified lines
110113 }
111114 }
112115
116+void bt_func(void *pc, const char *file, int line, const char *func)
117+{
118+ printf(" *** at %s:%d in '%s'\n", file, line, func);
119+}
120+
113121 TCCState *new_state(int w)
114122 {
115123 TCCState *s = tcc_new();
@@ -119,7 +127,14 @@ TCCState *new_state(int w) · 3 unmodified lines
119127 }
120128 tcc_set_error_func(s, stdout, handle_error);
121129 parse_args(s);
122− if (!w) tcc_set_options(s, "-w");
130+ if (0 == (w & 1))
131+ tcc_set_options(s, "-w");
132+ if (w & 2) {
133+ tcc_set_options(s, "-bt");
134+ tcc_define_symbol(s, "N_CRASH", str(M/2));
135+ tcc_set_backtrace_func(s, bt_func);
136+ } else
137+ tcc_define_symbol(s, "N_CRASH", "99");
123138 tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
124139 return s;
125140 }
@@ -139,23 +154,28 @@ void *reloc_state(TCCState *s, const char *entry) · 13 unmodified lines
139154 }
140155
141156 /* work with several states at the same time */
142−int state_test(void)
157+int state_test(int w)
143158 {
144159 TCCState *s[M];
145− int (*func[M])(int);
160+ int (*funcs[M])(int);
146161 int n;
162+ jmp_buf jb;
147163
148164 for (n = 0; n < M + 4; ++n) {
149165 unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
150166 if (a < M)
151− s[a] = new_state(0);
167+ s[a] = new_state(w);
152168 if (b < M)
153169 if (tcc_compile_string(s[b], my_program) == -1)
154170 break;
155171 if (c < M)
156− func[c] = reloc_state(s[c], "foo");
157− if (d < M && func[d])
158− func[d](F(d));
172+ funcs[c] = reloc_state(s[c], "foo");
173+ if (d < M && funcs[d]) {
174+ if ((w & 2) && d == 8)
175+ printf("\n");
176+ if (0 == tcc_setjmp(s[d], jb, funcs[d]))
177+ funcs[d](F(d));
178+ }
159179 if (e < M)
160180 tcc_delete(s[e]);
161181 }
@@ -257,7 +277,13 @@ int main(int argc, char **argv) · 95 unmodified lines
257277 #if 1
258278 printf("running fib with mixed calls\n "), fflush(stdout);
259279 t = getclock_ms();
260− state_test();
280+ state_test(0);
281+ printf("\n (%u ms)\n", getclock_ms() - t);
282+#endif
283+#if 1
284+ printf("producing some exceptions\n "), fflush(stdout);
285+ t = getclock_ms();
286+ state_test(2);
261287 printf("\n (%u ms)\n", getclock_ms() - t);
262288 #endif
263289 #if 1
tests/tests2/128_run_atexit.c+5−0
@@ -4,6 +4,11 @@ int atexit(void (*function)(void)); · 3 unmodified lines
44 int on_exit(void (*function)(int, void *), void *arg);
55 void exit(int status);
66
7+void __attribute((constructor)) startup5(void)
8+{
9+ printf ("startup5\n");
10+}
11+
712 void cleanup1(void)
813 {
914 printf ("cleanup1\n");
tests/tests2/128_run_atexit.expect+2−0
@@ -1,4 +1,5 @@
11 [test_128_return]
2+startup5
23 cleanup5
34 1 cleanup4
45 1 cleanup3
@@ -7,6 +8,7 @@ cleanup1 · 2 unmodified lines
78 [returns 1]
89
910 [test_128_exit]
11+startup5
1012 cleanup5
1113 2 cleanup4
1214 2 cleanup3
win32/lib/crt1.c+19−11
@@ -37,15 +37,6 @@ extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]); · 36 unmodified lines
3737
3838 #include "crtinit.c"
3939
40−static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[])
41−{
42− int retval;
43− run_ctors(argc, argv, env);
44− retval = _tmain(__argc, __targv, _tenviron);
45− run_dtors();
46− return retval;
47−}
48−
4940 /* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
5041 int _dowildcard;
5142
@@ -56,6 +47,8 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex) · 4 unmodified lines
5647
5748 void _tstart(void)
5849 {
50+ int ret;
51+
5952 _startupinfo start_info = {0};
6053 SetUnhandledExceptionFilter(catch_sig);
6154 // Sets the current application type
@@ -68,11 +61,21 @@ void _tstart(void) · 6 unmodified lines
6861 #endif
6962
7063 __tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
71− exit(do_main(__argc, __targv, _tenviron));
64+ run_ctors(__argc, __targv, _tenviron);
65+ ret = _tmain(__argc, __targv, _tenviron);
66+ run_dtors();
67+ exit(ret);
7268 }
7369
70+// =============================================
71+// for 'tcc -run ,,,'
72+
73+__attribute__((weak)) extern int __rt_nr_exit;
74+__attribute__((weak)) extern int __run_on_exit();
75+
7476 int _runtmain(int argc, /* as tcc passed in */ char **argv)
7577 {
78+ int ret;
7679 #ifdef UNICODE
7780 _startupinfo start_info = {0};
7881
@@ -89,7 +92,12 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv) · 10 unmodified lines
8992 #if defined __i386__ || defined __x86_64__
9093 _controlfp(_PC_53, _MCW_PC);
9194 #endif
92− return _tmain(__argc, __targv, _tenviron);
95+ __rt_nr_exit = 0;
96+ run_ctors(__argc, __targv, _tenviron);
97+ ret = _tmain(__argc, __targv, _tenviron);
98+ run_dtors();
99+ __run_on_exit(ret);
100+ return ret;
93101 }
94102
95103 // =============================================

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