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)
This commit is contained in:
parent
8d8d75ca75
commit
c88b19966c
16 changed files with 395 additions and 210 deletions
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
|
@ -7,6 +7,7 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
test-x86_64-linux:
|
test-x86_64-linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 2
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: make & test tcc
|
- name: make & test tcc
|
||||||
|
@ -14,6 +15,7 @@ jobs:
|
||||||
|
|
||||||
test-x86_64-osx:
|
test-x86_64-osx:
|
||||||
runs-on: macos-11
|
runs-on: macos-11
|
||||||
|
timeout-minutes: 2
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: make & test tcc
|
- name: make & test tcc
|
||||||
|
@ -21,6 +23,7 @@ jobs:
|
||||||
|
|
||||||
test-x86_64-win32:
|
test-x86_64-win32:
|
||||||
runs-on: windows-2019
|
runs-on: windows-2019
|
||||||
|
timeout-minutes: 4
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: make & test tcc
|
- name: make & test tcc
|
||||||
|
@ -33,6 +36,7 @@ jobs:
|
||||||
|
|
||||||
test-armv7-linux:
|
test-armv7-linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: uraimo/run-on-arch-action@v2
|
- uses: uraimo/run-on-arch-action@v2
|
||||||
|
@ -49,6 +53,7 @@ jobs:
|
||||||
|
|
||||||
test-aarch64-linux:
|
test-aarch64-linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: uraimo/run-on-arch-action@v2
|
- uses: uraimo/run-on-arch-action@v2
|
||||||
|
@ -65,6 +70,7 @@ jobs:
|
||||||
|
|
||||||
test-riscv64-linux:
|
test-riscv64-linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: uraimo/run-on-arch-action@v2
|
- uses: uraimo/run-on-arch-action@v2
|
||||||
|
|
28
Makefile
28
Makefile
|
@ -29,6 +29,9 @@ ifdef CONFIG_WIN32
|
||||||
ifneq ($(CONFIG_static),yes)
|
ifneq ($(CONFIG_static),yes)
|
||||||
LIBTCC = libtcc$(DLLSUF)
|
LIBTCC = libtcc$(DLLSUF)
|
||||||
LIBTCCDEF = libtcc.def
|
LIBTCCDEF = libtcc.def
|
||||||
|
-LTCC = $(bindir)/libtcc.dll
|
||||||
|
else
|
||||||
|
-LTCC = -ltcc -L$(libdir)
|
||||||
endif
|
endif
|
||||||
ifneq ($(CONFIG_debug),yes)
|
ifneq ($(CONFIG_debug),yes)
|
||||||
LDFLAGS += -s
|
LDFLAGS += -s
|
||||||
|
@ -70,6 +73,7 @@ else
|
||||||
endif
|
endif
|
||||||
export MACOSX_DEPLOYMENT_TARGET := 10.6
|
export MACOSX_DEPLOYMENT_TARGET := 10.6
|
||||||
endif
|
endif
|
||||||
|
-LTCC = -ltcc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# run local version of tcc with local libraries and includes
|
# run local version of tcc with local libraries and includes
|
||||||
|
@ -79,6 +83,15 @@ TCCFLAGS = $(TCCFLAGS$(CFG))
|
||||||
TCC_LOCAL = $(TOP)/tcc$(EXESUF)
|
TCC_LOCAL = $(TOP)/tcc$(EXESUF)
|
||||||
TCC = $(TCC_LOCAL) $(TCCFLAGS)
|
TCC = $(TCC_LOCAL) $(TCCFLAGS)
|
||||||
|
|
||||||
|
# run tests with the installed tcc instead
|
||||||
|
ifdef TESTINSTALL
|
||||||
|
TCC_LOCAL = $(bindir)/tcc
|
||||||
|
TCCFLAGS-unx = -I..
|
||||||
|
TCCFLAGS-win = -I.. -B$(bindir)
|
||||||
|
LIBTCC =
|
||||||
|
LIBS += $(-LTCC)
|
||||||
|
endif
|
||||||
|
|
||||||
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
|
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
|
||||||
LIBS_P = $(LIBS)
|
LIBS_P = $(LIBS)
|
||||||
LDFLAGS_P = $(LDFLAGS)
|
LDFLAGS_P = $(LDFLAGS)
|
||||||
|
@ -373,7 +386,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2
|
||||||
IM = @echo "-> $2 : $1" ;
|
IM = @echo "-> $2 : $1" ;
|
||||||
BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
|
BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
|
||||||
|
|
||||||
B_O = bcheck.o bt-exe.o bt-log.o bt-dll.o
|
B_O = runmain.o bt-exe.o bt-dll.o bcheck.o
|
||||||
|
|
||||||
# install progs & libs
|
# install progs & libs
|
||||||
install-unx:
|
install-unx:
|
||||||
|
@ -411,7 +424,7 @@ install-win:
|
||||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
||||||
$(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
|
$(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
|
||||||
$(call IFw,$(TOPSRC)/libtcc.h libtcc.def,"$(libdir)")
|
$(call IFw,$(TOPSRC)/libtcc.h libtcc.def libtcc.a,"$(libdir)")
|
||||||
$(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
|
$(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
|
||||||
ifneq "$(wildcard $(LIBTCC1_U))" ""
|
ifneq "$(wildcard $(LIBTCC1_U))" ""
|
||||||
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
|
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
|
||||||
|
@ -420,9 +433,9 @@ endif
|
||||||
|
|
||||||
# uninstall on windows
|
# uninstall on windows
|
||||||
uninstall-win:
|
uninstall-win:
|
||||||
@rm -fv $(addprefix "$(bindir)/", libtcc*.dll $(PROGS) *-tcc.exe)
|
@rm -fv $(foreach P,libtcc*.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P)
|
||||||
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P/*")
|
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P/*)
|
||||||
@rm -frv $(addprefix "$(tccdir)/", doc examples include lib libtcc)
|
@rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P)
|
||||||
|
|
||||||
# the msys-git shell works to configure && make except it does not have install
|
# the msys-git shell works to configure && make except it does not have install
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@ -473,6 +486,9 @@ tcov-tes% : tcc_c$(EXESUF)
|
||||||
@$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
|
@$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
|
||||||
tcc_c$(EXESUF): $($T_FILES)
|
tcc_c$(EXESUF): $($T_FILES)
|
||||||
$S$(TCC) tcc.c -o $@ -ftest-coverage $(DEFINES) $(LIBS)
|
$S$(TCC) tcc.c -o $@ -ftest-coverage $(DEFINES) $(LIBS)
|
||||||
|
# test the installed tcc instead
|
||||||
|
test-install: tccdefs_.h
|
||||||
|
@$(MAKE) -C tests TESTINSTALL=yes #_all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f tcc$(EXESUF) tcc_c$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF)
|
@rm -f tcc$(EXESUF) tcc_c$(EXESUF) tcc_p$(EXESUF) *-tcc$(EXESUF)
|
||||||
|
@ -506,6 +522,8 @@ help:
|
||||||
@echo " run all/single test(s) from tests/pp"
|
@echo " run all/single test(s) from tests/pp"
|
||||||
@echo "make tcov-test / tcov-tests2... / tcov-testspp..."
|
@echo "make tcov-test / tcov-tests2... / tcov-testspp..."
|
||||||
@echo " run tests as above with code coverage. After test(s) see tcc_c$(EXESUF).tcov"
|
@echo " run tests as above with code coverage. After test(s) see tcc_c$(EXESUF).tcov"
|
||||||
|
@echo "make test-install"
|
||||||
|
@echo " run tests with the installed tcc"
|
||||||
@echo "Other supported make targets:"
|
@echo "Other supported make targets:"
|
||||||
@echo " install install-strip doc clean tags ETAGS tar distclean help"
|
@echo " install install-strip doc clean tags ETAGS tar distclean help"
|
||||||
@echo "Custom configuration:"
|
@echo "Custom configuration:"
|
||||||
|
|
|
@ -67,7 +67,8 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||||
OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
|
OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
|
||||||
|
|
||||||
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
|
OBJ-extra = $(filter-out bt-log.o,$(filter $(B_O),$(OBJ-$T)))
|
||||||
|
OBJ-extra += runmain.o
|
||||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||||
|
|
||||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
||||||
|
|
12
lib/bt-exe.c
12
lib/bt-exe.c
|
@ -26,14 +26,14 @@ void __bt_init(rt_context *p, int is_exe)
|
||||||
__bound_init(p->bounds_start, -1);
|
__bound_init(p->bounds_start, -1);
|
||||||
|
|
||||||
/* add to chain */
|
/* add to chain */
|
||||||
WAIT_SEM(&rt_sem);
|
rt_wait_sem();
|
||||||
p->next = g_rc, g_rc = p;
|
p->next = g_rc, g_rc = p;
|
||||||
if (is_exe)
|
rt_post_sem();
|
||||||
|
if (is_exe) {
|
||||||
/* we are the executable (not a dll) */
|
/* we are the executable (not a dll) */
|
||||||
p->top_func = main;
|
p->top_func = main;
|
||||||
POST_SEM(&rt_sem);
|
|
||||||
if (is_exe)
|
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(dllexport)
|
__declspec(dllexport)
|
||||||
|
@ -48,13 +48,13 @@ void __bt_exit(rt_context *p)
|
||||||
__bound_exit_dll(p->bounds_start);
|
__bound_exit_dll(p->bounds_start);
|
||||||
|
|
||||||
/* remove from chain */
|
/* remove from chain */
|
||||||
WAIT_SEM(&rt_sem);
|
rt_wait_sem();
|
||||||
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
||||||
if (rc == p) {
|
if (rc == p) {
|
||||||
*pp = rc->next;
|
*pp = rc->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
POST_SEM(&rt_sem);
|
rt_post_sem();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy a string and truncate it. */
|
/* copy a string and truncate it. */
|
||||||
|
|
|
@ -18,25 +18,24 @@
|
||||||
#pragma GCC diagnostic ignored "-Wframe-address"
|
#pragma GCC diagnostic ignored "-Wframe-address"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct rt_frame
|
typedef struct rt_frame {
|
||||||
{
|
|
||||||
void *ip, *fp, *sp;
|
void *ip, *fp, *sp;
|
||||||
} rt_frame;
|
} rt_frame;
|
||||||
|
|
||||||
__attribute__((weak))
|
__attribute__((weak))
|
||||||
int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
|
int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
|
||||||
|
|
||||||
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
|
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (_rt_error) {
|
if (__rt_dump) {
|
||||||
rt_frame f;
|
rt_frame f;
|
||||||
f.fp = __builtin_frame_address(1);
|
f.fp = __builtin_frame_address(1);
|
||||||
f.ip = __builtin_return_address(0);
|
f.ip = __builtin_return_address(0);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ret = _rt_error(&f, "", fmt, ap);
|
ret = __rt_dump(&f, NULL, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
} else {
|
} else {
|
||||||
const char *p, *nl = "\n";
|
const char *p, *nl = "\n";
|
||||||
|
|
87
lib/runmain.c
Normal file
87
lib/runmain.c
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
/* support for tcc_run() */
|
||||||
|
|
||||||
|
#ifdef __leading_underscore
|
||||||
|
# define _(s) s
|
||||||
|
#else
|
||||||
|
# define _(s) _##s
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
extern void (*_(_init_array_start)[]) (int argc, char **argv, char **envp);
|
||||||
|
extern void (*_(_init_array_end)[]) (int argc, char **argv, char **envp);
|
||||||
|
static void run_ctors(int argc, char **argv, char **env)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (&_(_init_array_start)[i] != _(_init_array_end))
|
||||||
|
(*_(_init_array_start)[i++])(argc, argv, env);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void (*_(_fini_array_start)[]) (void);
|
||||||
|
extern void (*_(_fini_array_end)[]) (void);
|
||||||
|
static void run_dtors(void)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (&_(_fini_array_end)[i] != _(_fini_array_start))
|
||||||
|
(*_(_fini_array_end)[--i])();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *rt_exitfunc[32];
|
||||||
|
static void *rt_exitarg[32];
|
||||||
|
int __rt_nr_exit;
|
||||||
|
|
||||||
|
void __run_on_exit(int ret)
|
||||||
|
{
|
||||||
|
int n = __rt_nr_exit;
|
||||||
|
while (n)
|
||||||
|
--n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int on_exit(void *function, void *arg)
|
||||||
|
{
|
||||||
|
int n = __rt_nr_exit;
|
||||||
|
if (n < 32) {
|
||||||
|
rt_exitfunc[n] = function;
|
||||||
|
rt_exitarg[n] = arg;
|
||||||
|
__rt_nr_exit = n + 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int atexit(void (*function)(void))
|
||||||
|
{
|
||||||
|
return on_exit(function, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct rt_frame {
|
||||||
|
void *ip, *fp, *sp;
|
||||||
|
} rt_frame;
|
||||||
|
|
||||||
|
void __rt_longjmp(rt_frame *, int);
|
||||||
|
|
||||||
|
void exit(int code)
|
||||||
|
{
|
||||||
|
rt_frame f;
|
||||||
|
run_dtors();
|
||||||
|
__run_on_exit(code);
|
||||||
|
f.fp = __builtin_frame_address(1);
|
||||||
|
f.ip = __builtin_return_address(0);
|
||||||
|
__rt_longjmp(&f, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
int main(int, char**, char**);
|
||||||
|
|
||||||
|
int _runmain(int argc, char **argv, char **envp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
__rt_nr_exit = 0;
|
||||||
|
run_ctors(argc, argv, envp);
|
||||||
|
ret = main(argc, argv, envp);
|
||||||
|
run_dtors();
|
||||||
|
__run_on_exit(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
11
libtcc.h
11
libtcc.h
|
@ -100,6 +100,17 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
|
||||||
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
||||||
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
||||||
|
|
||||||
|
/* experimental/advanced section (see libtcc_test_mt.c for an example) */
|
||||||
|
|
||||||
|
/* catch runtime exceptions (optionally limit backtraces at top_func),
|
||||||
|
when using tcc_set_options("-bt") and when not using tcc_run() */
|
||||||
|
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *longjmp, void *jmp_buf, void *top_func);
|
||||||
|
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, longjmp, jb, f))
|
||||||
|
|
||||||
|
/* set custom error printer for runtime exceptions */
|
||||||
|
typedef void TCCBtFunc(void *pc, const char *file, int line, const char* func);
|
||||||
|
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc*);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
4
tcc.h
4
tcc.h
|
@ -1000,6 +1000,10 @@ struct TCCState {
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
void *run_function_table; /* unwind data */
|
void *run_function_table; /* unwind data */
|
||||||
#endif
|
#endif
|
||||||
|
struct TCCState *next;
|
||||||
|
struct rt_context *rc; /* pointer to backtrace info block */
|
||||||
|
void *run_lj, *run_jb; /* sj/lj for tcc_setjmp()/tcc_run() */
|
||||||
|
void (*bt_func)(void *, const char*, int, const char*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
|
|
2
tccelf.c
2
tccelf.c
|
@ -1778,8 +1778,6 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||||
if (s1->do_backtrace) {
|
if (s1->do_backtrace) {
|
||||||
if (s1->output_type & TCC_OUTPUT_EXE)
|
if (s1->output_type & TCC_OUTPUT_EXE)
|
||||||
tcc_add_support(s1, "bt-exe.o");
|
tcc_add_support(s1, "bt-exe.o");
|
||||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
|
||||||
tcc_add_support(s1, "bt-log.o");
|
|
||||||
tcc_add_btstub(s1);
|
tcc_add_btstub(s1);
|
||||||
lpthread = 1;
|
lpthread = 1;
|
||||||
}
|
}
|
||||||
|
|
2
tccpe.c
2
tccpe.c
|
@ -1961,8 +1961,6 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||||
tcc_add_support(s1, "bt-exe.o");
|
tcc_add_support(s1, "bt-exe.o");
|
||||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||||
tcc_add_support(s1, "bt-dll.o");
|
tcc_add_support(s1, "bt-dll.o");
|
||||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
|
||||||
tcc_add_support(s1, "bt-log.o");
|
|
||||||
tcc_add_btstub(s1);
|
tcc_add_btstub(s1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
312
tccrun.c
312
tccrun.c
|
@ -26,7 +26,7 @@
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
typedef struct rt_context
|
typedef struct rt_context
|
||||||
{
|
{
|
||||||
/* --> tccelf.c:tcc_add_btstub wants those below in that order: */
|
/* tccelf.c:tcc_add_btstub() wants these in that order: */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
Stab_Sym *stab_sym;
|
Stab_Sym *stab_sym;
|
||||||
|
@ -42,55 +42,33 @@ typedef struct rt_context
|
||||||
ElfW(Sym) *esym_start;
|
ElfW(Sym) *esym_start;
|
||||||
ElfW(Sym) *esym_end;
|
ElfW(Sym) *esym_end;
|
||||||
char *elf_str;
|
char *elf_str;
|
||||||
|
// 6
|
||||||
addr_t prog_base;
|
addr_t prog_base;
|
||||||
void *bounds_start;
|
void *bounds_start;
|
||||||
void *top_func;
|
void *top_func;
|
||||||
TCCState *s1;
|
TCCState *s1;
|
||||||
struct rt_context *next;
|
struct rt_context *next;
|
||||||
|
// 11
|
||||||
int num_callers;
|
int num_callers;
|
||||||
int dwarf;
|
int dwarf;
|
||||||
/* <-- */
|
|
||||||
} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
|
} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
|
||||||
|
|
||||||
typedef struct rt_frame
|
typedef struct rt_frame {
|
||||||
{
|
|
||||||
addr_t ip, fp, sp;
|
addr_t ip, fp, sp;
|
||||||
} rt_frame;
|
} rt_frame;
|
||||||
|
|
||||||
/* linked list of rt_contexts */
|
/* linked list of rt_contexts */
|
||||||
static rt_context *g_rc;
|
static rt_context *g_rc;
|
||||||
|
static TCCState *g_s1;
|
||||||
/* semaphore to protect it */
|
/* semaphore to protect it */
|
||||||
TCC_SEM(static rt_sem);
|
TCC_SEM(static rt_sem);
|
||||||
static int signal_set;
|
static int signal_set;
|
||||||
static void set_exception_handler(void);
|
static void set_exception_handler(void);
|
||||||
|
static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
|
||||||
#ifdef _WIN32
|
static void rt_post_sem(void) { POST_SEM(&rt_sem); }
|
||||||
#define ATTR_WEAK
|
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
|
||||||
#else
|
|
||||||
#define ATTR_WEAK __attribute__((weak))
|
|
||||||
#endif
|
|
||||||
int ATTR_WEAK _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap);
|
|
||||||
void ATTR_WEAK rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
|
|
||||||
void ATTR_WEAK rt_post_sem(void) { POST_SEM(&rt_sem); }
|
|
||||||
#undef ATTR_WEAK
|
|
||||||
#endif /* def CONFIG_TCC_BACKTRACE */
|
#endif /* def CONFIG_TCC_BACKTRACE */
|
||||||
|
|
||||||
/* handle exit/atexit for tcc_run() -- thread-unsafe */
|
|
||||||
static jmp_buf rt_jb;
|
|
||||||
static int rt_do_jmp;
|
|
||||||
static int rt_nr_exit;
|
|
||||||
static void *rt_exitfunc[32];
|
|
||||||
static void *rt_exitarg[32];
|
|
||||||
|
|
||||||
static void rt_exit(int code)
|
|
||||||
{
|
|
||||||
if (rt_do_jmp)
|
|
||||||
longjmp(rt_jb, code ? code : 256);
|
|
||||||
exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/* defined when included from lib/bt-exe.c */
|
/* defined when included from lib/bt-exe.c */
|
||||||
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
||||||
|
@ -101,7 +79,8 @@ static void rt_exit(int code)
|
||||||
|
|
||||||
static int protect_pages(void *ptr, unsigned long length, int mode);
|
static int protect_pages(void *ptr, unsigned long length, int mode);
|
||||||
static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
|
static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff);
|
||||||
|
static int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap);
|
||||||
|
static void rt_longjmp(rt_frame *f, int code);
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
static void *win64_add_function_table(TCCState *s1);
|
static void *win64_add_function_table(TCCState *s1);
|
||||||
static void win64_del_function_table(void *);
|
static void win64_del_function_table(void *);
|
||||||
|
@ -118,12 +97,9 @@ static void bt_link(TCCState *s1)
|
||||||
rc = tcc_get_symbol(s1, "__rt_info");
|
rc = tcc_get_symbol(s1, "__rt_info");
|
||||||
if (!rc)
|
if (!rc)
|
||||||
return;
|
return;
|
||||||
rt_wait_sem();
|
|
||||||
rc->next = g_rc, g_rc = rc, rc->s1 = s1;
|
|
||||||
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
|
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
|
||||||
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
||||||
rc->elf_str = (char *)symtab_section->link->data;
|
rc->elf_str = (char *)symtab_section->link->data;
|
||||||
rc->top_func = tcc_get_symbol(s1, "main");
|
|
||||||
if (PTR_SIZE == 8 && !s1->dwarf)
|
if (PTR_SIZE == 8 && !s1->dwarf)
|
||||||
rc->prog_base &= 0xffffffff00000000ULL;
|
rc->prog_base &= 0xffffffff00000000ULL;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
|
@ -132,7 +108,7 @@ static void bt_link(TCCState *s1)
|
||||||
((void(*)(void*,int))p)(rc->bounds_start, 1);
|
((void(*)(void*,int))p)(rc->bounds_start, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
rt_post_sem();
|
rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc;
|
||||||
if (0 == signal_set)
|
if (0 == signal_set)
|
||||||
set_exception_handler(), signal_set = 1;
|
set_exception_handler(), signal_set = 1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -142,16 +118,35 @@ static void bt_unlink(TCCState *s1)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
rt_context *rc, **pp;
|
rt_context *rc, **pp;
|
||||||
rt_wait_sem();
|
|
||||||
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
||||||
if (rc->s1 == s1) {
|
if (rc->s1 == s1) {
|
||||||
*pp = rc->next;
|
*pp = rc->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rt_post_sem();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void st_link(TCCState *s1)
|
||||||
|
{
|
||||||
|
rt_wait_sem();
|
||||||
|
s1->next = g_s1, g_s1 = s1;
|
||||||
|
bt_link(s1);
|
||||||
|
rt_post_sem();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void st_unlink(TCCState *s1)
|
||||||
|
{
|
||||||
|
TCCState *s2, **pp;
|
||||||
|
rt_wait_sem();
|
||||||
|
bt_unlink(s1);
|
||||||
|
for (pp = &g_s1; s2 = *pp, s2; pp = &s2->next)
|
||||||
|
if (s2 == s1) {
|
||||||
|
*pp = s2->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rt_post_sem();
|
||||||
|
}
|
||||||
|
|
||||||
#if !_WIN32 && !__APPLE__
|
#if !_WIN32 && !__APPLE__
|
||||||
//#define HAVE_SELINUX 1
|
//#define HAVE_SELINUX 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -196,9 +191,8 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
|
||||||
exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
|
exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BACKTRACE
|
#ifdef CONFIG_TCC_BACKTRACE
|
||||||
/* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
|
if (s1->do_backtrace)
|
||||||
if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error"))
|
tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */
|
||||||
tcc_add_symbol(s1, "_rt_error", _rt_error);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size = tcc_relocate_ex(s1, NULL, 0);
|
size = tcc_relocate_ex(s1, NULL, 0);
|
||||||
|
@ -209,7 +203,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
|
||||||
return -1;
|
return -1;
|
||||||
ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
|
ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
bt_link(s1);
|
st_link(s1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,12 +225,11 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||||
}
|
}
|
||||||
/* free loaded dlls array */
|
/* free loaded dlls array */
|
||||||
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
|
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
|
||||||
|
|
||||||
/* unmap or unprotect and free memory */
|
/* unmap or unprotect and free memory */
|
||||||
ptr = s1->run_ptr;
|
ptr = s1->run_ptr;
|
||||||
if (NULL == ptr)
|
if (NULL == ptr)
|
||||||
return;
|
return;
|
||||||
bt_unlink(s1);
|
st_unlink(s1);
|
||||||
size = s1->run_size;
|
size = s1->run_size;
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
munmap(ptr, size * 2);
|
munmap(ptr, size * 2);
|
||||||
|
@ -250,41 +243,25 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_cdtors(TCCState *s1, const char *start, const char *end,
|
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func)
|
||||||
int argc, char **argv, char **envp)
|
|
||||||
{
|
{
|
||||||
void **a = (void **)get_sym_addr(s1, start, 0, 0);
|
s1->run_lj = p_longjmp;
|
||||||
void **b = (void **)get_sym_addr(s1, end, 0, 0);
|
s1->run_jb = p_jmp_buf;
|
||||||
while (a != b)
|
if (func && s1->rc)
|
||||||
((void(*)(int, char **, char **))*a++)(argc, argv, envp);
|
s1->rc->top_func = func;
|
||||||
|
return p_jmp_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_on_exit(int ret)
|
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, TCCBtFunc *func)
|
||||||
{
|
{
|
||||||
int n = rt_nr_exit;
|
s1->bt_func = func;
|
||||||
while (n)
|
|
||||||
--n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rt_on_exit(void *function, void *arg)
|
|
||||||
{
|
|
||||||
if (rt_nr_exit < countof(rt_exitfunc)) {
|
|
||||||
rt_exitfunc[rt_nr_exit] = function;
|
|
||||||
rt_exitarg[rt_nr_exit++] = arg;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rt_atexit(void *function)
|
|
||||||
{
|
|
||||||
return rt_on_exit(function, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* launch the compiled program with the given arguments */
|
/* launch the compiled program with the given arguments */
|
||||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
{
|
{
|
||||||
int (*prog_main)(int, char **, char **), ret;
|
int (*prog_main)(int, char **, char **), ret;
|
||||||
|
jmp_buf main_jb;
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
char **envp = NULL;
|
char **envp = NULL;
|
||||||
|
@ -295,35 +272,29 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
char **envp = environ;
|
char **envp = environ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s1->run_main = s1->nostdlib ? "_start" : "main";
|
/* tcc -dt -run ... nothing to do if no main() */
|
||||||
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1))
|
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
tcc_add_symbol(s1, "exit", rt_exit);
|
tcc_add_support(s1, "runmain.o");
|
||||||
tcc_add_symbol(s1, "atexit", rt_atexit);
|
tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp);
|
||||||
tcc_add_symbol(s1, "on_exit", rt_on_exit);
|
s1->run_main = (s1->nostdlib ? "_start" : "_runmain");
|
||||||
if (tcc_relocate(s1) < 0)
|
if (tcc_relocate(s1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
|
prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
|
||||||
if ((addr_t)-1 == (addr_t)prog_main)
|
if ((addr_t)-1 == (addr_t)prog_main)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
errno = 0; /* clean errno value */
|
errno = 0; /* clean errno value */
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
rt_do_jmp = 1;
|
|
||||||
rt_nr_exit = 0;
|
|
||||||
|
|
||||||
/* These aren't C symbols, so don't need leading underscore handling. */
|
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main"));
|
||||||
run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
|
|
||||||
ret = setjmp(rt_jb);
|
|
||||||
if (0 == ret)
|
if (0 == ret)
|
||||||
ret = prog_main(argc, argv, envp);
|
ret = prog_main(argc, argv, envp);
|
||||||
else if (256 == ret)
|
else if (256 == ret)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
run_cdtors(s1, "__fini_array_start", "__fini_array_end", 0, NULL, NULL);
|
|
||||||
run_on_exit(ret);
|
|
||||||
if (s1->dflag & 16 && ret) /* tcc -dt -run ... */
|
if (s1->dflag & 16 && ret) /* tcc -dt -run ... */
|
||||||
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
|
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -385,7 +356,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
|
||||||
addr_t mem, addr;
|
addr_t mem, addr;
|
||||||
|
|
||||||
if (NULL == ptr) {
|
if (NULL == ptr) {
|
||||||
s1->nb_errors = 0;
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
pe_output_file(s1, NULL);
|
pe_output_file(s1, NULL);
|
||||||
#else
|
#else
|
||||||
|
@ -616,7 +586,7 @@ static char *rt_elfsym(rt_context *rc, addr_t wanted_pc, addr_t *func_addr)
|
||||||
/* print the position in the source file of PC value 'pc' by reading
|
/* print the position in the source file of PC value 'pc' by reading
|
||||||
the stabs debug information */
|
the stabs debug information */
|
||||||
static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
|
static addr_t rt_printline (rt_context *rc, addr_t wanted_pc,
|
||||||
const char *msg, const char *skip)
|
rt_context** prc, const char *msg, const char *skip)
|
||||||
{
|
{
|
||||||
char func_name[128];
|
char func_name[128];
|
||||||
addr_t func_addr, last_pc, pc;
|
addr_t func_addr, last_pc, pc;
|
||||||
|
@ -726,14 +696,21 @@ next:
|
||||||
|
|
||||||
found:
|
found:
|
||||||
i = last_incl_index;
|
i = last_incl_index;
|
||||||
|
str = NULL;
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
str = incl_files[--i];
|
str = incl_files[--i];
|
||||||
if (skip[0] && strstr(str, skip))
|
if (skip[0] && strstr(str, skip))
|
||||||
return (addr_t)-1;
|
return (addr_t)-1;
|
||||||
|
}
|
||||||
|
if (rc && rc->s1 && rc->s1->bt_func) {
|
||||||
|
rc->s1->bt_func((void*)wanted_pc, str, last_line_num, func_name[0] ? func_name : NULL);
|
||||||
|
} else {
|
||||||
|
if (str)
|
||||||
rt_printf("%s:%d: ", str, last_line_num);
|
rt_printf("%s:%d: ", str, last_line_num);
|
||||||
} else
|
else
|
||||||
rt_printf("%08llx : ", (long long)wanted_pc);
|
rt_printf("%08llx : ", (long long)wanted_pc);
|
||||||
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
|
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
if (--i >= 0) {
|
if (--i >= 0) {
|
||||||
rt_printf(" (included from ");
|
rt_printf(" (included from ");
|
||||||
|
@ -746,6 +723,7 @@ found:
|
||||||
rt_printf(")");
|
rt_printf(")");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
*prc = rc;
|
||||||
return func_addr;
|
return func_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,7 +794,7 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
|
||||||
}
|
}
|
||||||
|
|
||||||
static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
||||||
const char *msg, const char *skip)
|
rt_context** prc, const char *msg, const char *skip)
|
||||||
{
|
{
|
||||||
unsigned char *ln;
|
unsigned char *ln;
|
||||||
unsigned char *cp;
|
unsigned char *cp;
|
||||||
|
@ -859,6 +837,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
||||||
next:
|
next:
|
||||||
filename = NULL;
|
filename = NULL;
|
||||||
func_addr = 0;
|
func_addr = 0;
|
||||||
|
line = 0;
|
||||||
if (NULL == rc)
|
if (NULL == rc)
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
|
@ -1102,6 +1081,9 @@ next_line:
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
|
if (rc && rc->s1 && rc->s1->bt_func) {
|
||||||
|
rc->s1->bt_func((void*)wanted_pc, filename, line, function);
|
||||||
|
} else {
|
||||||
if (filename) {
|
if (filename) {
|
||||||
if (skip[0] && strstr(filename, skip))
|
if (skip[0] && strstr(filename, skip))
|
||||||
return (addr_t)-1;
|
return (addr_t)-1;
|
||||||
|
@ -1110,21 +1092,22 @@ found:
|
||||||
else
|
else
|
||||||
rt_printf("0x%08llx : ", (long long)wanted_pc);
|
rt_printf("0x%08llx : ", (long long)wanted_pc);
|
||||||
rt_printf("%s %s", msg, function ? function : "???");
|
rt_printf("%s %s", msg, function ? function : "???");
|
||||||
|
}
|
||||||
|
*prc = rc;
|
||||||
return (addr_t)func_addr;
|
return (addr_t)func_addr;
|
||||||
}
|
}
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
||||||
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
|
static
|
||||||
|
#endif
|
||||||
int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)
|
int __rt_dump(rt_frame *f, const char *msg, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
rt_context *rc;
|
rt_context *rc, *rd;
|
||||||
addr_t pc = 0;
|
addr_t pc = 0;
|
||||||
char skip[100];
|
char skip[100];
|
||||||
int i, level, ret, n, one;
|
int i, level, ret, n, one;
|
||||||
const char *a, *b;
|
const char *a, *b;
|
||||||
addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
|
addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*);
|
||||||
addr_t top_func = 0;
|
|
||||||
|
|
||||||
skip[0] = 0;
|
skip[0] = 0;
|
||||||
/* If fmt is like "^file.c^..." then skip calls from 'file.c' */
|
/* 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)
|
||||||
printline = rt_printline_dwarf;
|
printline = rt_printline_dwarf;
|
||||||
if (rc->num_callers)
|
if (rc->num_callers)
|
||||||
n = rc->num_callers;
|
n = rc->num_callers;
|
||||||
top_func = (addr_t)rc->top_func;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = level = 0; level < n; i++) {
|
for (i = level = 0; level < n; i++) {
|
||||||
ret = rt_get_caller_pc(&pc, f, i);
|
ret = rt_get_caller_pc(&pc, f, i);
|
||||||
a = "%s";
|
|
||||||
if (ret != -1) {
|
if (ret != -1) {
|
||||||
pc = printline(rc, pc, level ? "by" : "at", skip);
|
pc = printline(rc, pc, &rd, level ? "by" : "at", skip);
|
||||||
if (pc == (addr_t)-1)
|
if (pc == (addr_t)-1)
|
||||||
continue;
|
continue;
|
||||||
a = ": %s";
|
|
||||||
}
|
}
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
rt_printf(a, msg);
|
if (rd && rd->s1 && rd->s1->bt_func)
|
||||||
|
break;
|
||||||
|
if (ret != -1)
|
||||||
|
rt_printf(": ");
|
||||||
|
if (msg)
|
||||||
|
rt_printf("%s: ", msg);
|
||||||
rt_vprintf(fmt, ap);
|
rt_vprintf(fmt, ap);
|
||||||
} else if (ret == -1)
|
} else if (ret == -1)
|
||||||
break;
|
break;
|
||||||
if (one)
|
if (one)
|
||||||
break;
|
break;
|
||||||
rt_printf("\n");
|
rt_printf("\n");
|
||||||
if (ret == -1 || (pc == top_func && pc))
|
if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc))
|
||||||
break;
|
break;
|
||||||
++level;
|
++level;
|
||||||
}
|
}
|
||||||
|
@ -1180,11 +1164,46 @@ static int rt_error(rt_frame *f, const char *fmt, ...)
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
|
ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TCCState *rt_find_state(rt_frame *f)
|
||||||
|
{
|
||||||
|
TCCState *s;
|
||||||
|
int level;
|
||||||
|
addr_t pc;
|
||||||
|
|
||||||
|
rt_wait_sem();
|
||||||
|
for (s = g_s1; s; s = s->next) {
|
||||||
|
if (0 == s->run_lj)
|
||||||
|
continue;
|
||||||
|
for (level = 0; level < 8; ++level) {
|
||||||
|
if (rt_get_caller_pc(&pc, f, level) < 0)
|
||||||
|
break;
|
||||||
|
if (pc >= (addr_t)s->run_ptr
|
||||||
|
&& pc < (addr_t)s->run_ptr + s->run_size)
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
rt_post_sem();
|
||||||
|
//fprintf(stderr, "\nrt_state found %s %p %p\n", s ? "YES" : "NO", s, s->rc->top_func), fflush(stderr);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rt_longjmp(rt_frame *f, int code)
|
||||||
|
{
|
||||||
|
TCCState *s = rt_find_state(f);
|
||||||
|
if (s && s->run_lj) {
|
||||||
|
if (code == 0)
|
||||||
|
code = 256;
|
||||||
|
((void(*)(void*,int))s->run_lj)(s->run_jb, code);
|
||||||
|
}
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -1319,7 +1338,8 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||||
rt_error(&f, "caught signal %d", signum);
|
rt_error(&f, "caught signal %d", signum);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rt_exit(255);
|
set_exception_handler();
|
||||||
|
rt_longjmp(&f, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SA_SIGINFO
|
#ifndef SA_SIGINFO
|
||||||
|
@ -1333,7 +1353,7 @@ static void set_exception_handler(void)
|
||||||
/* install TCC signal handlers to print debug info on fatal
|
/* install TCC signal handlers to print debug info on fatal
|
||||||
runtime errors */
|
runtime errors */
|
||||||
sigemptyset (&sigact.sa_mask);
|
sigemptyset (&sigact.sa_mask);
|
||||||
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER;
|
||||||
#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
|
#if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
|
||||||
sigact.sa_flags |= SA_ONSTACK;
|
sigact.sa_flags |= SA_ONSTACK;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1365,7 +1385,6 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||||
{
|
{
|
||||||
rt_frame f;
|
rt_frame f;
|
||||||
unsigned code;
|
unsigned code;
|
||||||
|
|
||||||
rt_getcontext(ex_info->ContextRecord, &f);
|
rt_getcontext(ex_info->ContextRecord, &f);
|
||||||
|
|
||||||
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
|
switch (code = ex_info->ExceptionRecord->ExceptionCode) {
|
||||||
|
@ -1387,8 +1406,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||||
rt_error(&f, "caught exception %08x", code);
|
rt_error(&f, "caught exception %08x", code);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rt_do_jmp)
|
rt_longjmp(&f, 255);
|
||||||
rt_exit(255);
|
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1405,45 +1423,41 @@ static void set_exception_handler(void)
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||||
{
|
{
|
||||||
addr_t ip, fp;
|
|
||||||
if (level == 0) {
|
|
||||||
ip = rc->ip;
|
|
||||||
} else {
|
|
||||||
ip = 0;
|
|
||||||
fp = rc->fp;
|
|
||||||
while (--level) {
|
|
||||||
/* XXX: check address validity with program info */
|
|
||||||
if (fp <= 0x1000)
|
|
||||||
break;
|
|
||||||
fp = ((addr_t *)fp)[0];
|
|
||||||
}
|
|
||||||
if (fp > 0x1000)
|
|
||||||
ip = ((addr_t *)fp)[1];
|
|
||||||
}
|
|
||||||
if (ip <= 0x1000)
|
|
||||||
return -1;
|
|
||||||
*paddr = ip;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(__arm__)
|
|
||||||
static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
|
||||||
{
|
|
||||||
/* XXX: only supports linux/bsd */
|
|
||||||
#if !defined(__linux__) && \
|
|
||||||
!defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
|
|
||||||
return -1;
|
|
||||||
#else
|
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
*paddr = rc->ip;
|
*paddr = rc->ip;
|
||||||
} else {
|
} else {
|
||||||
addr_t fp = rc->fp;
|
addr_t fp = rc->fp;
|
||||||
while (--level)
|
while (1) {
|
||||||
|
if (fp < 0x1000)
|
||||||
|
return -1;
|
||||||
|
if (0 == --level)
|
||||||
|
break;
|
||||||
|
/* XXX: check address validity with program info */
|
||||||
fp = ((addr_t *)fp)[0];
|
fp = ((addr_t *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((addr_t *)fp)[1];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: only supports linux/bsd */
|
||||||
|
#elif defined(__arm__) && !defined(_WIN32)
|
||||||
|
static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||||
|
{
|
||||||
|
if (level == 0) {
|
||||||
|
*paddr = rc->ip;
|
||||||
|
} else {
|
||||||
|
addr_t fp = rc->fp;
|
||||||
|
while (1) {
|
||||||
|
if (fp < 0x1000)
|
||||||
|
return -1;
|
||||||
|
if (0 == --level)
|
||||||
|
break;
|
||||||
|
fp = ((addr_t *)fp)[0];
|
||||||
|
}
|
||||||
*paddr = ((addr_t *)fp)[2];
|
*paddr = ((addr_t *)fp)[2];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
@ -1452,10 +1466,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
*paddr = rc->ip;
|
*paddr = rc->ip;
|
||||||
} else {
|
} else {
|
||||||
addr_t *fp = (addr_t*)rc->fp;
|
addr_t fp = rc->fp;
|
||||||
while (--level)
|
while (1) {
|
||||||
fp = (addr_t *)fp[0];
|
if (fp < 0x1000)
|
||||||
*paddr = fp[1];
|
return -1;
|
||||||
|
if (0 == --level)
|
||||||
|
break;
|
||||||
|
fp = ((addr_t *)fp)[0];
|
||||||
|
}
|
||||||
|
*paddr = ((addr_t *)fp)[1];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1466,12 +1485,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
*paddr = rc->ip;
|
*paddr = rc->ip;
|
||||||
} else {
|
} else {
|
||||||
addr_t *fp = (addr_t*)rc->fp;
|
addr_t fp = rc->fp;
|
||||||
while (--level && fp >= (addr_t*)0x1000)
|
while (1) {
|
||||||
fp = (addr_t *)fp[-2];
|
if (fp < 0x1000)
|
||||||
if (fp < (addr_t*)0x1000)
|
|
||||||
return -1;
|
return -1;
|
||||||
*paddr = fp[-1];
|
if (0 == --level)
|
||||||
|
break;
|
||||||
|
fp = ((addr_t *)fp)[-2];
|
||||||
|
}
|
||||||
|
*paddr = ((addr_t *)fp)[-1];
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,23 +14,20 @@ TESTS = \
|
||||||
libtest \
|
libtest \
|
||||||
libtest_mt \
|
libtest_mt \
|
||||||
test3 \
|
test3 \
|
||||||
memtest \
|
|
||||||
dlltest \
|
|
||||||
abitest \
|
abitest \
|
||||||
asm-c-connect-test \
|
asm-c-connect-test \
|
||||||
vla_test-run \
|
vla_test-run \
|
||||||
cross-test \
|
|
||||||
tests2-dir \
|
tests2-dir \
|
||||||
pp-dir
|
pp-dir \
|
||||||
|
memtest \
|
||||||
|
dlltest \
|
||||||
|
cross-test
|
||||||
|
|
||||||
# test4_static -- Not all relocation types are implemented yet.
|
# test4_static -- Not all relocation types are implemented yet.
|
||||||
# asmtest / asmtest2 -- minor differences with gcc
|
# asmtest / asmtest2 -- minor differences with gcc
|
||||||
|
|
||||||
ifneq ($(CONFIG_bcheck),no)
|
ifneq ($(CONFIG_bcheck),no)
|
||||||
TESTS += btest test1b
|
TESTS += btest test1b tccb
|
||||||
ifndef CONFIG_WIN32
|
|
||||||
TESTS += tccb
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
ifeq ($(CONFIG_dll),no)
|
ifeq ($(CONFIG_dll),no)
|
||||||
TESTS := $(filter-out dlltest, $(TESTS))
|
TESTS := $(filter-out dlltest, $(TESTS))
|
||||||
|
@ -82,7 +79,9 @@ all test :
|
||||||
@echo ------------ version ------------
|
@echo ------------ version ------------
|
||||||
@$(TCC_LOCAL) -v
|
@$(TCC_LOCAL) -v
|
||||||
@$(MAKE) --no-print-directory -s clean
|
@$(MAKE) --no-print-directory -s clean
|
||||||
@$(MAKE) --no-print-directory -s -r $(TESTS)
|
@$(MAKE) --no-print-directory -s -r _all
|
||||||
|
|
||||||
|
_all : $(TESTS)
|
||||||
|
|
||||||
hello-exe: ../examples/ex1.c
|
hello-exe: ../examples/ex1.c
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
|
@ -199,14 +198,15 @@ btest: boundtest.c
|
||||||
echo "Test $$i failed as expected" ; \
|
echo "Test $$i failed as expected" ; \
|
||||||
fi ;\
|
fi ;\
|
||||||
done ;\
|
done ;\
|
||||||
echo Bound test OK
|
echo Bound-Test OK
|
||||||
|
|
||||||
tccb:
|
tccb:
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
|
$(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
|
||||||
mv v1-tcc$(EXESUF) v2-tcc$(EXESUF)
|
mv tccb1.exe tccb2.exe
|
||||||
./v2-tcc$(EXESUF) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
|
./tccb2.exe -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
|
||||||
cmp -s v1-tcc$(EXESUF) v2-tcc$(EXESUF) && echo "Bound-Test tcc OK"
|
cmp -s tccb1.exe tccb2.exe && echo "Exe Bound-Rest OK"
|
||||||
|
|
||||||
|
|
||||||
# speed test
|
# speed test
|
||||||
speedtest: ex2 ex3
|
speedtest: ex2 ex3
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <setjmp.h>
|
||||||
#include "libtcc.h"
|
#include "libtcc.h"
|
||||||
|
|
||||||
#define M 20 /* number of states */
|
#define M 20 /* number of states */
|
||||||
|
@ -84,6 +85,8 @@ PROG(my_program)
|
||||||
"\n"
|
"\n"
|
||||||
"int foo(int n)\n"
|
"int foo(int n)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
" if (n >= N_CRASH && n < N_CRASH + 3)\n"
|
||||||
|
" *(void**)0 = 0;\n"
|
||||||
" printf(\" %d\", fib(n));\n"
|
" printf(\" %d\", fib(n));\n"
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"# warning is this the correct file:line...\n"
|
"# warning is this the correct file:line...\n"
|
||||||
|
@ -110,6 +113,11 @@ void parse_args(TCCState *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bt_func(void *pc, const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
printf(" *** at %s:%d in '%s'\n", file, line, func);
|
||||||
|
}
|
||||||
|
|
||||||
TCCState *new_state(int w)
|
TCCState *new_state(int w)
|
||||||
{
|
{
|
||||||
TCCState *s = tcc_new();
|
TCCState *s = tcc_new();
|
||||||
|
@ -119,7 +127,14 @@ TCCState *new_state(int w)
|
||||||
}
|
}
|
||||||
tcc_set_error_func(s, stdout, handle_error);
|
tcc_set_error_func(s, stdout, handle_error);
|
||||||
parse_args(s);
|
parse_args(s);
|
||||||
if (!w) tcc_set_options(s, "-w");
|
if (0 == (w & 1))
|
||||||
|
tcc_set_options(s, "-w");
|
||||||
|
if (w & 2) {
|
||||||
|
tcc_set_options(s, "-bt");
|
||||||
|
tcc_define_symbol(s, "N_CRASH", str(M/2));
|
||||||
|
tcc_set_backtrace_func(s, bt_func);
|
||||||
|
} else
|
||||||
|
tcc_define_symbol(s, "N_CRASH", "99");
|
||||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -139,23 +154,28 @@ void *reloc_state(TCCState *s, const char *entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* work with several states at the same time */
|
/* work with several states at the same time */
|
||||||
int state_test(void)
|
int state_test(int w)
|
||||||
{
|
{
|
||||||
TCCState *s[M];
|
TCCState *s[M];
|
||||||
int (*func[M])(int);
|
int (*funcs[M])(int);
|
||||||
int n;
|
int n;
|
||||||
|
jmp_buf jb;
|
||||||
|
|
||||||
for (n = 0; n < M + 4; ++n) {
|
for (n = 0; n < M + 4; ++n) {
|
||||||
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
|
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
|
||||||
if (a < M)
|
if (a < M)
|
||||||
s[a] = new_state(0);
|
s[a] = new_state(w);
|
||||||
if (b < M)
|
if (b < M)
|
||||||
if (tcc_compile_string(s[b], my_program) == -1)
|
if (tcc_compile_string(s[b], my_program) == -1)
|
||||||
break;
|
break;
|
||||||
if (c < M)
|
if (c < M)
|
||||||
func[c] = reloc_state(s[c], "foo");
|
funcs[c] = reloc_state(s[c], "foo");
|
||||||
if (d < M && func[d])
|
if (d < M && funcs[d]) {
|
||||||
func[d](F(d));
|
if ((w & 2) && d == 8)
|
||||||
|
printf("\n");
|
||||||
|
if (0 == tcc_setjmp(s[d], jb, funcs[d]))
|
||||||
|
funcs[d](F(d));
|
||||||
|
}
|
||||||
if (e < M)
|
if (e < M)
|
||||||
tcc_delete(s[e]);
|
tcc_delete(s[e]);
|
||||||
}
|
}
|
||||||
|
@ -257,7 +277,13 @@ int main(int argc, char **argv)
|
||||||
#if 1
|
#if 1
|
||||||
printf("running fib with mixed calls\n "), fflush(stdout);
|
printf("running fib with mixed calls\n "), fflush(stdout);
|
||||||
t = getclock_ms();
|
t = getclock_ms();
|
||||||
state_test();
|
state_test(0);
|
||||||
|
printf("\n (%u ms)\n", getclock_ms() - t);
|
||||||
|
#endif
|
||||||
|
#if 1
|
||||||
|
printf("producing some exceptions\n "), fflush(stdout);
|
||||||
|
t = getclock_ms();
|
||||||
|
state_test(2);
|
||||||
printf("\n (%u ms)\n", getclock_ms() - t);
|
printf("\n (%u ms)\n", getclock_ms() - t);
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
|
|
|
@ -4,6 +4,11 @@ int atexit(void (*function)(void));
|
||||||
int on_exit(void (*function)(int, void *), void *arg);
|
int on_exit(void (*function)(int, void *), void *arg);
|
||||||
void exit(int status);
|
void exit(int status);
|
||||||
|
|
||||||
|
void __attribute((constructor)) startup5(void)
|
||||||
|
{
|
||||||
|
printf ("startup5\n");
|
||||||
|
}
|
||||||
|
|
||||||
void cleanup1(void)
|
void cleanup1(void)
|
||||||
{
|
{
|
||||||
printf ("cleanup1\n");
|
printf ("cleanup1\n");
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
[test_128_return]
|
[test_128_return]
|
||||||
|
startup5
|
||||||
cleanup5
|
cleanup5
|
||||||
1 cleanup4
|
1 cleanup4
|
||||||
1 cleanup3
|
1 cleanup3
|
||||||
|
@ -7,6 +8,7 @@ cleanup1
|
||||||
[returns 1]
|
[returns 1]
|
||||||
|
|
||||||
[test_128_exit]
|
[test_128_exit]
|
||||||
|
startup5
|
||||||
cleanup5
|
cleanup5
|
||||||
2 cleanup4
|
2 cleanup4
|
||||||
2 cleanup3
|
2 cleanup3
|
||||||
|
|
|
@ -37,15 +37,6 @@ extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
|
||||||
|
|
||||||
#include "crtinit.c"
|
#include "crtinit.c"
|
||||||
|
|
||||||
static int do_main (int argc, _TCHAR * argv[], _TCHAR * env[])
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
run_ctors(argc, argv, env);
|
|
||||||
retval = _tmain(__argc, __targv, _tenviron);
|
|
||||||
run_dtors();
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
|
/* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
|
||||||
int _dowildcard;
|
int _dowildcard;
|
||||||
|
|
||||||
|
@ -56,6 +47,8 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
|
||||||
|
|
||||||
void _tstart(void)
|
void _tstart(void)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
_startupinfo start_info = {0};
|
_startupinfo start_info = {0};
|
||||||
SetUnhandledExceptionFilter(catch_sig);
|
SetUnhandledExceptionFilter(catch_sig);
|
||||||
// Sets the current application type
|
// Sets the current application type
|
||||||
|
@ -68,11 +61,21 @@ void _tstart(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
|
__tgetmainargs( &__argc, &__targv, &_tenviron, _dowildcard, &start_info);
|
||||||
exit(do_main(__argc, __targv, _tenviron));
|
run_ctors(__argc, __targv, _tenviron);
|
||||||
|
ret = _tmain(__argc, __targv, _tenviron);
|
||||||
|
run_dtors();
|
||||||
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =============================================
|
||||||
|
// for 'tcc -run ,,,'
|
||||||
|
|
||||||
|
__attribute__((weak)) extern int __rt_nr_exit;
|
||||||
|
__attribute__((weak)) extern int __run_on_exit();
|
||||||
|
|
||||||
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
#ifdef UNICODE
|
#ifdef UNICODE
|
||||||
_startupinfo start_info = {0};
|
_startupinfo start_info = {0};
|
||||||
|
|
||||||
|
@ -89,7 +92,12 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||||
#if defined __i386__ || defined __x86_64__
|
#if defined __i386__ || defined __x86_64__
|
||||||
_controlfp(_PC_53, _MCW_PC);
|
_controlfp(_PC_53, _MCW_PC);
|
||||||
#endif
|
#endif
|
||||||
return _tmain(__argc, __targv, _tenviron);
|
__rt_nr_exit = 0;
|
||||||
|
run_ctors(__argc, __targv, _tenviron);
|
||||||
|
ret = _tmain(__argc, __targv, _tenviron);
|
||||||
|
run_dtors();
|
||||||
|
__run_on_exit(ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
Loading…
Reference in a new issue