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 == '-')
        ...
This commit is contained in:
grischka 2020-01-19 11:15:12 +01:00
parent a5f6e6189e
commit d79e1dee8c
13 changed files with 209 additions and 218 deletions

View File

@ -97,6 +97,8 @@ static int func_ret_sub;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
static addr_t func_bound_offset; static addr_t func_bound_offset;
static unsigned long func_bound_ind; static unsigned long func_bound_ind;
static void gen_bounds_prolog(void);
static void gen_bounds_epilog(void);
#endif #endif
/* XXX: make it faster ? */ /* 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) else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
args_size -= 4; args_size -= 4;
#endif #endif
gcall_or_jmp(0); gcall_or_jmp(0);
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW) 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; CType *func_type = &func_sym->type;
int addr, align, size, func_call, fastcall_nb_regs; int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr; int param_index, param_addr;
int n_arg = 0;
uint8_t *fastcall_regs_ptr; uint8_t *fastcall_regs_ptr;
Sym *sym; Sym *sym;
CType *type; CType *type;
@ -542,7 +544,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
} }
/* define parameters */ /* define parameters */
while ((sym = sym->next) != NULL) { while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type; type = &sym->type;
size = type_size(type, &align); size = type_size(type, &align);
size = (size + 3) & ~3; size = (size + 3) & ~3;
@ -576,19 +577,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
#endif #endif
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */ if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) { gen_bounds_prolog();
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 */
}
}
#endif #endif
} }
@ -598,34 +588,8 @@ ST_FUNC void gfunc_epilog(void)
addr_t v, saved_ind; addr_t v, saved_ind;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check if (tcc_state->do_bounds_check)
&& func_bound_offset != lbounds_section->data_offset) { gen_bounds_epilog();
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 */
}
#endif #endif
/* align local size to word & save local variables */ /* 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 = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); 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 #endif
/* Save the stack pointer onto the stack */ /* Save the stack pointer onto the stack */

View File

@ -353,7 +353,8 @@ void * __bound_ptr_add(void *p, size_t offset)
if (addr <= tree->size) { if (addr <= tree->size) {
if (tree->is_invalid || addr + offset > tree->size) { if (tree->is_invalid || addr + offset > tree->size) {
POST_SEM (); 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) if (never_fatal <= 0)
return INVALID_POINTER; /* return an invalid pointer */ return INVALID_POINTER; /* return an invalid pointer */
return p + offset; return p + offset;

View File

@ -802,11 +802,6 @@ LIBTCCAPI TCCState *tcc_new(void)
tcc_define_symbol(s, "__STDC_VERSION__", "199901L"); tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
tcc_define_symbol(s, "__STDC_HOSTED__", NULL); 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 */ /* target defines */
#if defined(TCC_TARGET_I386) #if defined(TCC_TARGET_I386)
tcc_define_symbol(s, "__i386__", NULL); tcc_define_symbol(s, "__i386__", NULL);
@ -1905,11 +1900,6 @@ reparse:
* encoding used is implementationdefined. * encoding used is implementationdefined.
*/ */
tcc_define_symbol(s, "__STDC_UTF_32__", "1"); 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 */ #endif /* !TCC_TARGET_PE */
s->cversion = 201112; s->cversion = 201112;
} }

3
tcc.h
View File

@ -884,6 +884,9 @@ struct TCCState {
const char *runtime_main; const char *runtime_main;
void **runtime_mem; void **runtime_mem;
int nb_runtime_mem; int nb_runtime_mem;
#endif
#ifdef CONFIG_TCC_BACKTRACE
int rt_num_callers; int rt_num_callers;
#endif #endif

View File

@ -1387,7 +1387,11 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
"__attribute__((constructor)) static void __bt_init_rt(){"); "__attribute__((constructor)) static void __bt_init_rt(){");
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
if (s1->output_type == TCC_OUTPUT_DLL) if (s1->output_type == TCC_OUTPUT_DLL)
#ifdef CONFIG_TCC_BCHECK
cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check); cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check);
#else
cstr_printf(&cstr, "__bt_init_dll(0);");
#endif
#endif #endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}", cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);

View File

