mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-24 03:40:09 +08:00
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
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -7,6 +7,7 @@ on:
|
||||
jobs:
|
||||
test-x86_64-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
@ -14,6 +15,7 @@ jobs:
|
||||
|
||||
test-x86_64-osx:
|
||||
runs-on: macos-11
|
||||
timeout-minutes: 2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
@ -21,6 +23,7 @@ jobs:
|
||||
|
||||
test-x86_64-win32:
|
||||
runs-on: windows-2019
|
||||
timeout-minutes: 4
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc
|
||||
@ -33,6 +36,7 @@ jobs:
|
||||
|
||||
test-armv7-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
@ -49,6 +53,7 @@ jobs:
|
||||
|
||||
test-aarch64-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
@ -65,6 +70,7 @@ jobs:
|
||||
|
||||
test-riscv64-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
|
28
Makefile
28
Makefile
@ -29,6 +29,9 @@ ifdef CONFIG_WIN32
|
||||
ifneq ($(CONFIG_static),yes)
|
||||
LIBTCC = libtcc$(DLLSUF)
|
||||
LIBTCCDEF = libtcc.def
|
||||
-LTCC = $(bindir)/libtcc.dll
|
||||
else
|
||||
-LTCC = -ltcc -L$(libdir)
|
||||
endif
|
||||
ifneq ($(CONFIG_debug),yes)
|
||||
LDFLAGS += -s
|
||||
@ -70,6 +73,7 @@ else
|
||||
endif
|
||||
export MACOSX_DEPLOYMENT_TARGET := 10.6
|
||||
endif
|
||||
-LTCC = -ltcc
|
||||
endif
|
||||
|
||||
# run local version of tcc with local libraries and includes
|
||||
@ -79,6 +83,15 @@ TCCFLAGS = $(TCCFLAGS$(CFG))
|
||||
TCC_LOCAL = $(TOP)/tcc$(EXESUF)
|
||||
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
|
||||
LIBS_P = $(LIBS)
|
||||
LDFLAGS_P = $(LDFLAGS)
|
||||
@ -373,7 +386,7 @@ IR = $(IM) mkdir -p $2 && cp -r $1/. $2
|
||||
IM = @echo "-> $2 : $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-unx:
|
||||
@ -411,7 +424,7 @@ install-win:
|
||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/examples,"$(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)")
|
||||
ifneq "$(wildcard $(LIBTCC1_U))" ""
|
||||
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
|
||||
@ -420,9 +433,9 @@ endif
|
||||
|
||||
# uninstall on windows
|
||||
uninstall-win:
|
||||
@rm -fv $(addprefix "$(bindir)/", libtcc*.dll $(PROGS) *-tcc.exe)
|
||||
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)/$P/*")
|
||||
@rm -frv $(addprefix "$(tccdir)/", doc examples include lib libtcc)
|
||||
@rm -fv $(foreach P,libtcc*.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P)
|
||||
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P/*)
|
||||
@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
|
||||
ifeq ($(OS),Windows_NT)
|
||||
@ -473,6 +486,9 @@ tcov-tes% : tcc_c$(EXESUF)
|
||||
@$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
|
||||
tcc_c$(EXESUF): $($T_FILES)
|
||||
$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:
|
||||
@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 "make tcov-test / tcov-tests2... / tcov-testspp..."
|
||||
@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 " install install-strip doc clean tags ETAGS tar distclean help"
|
||||
@echo "Custom configuration:"
|
||||
|
@ -67,7 +67,8 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_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)))
|
||||
|
||||
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);
|
||||
|
||||
/* add to chain */
|
||||
WAIT_SEM(&rt_sem);
|
||||
rt_wait_sem();
|
||||
p->next = g_rc, g_rc = p;
|
||||
if (is_exe)
|
||||
rt_post_sem();
|
||||
if (is_exe) {
|
||||
/* we are the executable (not a dll) */
|
||||
p->top_func = main;
|
||||
POST_SEM(&rt_sem);
|
||||
if (is_exe)
|
||||
set_exception_handler();
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(dllexport)
|
||||
@ -48,13 +48,13 @@ void __bt_exit(rt_context *p)
|
||||
__bound_exit_dll(p->bounds_start);
|
||||
|
||||
/* remove from chain */
|
||||
WAIT_SEM(&rt_sem);
|
||||
rt_wait_sem();
|
||||
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
||||
if (rc == p) {
|
||||
*pp = rc->next;
|
||||
break;
|
||||
}
|
||||
POST_SEM(&rt_sem);
|
||||
rt_post_sem();
|
||||
}
|
||||
|
||||
/* copy a string and truncate it. */
|
||||
|
@ -18,25 +18,24 @@
|
||||
#pragma GCC diagnostic ignored "-Wframe-address"
|
||||
#endif
|
||||
|
||||
typedef struct rt_frame
|
||||
{
|
||||
typedef struct rt_frame {
|
||||
void *ip, *fp, *sp;
|
||||
} rt_frame;
|
||||
|
||||
__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, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
if (_rt_error) {
|
||||
if (__rt_dump) {
|
||||
rt_frame f;
|
||||
f.fp = __builtin_frame_address(1);
|
||||
f.ip = __builtin_return_address(0);
|
||||
va_start(ap, fmt);
|
||||
ret = _rt_error(&f, "", fmt, ap);
|
||||
ret = __rt_dump(&f, NULL, fmt, ap);
|
||||
va_end(ap);
|
||||
} else {
|
||||
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,
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
4
tcc.h
4
tcc.h
@ -1000,6 +1000,10 @@ struct TCCState {
|
||||
#ifdef _WIN64
|
||||
void *run_function_table; /* unwind data */
|
||||
#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
|
||||
|
||||
#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->output_type & TCC_OUTPUT_EXE)
|
||||
tcc_add_support(s1, "bt-exe.o");
|
||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-log.o");
|
||||
tcc_add_btstub(s1);
|
||||
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");
|
||||
if (s1->output_type == TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-dll.o");
|
||||
if (s1->output_type != TCC_OUTPUT_DLL)
|
||||
tcc_add_support(s1, "bt-log.o");
|
||||
tcc_add_btstub(s1);
|
||||
}
|
||||
#endif
|
||||
|
334
tccrun.c
334
tccrun.c
@ -26,7 +26,7 @@
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
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 {
|
||||
struct {
|
||||
Stab_Sym *stab_sym;
|
||||
@ -42,55 +42,33 @@ typedef struct rt_context
|
||||
ElfW(Sym) *esym_start;
|
||||
ElfW(Sym) *esym_end;
|
||||
char *elf_str;
|
||||
|
||||
// 6
|
||||
addr_t prog_base;
|
||||
void *bounds_start;
|
||||
void *top_func;
|
||||
TCCState *s1;
|
||||
struct rt_context *next;
|
||||
|
||||
// 11
|
||||
int num_callers;
|
||||
int dwarf;
|
||||
/* <-- */
|
||||
} rt_context; /* size = 11 * PTR_SIZE + 2 * sizeof (int) */
|
||||
|
||||
typedef struct rt_frame
|
||||
{
|
||||
typedef struct rt_frame {
|
||||
addr_t ip, fp, sp;
|
||||
} rt_frame;
|
||||
|
||||
/* linked list of rt_contexts */
|
||||
static rt_context *g_rc;
|
||||
static TCCState *g_s1;
|
||||
/* semaphore to protect it */
|
||||
TCC_SEM(static rt_sem);
|
||||
static int signal_set;
|
||||
static void set_exception_handler(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ATTR_WEAK
|
||||
#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
|
||||
static void rt_wait_sem(void) { WAIT_SEM(&rt_sem); }
|
||||
static void rt_post_sem(void) { POST_SEM(&rt_sem); }
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
|
||||
#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 */
|
||||
#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 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
|
||||
static void *win64_add_function_table(TCCState *s1);
|
||||
static void win64_del_function_table(void *);
|
||||
@ -118,12 +97,9 @@ static void bt_link(TCCState *s1)
|
||||
rc = tcc_get_symbol(s1, "__rt_info");
|
||||
if (!rc)
|
||||
return;
|
||||
rt_wait_sem();
|
||||
rc->next = g_rc, g_rc = rc, rc->s1 = s1;
|
||||
rc->esym_start = (ElfW(Sym) *)(symtab_section->data);
|
||||
rc->esym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
|
||||
rc->elf_str = (char *)symtab_section->link->data;
|
||||
rc->top_func = tcc_get_symbol(s1, "main");
|
||||
if (PTR_SIZE == 8 && !s1->dwarf)
|
||||
rc->prog_base &= 0xffffffff00000000ULL;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
@ -132,7 +108,7 @@ static void bt_link(TCCState *s1)
|
||||
((void(*)(void*,int))p)(rc->bounds_start, 1);
|
||||
}
|
||||
#endif
|
||||
rt_post_sem();
|
||||
rc->next = g_rc, g_rc = rc, rc->s1 = s1, s1->rc = rc;
|
||||
if (0 == signal_set)
|
||||
set_exception_handler(), signal_set = 1;
|
||||
#endif
|
||||
@ -142,16 +118,35 @@ static void bt_unlink(TCCState *s1)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
rt_context *rc, **pp;
|
||||
rt_wait_sem();
|
||||
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
||||
if (rc->s1 == s1) {
|
||||
*pp = rc->next;
|
||||
break;
|
||||
}
|
||||
rt_post_sem();
|
||||
#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__
|
||||
//#define HAVE_SELINUX 1
|
||||
#endif
|
||||
@ -196,9 +191,8 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
|
||||
exit(tcc_error_noabort("'tcc_relocate()' twice is no longer supported"));
|
||||
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
/* for bt-log.c (but not when 'tcc -bt -run tcc.c') */
|
||||
if (s1->do_backtrace && !tcc_get_symbol(s1, "_rt_error"))
|
||||
tcc_add_symbol(s1, "_rt_error", _rt_error);
|
||||
if (s1->do_backtrace)
|
||||
tcc_add_symbol(s1, "__rt_dump", __rt_dump); /* for bt-log.c */
|
||||
#endif
|
||||
|
||||
size = tcc_relocate_ex(s1, NULL, 0);
|
||||
@ -209,7 +203,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1)
|
||||
return -1;
|
||||
ret = tcc_relocate_ex(s1, s1->run_ptr, ptr_diff);
|
||||
if (ret == 0)
|
||||
bt_link(s1);
|
||||
st_link(s1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -231,12 +225,11 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
}
|
||||
/* free loaded dlls array */
|
||||
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
|
||||
|
||||
/* unmap or unprotect and free memory */
|
||||
ptr = s1->run_ptr;
|
||||
if (NULL == ptr)
|
||||
return;
|
||||
bt_unlink(s1);
|
||||
st_unlink(s1);
|
||||
size = s1->run_size;
|
||||
#ifdef HAVE_SELINUX
|
||||
munmap(ptr, size * 2);
|
||||
@ -250,41 +243,25 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void run_cdtors(TCCState *s1, const char *start, const char *end,
|
||||
int argc, char **argv, char **envp)
|
||||
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *p_longjmp, void *p_jmp_buf, void *func)
|
||||
{
|
||||
void **a = (void **)get_sym_addr(s1, start, 0, 0);
|
||||
void **b = (void **)get_sym_addr(s1, end, 0, 0);
|
||||
while (a != b)
|
||||
((void(*)(int, char **, char **))*a++)(argc, argv, envp);
|
||||
s1->run_lj = p_longjmp;
|
||||
s1->run_jb = p_jmp_buf;
|
||||
if (func && s1->rc)
|
||||
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;
|
||||
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);
|
||||
s1->bt_func = func;
|
||||
}
|
||||
|
||||
/* launch the compiled program with the given arguments */
|
||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
int (*prog_main)(int, char **, char **), ret;
|
||||
jmp_buf main_jb;
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
char **envp = NULL;
|
||||
@ -295,35 +272,29 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
char **envp = environ;
|
||||
#endif
|
||||
|
||||
s1->run_main = s1->nostdlib ? "_start" : "main";
|
||||
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, s1->run_main, 0, 1))
|
||||
/* tcc -dt -run ... nothing to do if no main() */
|
||||
if ((s1->dflag & 16) && (addr_t)-1 == get_sym_addr(s1, "main", 0, 1))
|
||||
return 0;
|
||||
|
||||
tcc_add_symbol(s1, "exit", rt_exit);
|
||||
tcc_add_symbol(s1, "atexit", rt_atexit);
|
||||
tcc_add_symbol(s1, "on_exit", rt_on_exit);
|
||||
tcc_add_support(s1, "runmain.o");
|
||||
tcc_add_symbol(s1, "__rt_longjmp", rt_longjmp);
|
||||
s1->run_main = (s1->nostdlib ? "_start" : "_runmain");
|
||||
if (tcc_relocate(s1) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = (void*)get_sym_addr(s1, s1->run_main, 1, 1);
|
||||
if ((addr_t)-1 == (addr_t)prog_main)
|
||||
return -1;
|
||||
|
||||
errno = 0; /* clean errno value */
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
rt_do_jmp = 1;
|
||||
rt_nr_exit = 0;
|
||||
|
||||
/* These aren't C symbols, so don't need leading underscore handling. */
|
||||
run_cdtors(s1, "__init_array_start", "__init_array_end", argc, argv, envp);
|
||||
ret = setjmp(rt_jb);
|
||||
ret = tcc_setjmp(s1, main_jb, tcc_get_symbol(s1, "main"));
|
||||
if (0 == ret)
|
||||
ret = prog_main(argc, argv, envp);
|
||||
else if (256 == ret)
|
||||
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 ... */
|
||||
fprintf(s1->ppfp, "[returns %d]\n", ret), fflush(s1->ppfp);
|
||||
return ret;
|
||||
@ -385,7 +356,6 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
|
||||
addr_t mem, addr;
|
||||
|
||||
if (NULL == ptr) {
|
||||
s1->nb_errors = 0;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pe_output_file(s1, NULL);
|
||||
#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
|
||||
the stabs debug information */
|
||||
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];
|
||||
addr_t func_addr, last_pc, pc;
|
||||
@ -726,14 +696,21 @@ next:
|
||||
|
||||
found:
|
||||
i = last_incl_index;
|
||||
str = NULL;
|
||||
if (i > 0) {
|
||||
str = incl_files[--i];
|
||||
if (skip[0] && strstr(str, skip))
|
||||
return (addr_t)-1;
|
||||
rt_printf("%s:%d: ", str, last_line_num);
|
||||
} else
|
||||
rt_printf("%08llx : ", (long long)wanted_pc);
|
||||
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
|
||||
}
|
||||
if (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);
|
||||
else
|
||||
rt_printf("%08llx : ", (long long)wanted_pc);
|
||||
rt_printf("%s %s", msg, func_name[0] ? func_name : "???");
|
||||
}
|
||||
#if 0
|
||||
if (--i >= 0) {
|
||||
rt_printf(" (included from ");
|
||||
@ -746,6 +723,7 @@ found:
|
||||
rt_printf(")");
|
||||
}
|
||||
#endif
|
||||
*prc = rc;
|
||||
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,
|
||||
const char *msg, const char *skip)
|
||||
rt_context** prc, const char *msg, const char *skip)
|
||||
{
|
||||
unsigned char *ln;
|
||||
unsigned char *cp;
|
||||
@ -859,6 +837,7 @@ static addr_t rt_printline_dwarf (rt_context *rc, addr_t wanted_pc,
|
||||
next:
|
||||
filename = NULL;
|
||||
func_addr = 0;
|
||||
line = 0;
|
||||
if (NULL == rc)
|
||||
goto found;
|
||||
|
||||
@ -1102,29 +1081,33 @@ next_line:
|
||||
goto next;
|
||||
|
||||
found:
|
||||
if (filename) {
|
||||
if (skip[0] && strstr(filename, skip))
|
||||
return (addr_t)-1;
|
||||
rt_printf("%s:%d: ", filename, line);
|
||||
if (rc && rc->s1 && rc->s1->bt_func) {
|
||||
rc->s1->bt_func((void*)wanted_pc, filename, line, function);
|
||||
} else {
|
||||
if (filename) {
|
||||
if (skip[0] && strstr(filename, skip))
|
||||
return (addr_t)-1;
|
||||
rt_printf("%s:%d: ", filename, line);
|
||||
}
|
||||
else
|
||||
rt_printf("0x%08llx : ", (long long)wanted_pc);
|
||||
rt_printf("%s %s", msg, function ? function : "???");
|
||||
}
|
||||
else
|
||||
rt_printf("0x%08llx : ", (long long)wanted_pc);
|
||||
rt_printf("%s %s", msg, function ? function : "???");
|
||||
*prc = rc;
|
||||
return (addr_t)func_addr;
|
||||
}
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_frame *f, int level);
|
||||
|
||||
int _rt_error(rt_frame *f, const char *msg, const char *fmt, va_list ap)
|
||||
#ifndef CONFIG_TCC_BACKTRACE_ONLY
|
||||
static
|
||||
#endif
|
||||
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;
|
||||
char skip[100];
|
||||
int i, level, ret, n, one;
|
||||
const char *a, *b;
|
||||
addr_t (*printline)(rt_context*, addr_t, const char*, const char*);
|
||||
addr_t top_func = 0;
|
||||
addr_t (*printline)(rt_context*, addr_t, rt_context**, const char*, const char*);
|
||||
|
||||
skip[0] = 0;
|
||||
/* 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;
|
||||
if (rc->num_callers)
|
||||
n = rc->num_callers;
|
||||
top_func = (addr_t)rc->top_func;
|
||||
}
|
||||
|
||||
for (i = level = 0; level < n; i++) {
|
||||
ret = rt_get_caller_pc(&pc, f, i);
|
||||
a = "%s";
|
||||
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)
|
||||
continue;
|
||||
a = ": %s";
|
||||
}
|
||||
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);
|
||||
} else if (ret == -1)
|
||||
break;
|
||||
if (one)
|
||||
break;
|
||||
rt_printf("\n");
|
||||
if (ret == -1 || (pc == top_func && pc))
|
||||
if (ret == -1 || (rd && pc == (addr_t)rd->top_func && pc))
|
||||
break;
|
||||
++level;
|
||||
}
|
||||
@ -1180,11 +1164,46 @@ static int rt_error(rt_frame *f, const char *fmt, ...)
|
||||
va_list ap;
|
||||
int ret;
|
||||
va_start(ap, fmt);
|
||||
ret = _rt_error(f, "RUNTIME ERROR: ", fmt, ap);
|
||||
ret = __rt_dump(f, "RUNTIME ERROR", fmt, ap);
|
||||
va_end(ap);
|
||||
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
|
||||
@ -1319,7 +1338,8 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
||||
rt_error(&f, "caught signal %d", signum);
|
||||
break;
|
||||
}
|
||||
rt_exit(255);
|
||||
set_exception_handler();
|
||||
rt_longjmp(&f, 255);
|
||||
}
|
||||
|
||||
#ifndef SA_SIGINFO
|
||||
@ -1333,7 +1353,7 @@ static void set_exception_handler(void)
|
||||
/* install TCC signal handlers to print debug info on fatal
|
||||
runtime errors */
|
||||
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
|
||||
sigact.sa_flags |= SA_ONSTACK;
|
||||
#endif
|
||||
@ -1365,7 +1385,6 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
|
||||
{
|
||||
rt_frame f;
|
||||
unsigned code;
|
||||
|
||||
rt_getcontext(ex_info->ContextRecord, &f);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
if (rt_do_jmp)
|
||||
rt_exit(255);
|
||||
rt_longjmp(&f, 255);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
@ -1405,45 +1423,41 @@ static void set_exception_handler(void)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
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) {
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
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];
|
||||
}
|
||||
*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];
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
@ -1452,10 +1466,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||
if (level == 0) {
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
addr_t *fp = (addr_t*)rc->fp;
|
||||
while (--level)
|
||||
fp = (addr_t *)fp[0];
|
||||
*paddr = fp[1];
|
||||
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)[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1466,12 +1485,15 @@ static int rt_get_caller_pc(addr_t *paddr, rt_frame *rc, int level)
|
||||
if (level == 0) {
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
addr_t *fp = (addr_t*)rc->fp;
|
||||
while (--level && fp >= (addr_t*)0x1000)
|
||||
fp = (addr_t *)fp[-2];
|
||||
if (fp < (addr_t*)0x1000)
|
||||
return -1;
|
||||
*paddr = fp[-1];
|
||||
addr_t fp = rc->fp;
|
||||
while (1) {
|
||||
if (fp < 0x1000)
|
||||
return -1;
|
||||
if (0 == --level)
|
||||
break;
|
||||
fp = ((addr_t *)fp)[-2];
|
||||
}
|
||||
*paddr = ((addr_t *)fp)[-1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,23 +14,20 @@ TESTS = \
|
||||
libtest \
|
||||
libtest_mt \
|
||||
test3 \
|
||||
memtest \
|
||||
dlltest \
|
||||
abitest \
|
||||
asm-c-connect-test \
|
||||
vla_test-run \
|
||||
cross-test \
|
||||
tests2-dir \
|
||||
pp-dir
|
||||
pp-dir \
|
||||
memtest \
|
||||
dlltest \
|
||||
cross-test
|
||||
|
||||
# test4_static -- Not all relocation types are implemented yet.
|
||||
# asmtest / asmtest2 -- minor differences with gcc
|
||||
|
||||
ifneq ($(CONFIG_bcheck),no)
|
||||
TESTS += btest test1b
|
||||
ifndef CONFIG_WIN32
|
||||
TESTS += tccb
|
||||
endif
|
||||
TESTS += btest test1b tccb
|
||||
endif
|
||||
ifeq ($(CONFIG_dll),no)
|
||||
TESTS := $(filter-out dlltest, $(TESTS))
|
||||
@ -82,7 +79,9 @@ all test :
|
||||
@echo ------------ version ------------
|
||||
@$(TCC_LOCAL) -v
|
||||
@$(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
|
||||
@echo ------------ $@ ------------
|
||||
@ -199,14 +198,15 @@ btest: boundtest.c
|
||||
echo "Test $$i failed as expected" ; \
|
||||
fi ;\
|
||||
done ;\
|
||||
echo Bound test OK
|
||||
echo Bound-Test OK
|
||||
|
||||
tccb:
|
||||
@echo ------------ $@ ------------
|
||||
$(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
|
||||
mv v1-tcc$(EXESUF) v2-tcc$(EXESUF)
|
||||
./v2-tcc$(EXESUF) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o v1-tcc$(EXESUF)
|
||||
cmp -s v1-tcc$(EXESUF) v2-tcc$(EXESUF) && echo "Bound-Test tcc OK"
|
||||
$(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
|
||||
mv tccb1.exe tccb2.exe
|
||||
./tccb2.exe -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(NATIVE_DEFINES) -o tccb1.exe
|
||||
cmp -s tccb1.exe tccb2.exe && echo "Exe Bound-Rest OK"
|
||||
|
||||
|
||||
# speed test
|
||||
speedtest: ex2 ex3
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include "libtcc.h"
|
||||
|
||||
#define M 20 /* number of states */
|
||||
@ -84,6 +85,8 @@ PROG(my_program)
|
||||
"\n"
|
||||
"int foo(int n)\n"
|
||||
"{\n"
|
||||
" if (n >= N_CRASH && n < N_CRASH + 3)\n"
|
||||
" *(void**)0 = 0;\n"
|
||||
" printf(\" %d\", fib(n));\n"
|
||||
" return 0;\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 *s = tcc_new();
|
||||
@ -119,7 +127,14 @@ TCCState *new_state(int w)
|
||||
}
|
||||
tcc_set_error_func(s, stdout, handle_error);
|
||||
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);
|
||||
return s;
|
||||
}
|
||||
@ -139,23 +154,28 @@ void *reloc_state(TCCState *s, const char *entry)
|
||||
}
|
||||
|
||||
/* work with several states at the same time */
|
||||
int state_test(void)
|
||||
int state_test(int w)
|
||||
{
|
||||
TCCState *s[M];
|
||||
int (*func[M])(int);
|
||||
int (*funcs[M])(int);
|
||||
int n;
|
||||
jmp_buf jb;
|
||||
|
||||
for (n = 0; n < M + 4; ++n) {
|
||||
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
|
||||
if (a < M)
|
||||
s[a] = new_state(0);
|
||||
s[a] = new_state(w);
|
||||
if (b < M)
|
||||
if (tcc_compile_string(s[b], my_program) == -1)
|
||||
break;
|
||||
if (c < M)
|
||||
func[c] = reloc_state(s[c], "foo");
|
||||
if (d < M && func[d])
|
||||
func[d](F(d));
|
||||
funcs[c] = reloc_state(s[c], "foo");
|
||||
if (d < M && funcs[d]) {
|
||||
if ((w & 2) && d == 8)
|
||||
printf("\n");
|
||||
if (0 == tcc_setjmp(s[d], jb, funcs[d]))
|
||||
funcs[d](F(d));
|
||||
}
|
||||
if (e < M)
|
||||
tcc_delete(s[e]);
|
||||
}
|
||||
@ -257,7 +277,13 @@ int main(int argc, char **argv)
|
||||
#if 1
|
||||
printf("running fib with mixed calls\n "), fflush(stdout);
|
||||
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);
|
||||
#endif
|
||||
#if 1
|
||||
|
@ -4,6 +4,11 @@ int atexit(void (*function)(void));
|
||||
int on_exit(void (*function)(int, void *), void *arg);
|
||||
void exit(int status);
|
||||
|
||||
void __attribute((constructor)) startup5(void)
|
||||
{
|
||||
printf ("startup5\n");
|
||||
}
|
||||
|
||||
void cleanup1(void)
|
||||
{
|
||||
printf ("cleanup1\n");
|
||||
|
@ -1,4 +1,5 @@
|
||||
[test_128_return]
|
||||
startup5
|
||||
cleanup5
|
||||
1 cleanup4
|
||||
1 cleanup3
|
||||
@ -7,6 +8,7 @@ cleanup1
|
||||
[returns 1]
|
||||
|
||||
[test_128_exit]
|
||||
startup5
|
||||
cleanup5
|
||||
2 cleanup4
|
||||
2 cleanup3
|
||||
|
@ -37,15 +37,6 @@ extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
|
||||
|
||||
#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 */
|
||||
int _dowildcard;
|
||||
|
||||
@ -56,6 +47,8 @@ static LONG WINAPI catch_sig(EXCEPTION_POINTERS *ex)
|
||||
|
||||
void _tstart(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
_startupinfo start_info = {0};
|
||||
SetUnhandledExceptionFilter(catch_sig);
|
||||
// Sets the current application type
|
||||
@ -68,11 +61,21 @@ void _tstart(void)
|
||||
#endif
|
||||
|
||||
__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 ret;
|
||||
#ifdef UNICODE
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
@ -89,7 +92,12 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
_controlfp(_PC_53, _MCW_PC);
|
||||
#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 New Issue
Block a user