From d79e1dee8cfc9ddc68810be5af0d68670362094a Mon Sep 17 00:00:00 2001 From: grischka Date: Sun, 19 Jan 2020 11:15:12 +0100 Subject: [PATCH] backtrace: test with DLLs - tests2/113_btdll.c: test handling multiple stabs infos Also: - libtcc.c: remove _ISOC99_SOURCE pre-defines. It is causing strange warnings such as 'strdup not declared' - i386/x86_64-gen.c cleanup bounds_pro/epilog. This discards the extra code for main's argv. If needed, __argv might be processed instead. - tccgen.c:block(): reduce stackspace usage. For example with code like "if (..) ... else if (..) ... else if (..)... " considerable numbers of nested block() calls may occur. Before that most stack space used when compiling itself was for libtcc.c:tcc_set_linker(). Now it's rather this construct at tccpp.c:2765: in next_nomacro1(): if (!((isidnum_table[c - CH_EOF] & (IS_ID|IS_NUM)) || c == '.' || ((c == '+' || c == '-') ... --- i386-gen.c | 87 ++++++++--------- lib/bcheck.c | 3 +- libtcc.c | 10 -- tcc.h | 3 + tccelf.c | 4 + tccgen.c | 52 +++++----- tccrun.c | 10 +- tests/tests2/112_backtrace.expect | 22 ----- tests/tests2/113_btdll.c | 43 +++++++++ tests/tests2/113_btdll.expect | 6 ++ tests/tests2/Makefile | 31 +++--- win32/build-tcc.bat | 2 +- x86_64-gen.c | 154 +++++++++++------------------- 13 files changed, 209 insertions(+), 218 deletions(-) create mode 100644 tests/tests2/113_btdll.c create mode 100644 tests/tests2/113_btdll.expect diff --git a/i386-gen.c b/i386-gen.c index 7e1e0f49..8016af94 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -97,6 +97,8 @@ static int func_ret_sub; #ifdef CONFIG_TCC_BCHECK static addr_t func_bound_offset; static unsigned long func_bound_ind; +static void gen_bounds_prolog(void); +static void gen_bounds_epilog(void); #endif /* XXX: make it faster ? */ @@ -480,6 +482,7 @@ ST_FUNC void gfunc_call(int nb_args) else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT) args_size -= 4; #endif + gcall_or_jmp(0); if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW) @@ -499,7 +502,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) CType *func_type = &func_sym->type; int addr, align, size, func_call, fastcall_nb_regs; int param_index, param_addr; - int n_arg = 0; uint8_t *fastcall_regs_ptr; Sym *sym; CType *type; @@ -542,7 +544,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) } /* define parameters */ while ((sym = sym->next) != NULL) { - n_arg++; type = &sym->type; size = type_size(type, &align); size = (size + 3) & ~3; @@ -576,19 +577,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym) #endif #ifdef CONFIG_TCC_BCHECK - /* leave some room for bound checking code */ - if (tcc_state->do_bounds_check) { - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - oad(0xb8, 0); /* lbound section pointer */ - oad(0xb8, 0); /* call to function */ - if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) { - o(0x0c458b); /* mov 0x12(%ebp),%eax */ - o(0x50); /* push %eax */ - gen_static_call(TOK___bound_main_arg); - o(0x04c483); /* add $0x4,%esp */ - } - } + if (tcc_state->do_bounds_check) + gen_bounds_prolog(); #endif } @@ -598,34 +588,8 @@ ST_FUNC void gfunc_epilog(void) addr_t v, saved_ind; #ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check - && func_bound_offset != lbounds_section->data_offset) { - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - /* generate bound local allocation */ - saved_ind = ind; - ind = func_bound_ind; - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); - greloc(cur_text_section, sym_data, - ind + 1, R_386_32); - oad(0xb8, 0); /* mov %eax, xxx */ - gen_static_call(TOK___bound_local_new); - ind = saved_ind; - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - greloc(cur_text_section, sym_data, ind + 1, R_386_32); - oad(0xb8, 0); /* mov %eax, xxx */ - gen_static_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ - } + if (tcc_state->do_bounds_check) + gen_bounds_epilog(); #endif /* align local size to word & save local variables */ @@ -1096,6 +1060,43 @@ ST_FUNC void gen_bounded_ptr_deref(void) rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); } + +static void gen_bounds_prolog(void) +{ + /* leave some room for bound checking code */ + func_bound_offset = lbounds_section->data_offset; + func_bound_ind = ind; + oad(0xb8, 0); /* lbound section pointer */ + oad(0xb8, 0); /* call to function */ +} + +static void gen_bounds_epilog(void) +{ + addr_t saved_ind; + addr_t *bounds_ptr; + Sym *sym_data; + + /* add end of table info */ + bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); + *bounds_ptr = 0; + + /* generate bound local allocation */ + saved_ind = ind; + ind = func_bound_ind; + sym_data = get_sym_ref(&char_pointer_type, lbounds_section, + func_bound_offset, lbounds_section->data_offset); + greloc(cur_text_section, sym_data, ind + 1, R_386_32); + ind = ind + 5; + gen_static_call(TOK___bound_local_new); + ind = saved_ind; + + /* generate bound check local freeing */ + o(0x5250); /* save returned value, if any */ + greloc(cur_text_section, sym_data, ind + 1, R_386_32); + oad(0xb8, 0); /* mov %eax, xxx */ + gen_static_call(TOK___bound_local_delete); + o(0x585a); /* restore returned value, if any */ +} #endif /* Save the stack pointer onto the stack */ diff --git a/lib/bcheck.c b/lib/bcheck.c index 1e90aa9a..14cec509 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -353,7 +353,8 @@ void * __bound_ptr_add(void *p, size_t offset) if (addr <= tree->size) { if (tree->is_invalid || addr + offset > tree->size) { POST_SEM (); - bound_warning("%p is outside of the region", p + offset); + if (print_warn_ptr_add) + bound_warning("%p is outside of the region", p + offset); if (never_fatal <= 0) return INVALID_POINTER; /* return an invalid pointer */ return p + offset; diff --git a/libtcc.c b/libtcc.c index a7882196..fdbe2e7f 100644 --- a/libtcc.c +++ b/libtcc.c @@ -802,11 +802,6 @@ LIBTCCAPI TCCState *tcc_new(void) tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); tcc_define_symbol(s, "__STDC_HOSTED__", NULL); -#if !defined(TCC_TARGET_PE) - /* glibc compatible macro (default for C99) */ - tcc_define_symbol(s, "_ISOC99_SOURCE", "1"); -#endif - /* target defines */ #if defined(TCC_TARGET_I386) tcc_define_symbol(s, "__i386__", NULL); @@ -1905,11 +1900,6 @@ reparse: * encoding used is implementationdeļ¬ned. */ tcc_define_symbol(s, "__STDC_UTF_32__", "1"); - /* - * glibc compatible macro used when -std=c11 is used. - * _ISOC99_SOURCE remains defined as does gcc. - */ - tcc_define_symbol(s, "_ISOC11_SOURCE", "1"); #endif /* !TCC_TARGET_PE */ s->cversion = 201112; } diff --git a/tcc.h b/tcc.h index ce05d975..435795f4 100644 --- a/tcc.h +++ b/tcc.h @@ -884,6 +884,9 @@ struct TCCState { const char *runtime_main; void **runtime_mem; int nb_runtime_mem; +#endif + +#ifdef CONFIG_TCC_BACKTRACE int rt_num_callers; #endif diff --git a/tccelf.c b/tccelf.c index 6c919d97..fe00a30f 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1387,7 +1387,11 @@ ST_FUNC void tcc_add_btstub(TCCState *s1) "__attribute__((constructor)) static void __bt_init_rt(){"); #ifdef TCC_TARGET_PE if (s1->output_type == TCC_OUTPUT_DLL) +#ifdef CONFIG_TCC_BCHECK cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check); +#else + cstr_printf(&cstr, "__bt_init_dll(0);"); +#endif #endif cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); diff --git a/tccgen.c b/tccgen.c index 71d3d04d..047332b8 100644 --- a/tccgen.c +++ b/tccgen.c @@ -101,6 +101,8 @@ ST_DATA struct switch_t { int def_sym; /* default symbol */ int *bsym; struct scope *scope; + struct switch_t *prev; + SValue sv; } *cur_switch; /* current switch */ #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 @@ -6447,6 +6449,7 @@ static void lblock(int *bsym, int *csym) static void block(int is_expr) { int a, b, c, d, e, t; + struct scope o; Sym *s; if (is_expr) { @@ -6487,7 +6490,6 @@ again: gsym(a); } else if (t == '{') { - struct scope o; new_scope(&o); /* handle local labels declarations */ @@ -6545,10 +6547,10 @@ again: /* compute jump */ if (!cur_scope->bsym) tcc_error("cannot break"); - if (!cur_switch || cur_scope->bsym != cur_switch->bsym) - leave_scope(loop_scope); - else + if (cur_switch && cur_scope->bsym == cur_switch->bsym) leave_scope(cur_switch->scope); + else + leave_scope(loop_scope); *cur_scope->bsym = gjmp(*cur_scope->bsym); skip(';'); @@ -6561,7 +6563,6 @@ again: skip(';'); } else if (t == TOK_FOR) { - struct scope o; new_scope(&o); skip('('); @@ -6611,22 +6612,18 @@ again: gsym(a); } else if (t == TOK_SWITCH) { - struct switch_t *saved, sw; - SValue switchval; + struct switch_t *sw; - sw.p = NULL; - sw.n = 0; - sw.def_sym = 0; - sw.bsym = &a; - sw.scope = cur_scope; - - saved = cur_switch; - cur_switch = &sw; + sw = tcc_mallocz(sizeof *sw); + sw->bsym = &a; + sw->scope = cur_scope; + sw->prev = cur_switch; + cur_switch = sw; skip('('); gexpr(); skip(')'); - switchval = *vtop--; + sw->sv = *vtop--; /* save switch value */ a = 0; b = gjmp(0); /* jump to first case */ @@ -6635,28 +6632,29 @@ again: /* case lookup */ gsym(b); - qsort(sw.p, sw.n, sizeof(void*), case_cmp); - for (b = 1; b < sw.n; b++) - if (sw.p[b - 1]->v2 >= sw.p[b]->v1) + qsort(sw->p, sw->n, sizeof(void*), case_cmp); + for (b = 1; b < sw->n; b++) + if (sw->p[b - 1]->v2 >= sw->p[b]->v1) tcc_error("duplicate case value"); /* Our switch table sorting is signed, so the compared value needs to be as well when it's 64bit. */ - if ((switchval.type.t & VT_BTYPE) == VT_LLONG) - switchval.type.t &= ~VT_UNSIGNED; - vpushv(&switchval); + vpushv(&sw->sv); + if ((vtop->type.t & VT_BTYPE) == VT_LLONG) + vtop->type.t &= ~VT_UNSIGNED; gv(RC_INT); - d = 0, gcase(sw.p, sw.n, &d); + d = 0, gcase(sw->p, sw->n, &d); vpop(); - if (sw.def_sym) - gsym_addr(d, sw.def_sym); + if (sw->def_sym) + gsym_addr(d, sw->def_sym); else gsym(d); /* break label */ gsym(a); - dynarray_reset(&sw.p, &sw.n); - cur_switch = saved; + dynarray_reset(&sw->p, &sw->n); + cur_switch = sw->prev; + tcc_free(sw); } else if (t == TOK_CASE) { struct case_t *cr = tcc_malloc(sizeof(struct case_t)); diff --git a/tccrun.c b/tccrun.c index 6460bcca..4bf709d6 100644 --- a/tccrun.c +++ b/tccrun.c @@ -48,7 +48,7 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap); static void rt_exit(int code); #endif /* CONFIG_TCC_BACKTRACE */ -/* defined when included from lib/bt.c */ +/* defined when included from lib/bt-exe.c */ #ifndef CONFIG_TCC_BACKTRACE_ONLY #ifndef _WIN32 @@ -412,15 +412,15 @@ next: /* Stab_Sym.n_value is only 32bits */ pc += rc->prog_base; #endif - break; + goto check_pc; rel_pc: pc += func_addr; + check_pc: + if (pc >= wanted_pc && wanted_pc >= last_pc) + goto found; break; } - if (pc >= wanted_pc && wanted_pc >= last_pc) - goto found; - switch(sym->n_type) { /* function start or end */ case N_FUN: diff --git a/tests/tests2/112_backtrace.expect b/tests/tests2/112_backtrace.expect index f7829083..68986c6e 100644 --- a/tests/tests2/112_backtrace.expect +++ b/tests/tests2/112_backtrace.expect @@ -12,8 +12,6 @@ [test_bcheck_1] * main * f1() -112_backtrace.c:38: at f1: BCHECK: ........ is outside of the region -112_backtrace.c:43: by main 112_backtrace.c:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest 112_backtrace.c:43: by main [returns 255] @@ -32,12 +30,10 @@ [returns 1] [test_bcheck_100] -112_backtrace.c:107: at main: BCHECK: ........ is outside of the region 112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest [returns 255] [test_bcheck_101] -112_backtrace.c:109: at main: BCHECK: ........ is outside of the region 112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src [returns 255] @@ -50,42 +46,34 @@ [returns 255] [test_bcheck_104] -112_backtrace.c:115: at main: BCHECK: ........ is outside of the region 112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1 [returns 255] [test_bcheck_105] -112_backtrace.c:117: at main: BCHECK: ........ is outside of the region 112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2 [returns 255] [test_bcheck_106] -112_backtrace.c:119: at main: BCHECK: ........ is outside of the region 112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest [returns 255] [test_bcheck_107] -112_backtrace.c:121: at main: BCHECK: ........ is outside of the region 112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src [returns 255] [test_bcheck_108] -112_backtrace.c:123: at main: BCHECK: ........ is outside of the region 112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset [returns 255] [test_bcheck_109] -112_backtrace.c:125: at main: BCHECK: ........ is outside of the region 112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen [returns 255] [test_bcheck_110] -112_backtrace.c:127: at main: BCHECK: ........ is outside of the region 112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest [returns 255] [test_bcheck_111] -112_backtrace.c:129: at main: BCHECK: ........ is outside of the region 112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src [returns 255] @@ -98,12 +86,10 @@ [returns 255] [test_bcheck_114] -112_backtrace.c:135: at main: BCHECK: ........ is outside of the region 112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest [returns 255] [test_bcheck_115] -112_backtrace.c:137: at main: BCHECK: ........ is outside of the region 112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src [returns 255] @@ -116,32 +102,26 @@ [returns 255] [test_bcheck_118] -112_backtrace.c:143: at main: BCHECK: ........ is outside of the region 112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1 [returns 255] [test_bcheck_119] -112_backtrace.c:145: at main: BCHECK: ........ is outside of the region 112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2 [returns 255] [test_bcheck_120] -112_backtrace.c:147: at main: BCHECK: ........ is outside of the region 112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1 [returns 255] [test_bcheck_121] -112_backtrace.c:149: at main: BCHECK: ........ is outside of the region 112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2 [returns 255] [test_bcheck_122] -112_backtrace.c:151: at main: BCHECK: ........ is outside of the region 112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest [returns 255] [test_bcheck_123] -112_backtrace.c:153: at main: BCHECK: ........ is outside of the region 112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest [returns 255] @@ -154,11 +134,9 @@ [returns 255] [test_bcheck_126] -112_backtrace.c:159: at main: BCHECK: ........ is outside of the region 112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr [returns 255] [test_bcheck_127] -112_backtrace.c:161: at main: BCHECK: ........ is outside of the region 112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup [returns 255] diff --git a/tests/tests2/113_btdll.c b/tests/tests2/113_btdll.c new file mode 100644 index 00000000..8ae89816 --- /dev/null +++ b/tests/tests2/113_btdll.c @@ -0,0 +1,43 @@ +int tcc_backtrace(const char*, ...); +#define hello() \ + tcc_backtrace("hello from %s() / %s:%d",__FUNCTION__,__FILE__,__LINE__) + +#ifndef _WIN32 +# define __declspec(n) +#endif + +#if DLL==1 +__declspec(dllexport) int f_1() +{ + hello(); + return 0; +} + + +#elif DLL==2 +__declspec(dllexport) int f_2() +{ + hello(); + return 0; +} + + +#else + +int f_1(); +int f_2(); +int f_main() +{ + hello(); + return 0; +} + +int main () +{ + f_1(); + f_2(); + f_main(); + return 0; +} + +#endif diff --git a/tests/tests2/113_btdll.expect b/tests/tests2/113_btdll.expect new file mode 100644 index 00000000..34de4811 --- /dev/null +++ b/tests/tests2/113_btdll.expect @@ -0,0 +1,6 @@ +113_btdll.c:12: at f_1: hello from f_1() / 113_btdll.c:12 +113_btdll.c:37: by main +113_btdll.c:20: at f_2: hello from f_2() / 113_btdll.c:20 +113_btdll.c:38: by main +113_btdll.c:31: at f_main: hello from f_main() / 113_btdll.c:31 +113_btdll.c:39: by main diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index e55dfbb4..41d8d5ff 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -24,7 +24,7 @@ ifeq (,$(filter i386,$(ARCH))) endif ifeq (,$(filter i386 x86_64,$(ARCH))) SKIP += 85_asm-outside-function.test - SKIP += 112_backtrace.test + SKIP += 112_backtrace.test 113_btdll.test endif ifeq (-$(findstring gcc,$(CC))-,--) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) @@ -61,7 +61,7 @@ GEN-ALWAYS = 95_bitfields_ms.test : GEN = $(GEN-MSC) # this test compiles/links two files: -104_inline.test : FLAGS += $(SRC)/104+_inline.c +104_inline.test : FLAGS += $(subst 104,104+,$1) 104_inline.test : GEN = $(GEN-TCC) # this test needs pthread @@ -72,7 +72,16 @@ GEN-ALWAYS = 108_constructor.test: NORUN = true 112_backtrace.test: FLAGS += -dt -b -112_backtrace.test: FILTER += -e 's;[0-9A-Fa-fx]\{8,\};........;g' -e 's;0x[0-9A-Fa-f]\+;0x?;g' +112_backtrace.test 113_btdll.test: FILTER += \ + -e 's;[0-9A-Fa-fx]\{8,\};........;g' \ + -e 's;0x[0-9A-Fa-f]\+;0x?;g' + +# this test creates two DLLs and an EXE +113_btdll.test: NORUN = true +113_btdll.test: FLAGS += \ + -bt $1 -shared -D DLL=1 -o a1$(DLLSUF) && $(TCC) \ + -bt $1 -shared -D DLL=2 -o a2$(DLLSUF) && $(TCC) \ + -bt a1$(DLLSUF) a2$(DLLSUF) -Wl,-rpath=. # Filter source directory in warnings/errors (out-of-tree builds) FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' @@ -81,10 +90,10 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ; %.test: %.c %.expect @echo Test: $*... - @$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3)) + @$(call T1,$<) $(T3) -T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS) -T2 = $(TCC) $(FLAGS) -run $< $(ARGS) +T1 = $(TCC) $(FLAGS) $(T2) $(ARGS) +T2 = $(if $(NORUN),$1 -o a.exe && ./a.exe,-run $1) T3 = $(FILTER) >$*.output 2>&1 || true \ && diff -Nbu $(filter %.expect,$^) $*.output \ && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) @@ -95,7 +104,7 @@ tests2.%+: # just run tcc to see the output, e.g. "make tests2.37-" tests2.%-: - @$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory + @$(MAKE) $(call F1,$*) T3= --no-print-directory # run single test, e.g. "make tests2.37" tests2.%: @@ -111,9 +120,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)" @rm -f *.exe *.obj *.pdb # using TCC for .expect if -dt in FLAGS -GEN = $(if $(filter -dt,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) +GEN = $(if $(filter -dt -bt -b,$(FLAGS)),$(GEN-TCC),$(GEN-CC)) GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS) -GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS) +GEN-TCC = $(T1) GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe MS-CC = cl @@ -124,5 +133,5 @@ MS-CC = cl $(sort $(GEN-ALWAYS) $(UPDATE)) : force force: -clean: - rm -f fred.txt *.output a.exe $(GEN-ALWAYS) +clean tests2.clean : + rm -f fred.txt *.output a.exe *.dll *.so *.def $(GEN-ALWAYS) diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat index 882299d1..8b93bf7a 100644 --- a/win32/build-tcc.bat +++ b/win32/build-tcc.bat @@ -163,7 +163,7 @@ copy>nul tcc-win32.txt doc .\tcc -m64 -c ../lib/alloca86_64-bt.S .\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o @if errorlevel 1 goto :the_end -.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o +.\tcc -m%T% -c ../lib/bcheck.c -o lib/bcheck.o -g .\tcc -m%T% -c ../lib/bt-exe.c -o lib/bt-exe.o .\tcc -m%T% -c ../lib/bt-log.c -o lib/bt-log.o .\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o diff --git a/x86_64-gen.c b/x86_64-gen.c index 439fd988..44c34ab0 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -701,10 +701,57 @@ ST_FUNC void gen_bounded_ptr_deref(void) rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i); rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info)); } + +#ifdef TCC_TARGET_PE +# define TREG_FASTCALL_1 TREG_RCX +#else +# define TREG_FASTCALL_1 TREG_RDI +#endif + +static void gen_bounds_prolog(void) +{ + /* leave some room for bound checking code */ + func_bound_offset = lbounds_section->data_offset; + func_bound_ind = ind; + o(0xb848 + TREG_FASTCALL_1 * 0x100); /*lbound section pointer */ + gen_le64 (0); + oad(0xb8, 0); /* call to function */ +} + +static void gen_bounds_epilog(void) +{ + addr_t saved_ind; + addr_t *bounds_ptr; + Sym *sym_data; + + /* add end of table info */ + bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); + *bounds_ptr = 0; + + /* generate bound local allocation */ + sym_data = get_sym_ref(&char_pointer_type, lbounds_section, + func_bound_offset, lbounds_section->data_offset); + saved_ind = ind; + ind = func_bound_ind; + greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); + ind = ind + 10; + gen_bounds_call(TOK___bound_local_new); + ind = saved_ind; + + /* generate bound check local freeing */ + o(0x525051); /* save returned value, if any (+ scratch-space for windows) */ + greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); + o(0xb848 + TREG_FASTCALL_1 * 0x100); /* mov xxx, %rcx/di */ + gen_le64 (0); + gen_bounds_call(TOK___bound_local_delete); + o(0x59585a); /* restore returned value, if any */ +} #endif #ifdef TCC_TARGET_PE +static int func_scratch, func_alloca; + #define REGN 4 static const uint8_t arg_regs[REGN] = { TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 @@ -720,8 +767,6 @@ static int arg_prepare_reg(int idx) { return arg_regs[idx]; } -static int func_scratch, func_alloca; - /* Generate function call. The function address is pushed first, then all the parameters in call order. This functions pops all the parameters and the function address. */ @@ -918,7 +963,6 @@ void gfunc_prolog(Sym *func_sym) int addr, reg_param_index, bt, size; Sym *sym; CType *type; - int n_arg = 0; func_ret_sub = 0; func_scratch = 32; @@ -946,7 +990,6 @@ void gfunc_prolog(Sym *func_sym) /* define parameters */ while ((sym = sym->next) != NULL) { - n_arg++; type = &sym->type; bt = type->t & VT_BTYPE; size = gfunc_arg_size(type); @@ -983,23 +1026,8 @@ void gfunc_prolog(Sym *func_sym) reg_param_index++; } #ifdef CONFIG_TCC_BCHECK - /* leave some room for bound checking code */ - if (tcc_state->do_bounds_check) { - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - o(0xb848); /* lbound section pointer */ - gen_le64 (0); - o(0xc18948); /* mov %rax,%rcx ## first arg in %rdi, this must be ptr */ - o(0x20ec8348); /* sub $20, %rsp */ - oad(0xb8, 0); /* call to function */ - o(0x20c48348); /* add $20, %rsp */ - if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) { - o(0x184d8b48); /* mov 0x18(%rbp),%rcx */ - o(0x20ec8348); /* sub $20, %rsp */ - gen_bounds_call(TOK___bound_main_arg); - o(0x20c48348); /* add $20, %rsp */ - } - } + if (tcc_state->do_bounds_check) + gen_bounds_prolog(); #endif } @@ -1013,39 +1041,10 @@ void gfunc_epilog(void) loc = (loc & -16) - func_scratch; #ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check - && func_bound_offset != lbounds_section->data_offset) - { - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - /* generate bound local allocation */ - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); - saved_ind = ind; - ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); - ind = ind + 10 + 3 + 4; - gen_bounds_call(TOK___bound_local_new); - ind = saved_ind; - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); - o(0xb848); /* mov xxx, %rax */ - gen_le64 (0); - o(0xc18948); /* mov %rax,%rcx # first arg in %rdi, this must be ptr */ - o(0x20ec8348); /* sub $20, %rsp */ - gen_bounds_call(TOK___bound_local_delete); - o(0x20c48348); /* add $20, %rsp */ - o(0x585a); /* restore returned value, if any */ - } + if (tcc_state->do_bounds_check) + gen_bounds_epilog(); #endif + o(0xc9); /* leave */ if (func_ret_sub == 0) { o(0xc3); /* ret */ @@ -1469,7 +1468,6 @@ void gfunc_prolog(Sym *func_sym) X86_64_Mode mode; int i, addr, align, size, reg_count; int param_addr = 0, reg_param_index, sse_param_index; - int n_arg = 0; Sym *sym; CType *type; @@ -1553,7 +1551,6 @@ void gfunc_prolog(Sym *func_sym) } /* define parameters */ while ((sym = sym->next) != NULL) { - n_arg++; type = &sym->type; mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); switch (mode) { @@ -1606,19 +1603,8 @@ void gfunc_prolog(Sym *func_sym) } #ifdef CONFIG_TCC_BCHECK - /* leave some room for bound checking code */ - if (tcc_state->do_bounds_check) { - func_bound_offset = lbounds_section->data_offset; - func_bound_ind = ind; - o(0xb848); /* lbound section pointer */ - gen_le64 (0); - o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ - oad(0xb8, 0); /* call to function */ - if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) { - o(0xf07d8b48); /* mov -0x10(%rbp),%rdi */ - gen_bounds_call(TOK___bound_main_arg); - } - } + if (tcc_state->do_bounds_check) + gen_bounds_prolog(); #endif } @@ -1628,36 +1614,8 @@ void gfunc_epilog(void) int v, saved_ind; #ifdef CONFIG_TCC_BCHECK - if (tcc_state->do_bounds_check - && func_bound_offset != lbounds_section->data_offset) - { - addr_t saved_ind; - addr_t *bounds_ptr; - Sym *sym_data; - - /* add end of table info */ - bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); - *bounds_ptr = 0; - - /* generate bound local allocation */ - sym_data = get_sym_ref(&char_pointer_type, lbounds_section, - func_bound_offset, lbounds_section->data_offset); - saved_ind = ind; - ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); - ind = ind + 10 + 3; - gen_bounds_call(TOK___bound_local_new); - ind = saved_ind; - - /* generate bound check local freeing */ - o(0x5250); /* save returned value, if any */ - greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); - o(0xb848); /* mov xxx, %rax */ - gen_le64 (0); - o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */ - gen_bounds_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ - } + if (tcc_state->do_bounds_check) + gen_bounds_epilog(); #endif o(0xc9); /* leave */ if (func_ret_sub == 0) {