@ -101,6 +101,8 @@ ST_DATA struct switch_t {
int def_sym; /* default symbol */ int def_sym; /* default symbol */
int *bsym; int *bsym;
struct scope *scope; struct scope *scope;
struct switch_t *prev;
SValue sv;
} *cur_switch; /* current switch */ } *cur_switch; /* current switch */
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8
@ -6447,6 +6449,7 @@ static void lblock(int *bsym, int *csym)
static void block(int is_expr) static void block(int is_expr)
{ {
int a, b, c, d, e, t; int a, b, c, d, e, t;
struct scope o;
Sym *s; Sym *s;
if (is_expr) { if (is_expr) {
@ -6487,7 +6490,6 @@ again:
gsym(a); gsym(a);
} else if (t == '{') { } else if (t == '{') {
struct scope o;
new_scope(&o); new_scope(&o);
/* handle local labels declarations */ /* handle local labels declarations */
@ -6545,10 +6547,10 @@ again:
/* compute jump */ /* compute jump */
if (!cur_scope->bsym) if (!cur_scope->bsym)
tcc_error("cannot break"); tcc_error("cannot break");
if (!cur_switch || cur_scope->bsym != cur_switch->bsym) if (cur_switch && cur_scope->bsym == cur_switch->bsym)
leave_scope(loop_scope);
else
leave_scope(cur_switch->scope); leave_scope(cur_switch->scope);
else
leave_scope(loop_scope);
*cur_scope->bsym = gjmp(*cur_scope->bsym); *cur_scope->bsym = gjmp(*cur_scope->bsym);
skip(';'); skip(';');
@ -6561,7 +6563,6 @@ again:
skip(';'); skip(';');
} else if (t == TOK_FOR) { } else if (t == TOK_FOR) {
struct scope o;
new_scope(&o); new_scope(&o);
skip('('); skip('(');
@ -6611,22 +6612,18 @@ again:
gsym(a); gsym(a);
} else if (t == TOK_SWITCH) { } else if (t == TOK_SWITCH) {
struct switch_t *saved, sw; struct switch_t *sw;
SValue switchval;
sw.p = NULL; sw = tcc_mallocz(sizeof *sw);
sw.n = 0; sw->bsym = &a;
sw.def_sym = 0; sw->scope = cur_scope;
sw.bsym = &a; sw->prev = cur_switch;
sw.scope = cur_scope; cur_switch = sw;
saved = cur_switch;
cur_switch = &sw;
skip('('); skip('(');
gexpr(); gexpr();
skip(')'); skip(')');
switchval = *vtop--; sw->sv = *vtop--; /* save switch value */
a = 0; a = 0;
b = gjmp(0); /* jump to first case */ b = gjmp(0); /* jump to first case */
@ -6635,28 +6632,29 @@ again:
/* case lookup */ /* case lookup */
gsym(b); gsym(b);
qsort(sw.p, sw.n, sizeof(void*), case_cmp); qsort(sw->p, sw->n, sizeof(void*), case_cmp);
for (b = 1; b < sw.n; b++) for (b = 1; b < sw->n; b++)
if (sw.p[b - 1]->v2 >= sw.p[b]->v1) if (sw->p[b - 1]->v2 >= sw->p[b]->v1)
tcc_error("duplicate case value"); tcc_error("duplicate case value");
/* Our switch table sorting is signed, so the compared /* Our switch table sorting is signed, so the compared
value needs to be as well when it's 64bit. */ value needs to be as well when it's 64bit. */
if ((switchval.type.t & VT_BTYPE) == VT_LLONG) vpushv(&sw->sv);
switchval.type.t &= ~VT_UNSIGNED; if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
vpushv(&switchval); vtop->type.t &= ~VT_UNSIGNED;
gv(RC_INT); gv(RC_INT);
d = 0, gcase(sw.p, sw.n, &d); d = 0, gcase(sw->p, sw->n, &d);
vpop(); vpop();
if (sw.def_sym) if (sw->def_sym)
gsym_addr(d, sw.def_sym); gsym_addr(d, sw->def_sym);
else else
gsym(d); gsym(d);
/* break label */ /* break label */
gsym(a); gsym(a);
dynarray_reset(&sw.p, &sw.n); dynarray_reset(&sw->p, &sw->n);
cur_switch = saved; cur_switch = sw->prev;
tcc_free(sw);
} else if (t == TOK_CASE) { } else if (t == TOK_CASE) {
struct case_t *cr = tcc_malloc(sizeof(struct case_t)); struct case_t *cr = tcc_malloc(sizeof(struct case_t));

View File

@ -48,7 +48,7 @@ static int _rt_error(void *fp, void *ip, const char *fmt, va_list ap);
static void rt_exit(int code); static void rt_exit(int code);
#endif /* CONFIG_TCC_BACKTRACE */ #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 CONFIG_TCC_BACKTRACE_ONLY
#ifndef _WIN32 #ifndef _WIN32
@ -412,15 +412,15 @@ next:
/* Stab_Sym.n_value is only 32bits */ /* Stab_Sym.n_value is only 32bits */
pc += rc->prog_base; pc += rc->prog_base;
#endif #endif
break; goto check_pc;
rel_pc: rel_pc:
pc += func_addr; pc += func_addr;
check_pc:
if (pc >= wanted_pc && wanted_pc >= last_pc)
goto found;
break; break;
} }
if (pc >= wanted_pc && wanted_pc >= last_pc)
goto found;
switch(sym->n_type) { switch(sym->n_type) {
/* function start or end */ /* function start or end */
case N_FUN: case N_FUN:

View File

@ -12,8 +12,6 @@
[test_bcheck_1] [test_bcheck_1]
* main * main
* f1() * 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:38: at f1: BCHECK: invalid pointer ........, size 0x? in memmove dest
112_backtrace.c:43: by main 112_backtrace.c:43: by main
[returns 255] [returns 255]
@ -32,12 +30,10 @@
[returns 1] [returns 1]
[test_bcheck_100] [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 112_backtrace.c:107: at main: BCHECK: invalid pointer ........, size 0x? in memcpy dest
[returns 255] [returns 255]
[test_bcheck_101] [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 112_backtrace.c:109: at main: BCHECK: invalid pointer ........, size 0x? in memcpy src
[returns 255] [returns 255]
@ -50,42 +46,34 @@
[returns 255] [returns 255]
[test_bcheck_104] [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 112_backtrace.c:115: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s1
[returns 255] [returns 255]
[test_bcheck_105] [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 112_backtrace.c:117: at main: BCHECK: invalid pointer ........, size 0x? in memcmp s2
[returns 255] [returns 255]
[test_bcheck_106] [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 112_backtrace.c:119: at main: BCHECK: invalid pointer ........, size 0x? in memmove dest
[returns 255] [returns 255]
[test_bcheck_107] [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 112_backtrace.c:121: at main: BCHECK: invalid pointer ........, size 0x? in memmove src
[returns 255] [returns 255]
[test_bcheck_108] [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 112_backtrace.c:123: at main: BCHECK: invalid pointer ........, size 0x? in memset
[returns 255] [returns 255]
[test_bcheck_109] [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 112_backtrace.c:125: at main: BCHECK: invalid pointer ........, size 0x? in strlen
[returns 255] [returns 255]
[test_bcheck_110] [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 112_backtrace.c:127: at main: BCHECK: invalid pointer ........, size 0x? in strcpy dest
[returns 255] [returns 255]
[test_bcheck_111] [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 112_backtrace.c:129: at main: BCHECK: invalid pointer ........, size 0x? in strcpy src
[returns 255] [returns 255]
@ -98,12 +86,10 @@
[returns 255] [returns 255]
[test_bcheck_114] [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 112_backtrace.c:135: at main: BCHECK: invalid pointer ........, size 0x? in strncpy dest
[returns 255] [returns 255]
[test_bcheck_115] [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 112_backtrace.c:137: at main: BCHECK: invalid pointer ........, size 0x? in strncpy src
[returns 255] [returns 255]
@ -116,32 +102,26 @@
[returns 255] [returns 255]
[test_bcheck_118] [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 112_backtrace.c:143: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s1
[returns 255] [returns 255]
[test_bcheck_119] [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 112_backtrace.c:145: at main: BCHECK: invalid pointer ........, size 0x? in strcmp s2
[returns 255] [returns 255]
[test_bcheck_120] [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 112_backtrace.c:147: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s1
[returns 255] [returns 255]
[test_bcheck_121] [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 112_backtrace.c:149: at main: BCHECK: invalid pointer ........, size 0x? in strncmp s2
[returns 255] [returns 255]
[test_bcheck_122] [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 112_backtrace.c:151: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
[returns 255] [returns 255]
[test_bcheck_123] [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 112_backtrace.c:153: at main: BCHECK: invalid pointer ........, size 0x? in strcat dest
[returns 255] [returns 255]
@ -154,11 +134,9 @@
[returns 255] [returns 255]
[test_bcheck_126] [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 112_backtrace.c:159: at main: BCHECK: invalid pointer ........, size 0x? in strchr
[returns 255] [returns 255]
[test_bcheck_127] [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 112_backtrace.c:161: at main: BCHECK: invalid pointer ........, size 0x? in strdup
[returns 255] [returns 255]

43
tests/tests2/113_btdll.c Normal file
View File

@ -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

View File

@ -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

View File

@ -24,7 +24,7 @@ ifeq (,$(filter i386,$(ARCH)))
endif endif
ifeq (,$(filter i386 x86_64,$(ARCH))) ifeq (,$(filter i386 x86_64,$(ARCH)))
SKIP += 85_asm-outside-function.test SKIP += 85_asm-outside-function.test
SKIP += 112_backtrace.test SKIP += 112_backtrace.test 113_btdll.test
endif endif
ifeq (-$(findstring gcc,$(CC))-,--) ifeq (-$(findstring gcc,$(CC))-,--)
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS)) SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
@ -61,7 +61,7 @@ GEN-ALWAYS =
95_bitfields_ms.test : GEN = $(GEN-MSC) 95_bitfields_ms.test : GEN = $(GEN-MSC)
# this test compiles/links two files: # 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) 104_inline.test : GEN = $(GEN-TCC)
# this test needs pthread # this test needs pthread
@ -72,7 +72,16 @@ GEN-ALWAYS =
108_constructor.test: NORUN = true 108_constructor.test: NORUN = true
112_backtrace.test: FLAGS += -dt -b 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 source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g' FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
@ -81,10 +90,10 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
%.test: %.c %.expect %.test: %.c %.expect
@echo Test: $*... @echo Test: $*...
@$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3)) @$(call T1,$<) $(T3)
T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS) T1 = $(TCC) $(FLAGS) $(T2) $(ARGS)
T2 = $(TCC) $(FLAGS) -run $< $(ARGS) T2 = $(if $(NORUN),$1 -o a.exe && ./a.exe,-run $1)
T3 = $(FILTER) >$*.output 2>&1 || true \ T3 = $(FILTER) >$*.output 2>&1 || true \
&& diff -Nbu $(filter %.expect,$^) $*.output \ && diff -Nbu $(filter %.expect,$^) $*.output \
&& rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS)) && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
@ -95,7 +104,7 @@ tests2.%+:
# just run tcc to see the output, e.g. "make tests2.37-" # just run tcc to see the output, e.g. "make tests2.37-"
tests2.%-: tests2.%-:
@$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory @$(MAKE) $(call F1,$*) T3= --no-print-directory
# run single test, e.g. "make tests2.37" # run single test, e.g. "make tests2.37"
tests2.%: tests2.%:
@ -111,9 +120,9 @@ F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
@rm -f *.exe *.obj *.pdb @rm -f *.exe *.obj *.pdb
# using TCC for .expect if -dt in FLAGS # 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-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 GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe
MS-CC = cl MS-CC = cl
@ -124,5 +133,5 @@ MS-CC = cl
$(sort $(GEN-ALWAYS) $(UPDATE)) : force $(sort $(GEN-ALWAYS) $(UPDATE)) : force
force: force:
clean: clean tests2.clean :
rm -f fred.txt *.output a.exe $(GEN-ALWAYS) rm -f fred.txt *.output a.exe *.dll *.so *.def $(GEN-ALWAYS)

View File

@ -163,7 +163,7 @@ copy>nul tcc-win32.txt doc
.\tcc -m64 -c ../lib/alloca86_64-bt.S .\tcc -m64 -c ../lib/alloca86_64-bt.S
.\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o .\tcc -m64 -ar lib/libtcc1-64.a %O1% alloca86_64.o alloca86_64-bt.o
@if errorlevel 1 goto :the_end @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-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-log.c -o lib/bt-log.o
.\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o .\tcc -m%T% -c ../lib/bt-dll.c -o lib/bt-dll.o

View File

@ -701,10 +701,57 @@ ST_FUNC void gen_bounded_ptr_deref(void)
rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i); 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)); 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 #endif
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
static int func_scratch, func_alloca;
#define REGN 4 #define REGN 4
static const uint8_t arg_regs[REGN] = { static const uint8_t arg_regs[REGN] = {
TREG_RCX, TREG_RDX, TREG_R8, TREG_R9 TREG_RCX, TREG_RDX, TREG_R8, TREG_R9
@ -720,8 +767,6 @@ static int arg_prepare_reg(int idx) {
return arg_regs[idx]; return arg_regs[idx];
} }
static int func_scratch, func_alloca;
/* Generate function call. The function address is pushed first, then /* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the all the parameters in call order. This functions pops all the
parameters and the function address. */ parameters and the function address. */
@ -918,7 +963,6 @@ void gfunc_prolog(Sym *func_sym)
int addr, reg_param_index, bt, size; int addr, reg_param_index, bt, size;
Sym *sym; Sym *sym;
CType *type; CType *type;
int n_arg = 0;
func_ret_sub = 0; func_ret_sub = 0;
func_scratch = 32; func_scratch = 32;
@ -946,7 +990,6 @@ void gfunc_prolog(Sym *func_sym)
/* define parameters */ /* define parameters */
while ((sym = sym->next) != NULL) { while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type; type = &sym->type;
bt = type->t & VT_BTYPE; bt = type->t & VT_BTYPE;
size = gfunc_arg_size(type); size = gfunc_arg_size(type);
@ -983,23 +1026,8 @@ void gfunc_prolog(Sym *func_sym)
reg_param_index++; reg_param_index++;
} }
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */ if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) { gen_bounds_prolog();
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 */
}
}
#endif #endif
} }
@ -1013,39 +1041,10 @@ void gfunc_epilog(void)
loc = (loc & -16) - func_scratch; loc = (loc & -16) - func_scratch;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check if (tcc_state->do_bounds_check)
&& func_bound_offset != lbounds_section->data_offset) gen_bounds_epilog();
{
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 */
}
#endif #endif
o(0xc9); /* leave */ o(0xc9); /* leave */
if (func_ret_sub == 0) { if (func_ret_sub == 0) {
o(0xc3); /* ret */ o(0xc3); /* ret */
@ -1469,7 +1468,6 @@ void gfunc_prolog(Sym *func_sym)
X86_64_Mode mode; X86_64_Mode mode;
int i, addr, align, size, reg_count; int i, addr, align, size, reg_count;
int param_addr = 0, reg_param_index, sse_param_index; int param_addr = 0, reg_param_index, sse_param_index;
int n_arg = 0;
Sym *sym; Sym *sym;
CType *type; CType *type;
@ -1553,7 +1551,6 @@ void gfunc_prolog(Sym *func_sym)
} }
/* define parameters */ /* define parameters */
while ((sym = sym->next) != NULL) { while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type; type = &sym->type;
mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count); mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);
switch (mode) { switch (mode) {
@ -1606,19 +1603,8 @@ void gfunc_prolog(Sym *func_sym)
} }
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */ if (tcc_state->do_bounds_check)
if (tcc_state->do_bounds_check) { gen_bounds_prolog();
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);
}
}
#endif #endif
} }
@ -1628,36 +1614,8 @@ void gfunc_epilog(void)
int v, saved_ind; int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check if (tcc_state->do_bounds_check)
&& func_bound_offset != lbounds_section->data_offset) gen_bounds_epilog();
{
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 */
}
#endif #endif
o(0xc9); /* leave */ o(0xc9); /* leave */
if (func_ret_sub == 0) { if (func_ret_sub == 0) {