mirror of
https://github.com/frida/tinycc
synced 2025-01-01 17:44:26 +03:00
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:
parent
a5f6e6189e
commit
d79e1dee8c
87
i386-gen.c
87
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 */
|
||||
|
@ -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;
|
||||
|
10
libtcc.c
10
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 implementationdefined.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
3
tcc.h
3
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
|
||||
|
||||
|
4
tccelf.c
4
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);
|
||||
|
52
tccgen.c
52
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));
|
||||
|
10
tccrun.c
10
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:
|
||||
|
@ -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]
|
||||
|
43
tests/tests2/113_btdll.c
Normal file
43
tests/tests2/113_btdll.c
Normal 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
|
6
tests/tests2/113_btdll.expect
Normal file
6
tests/tests2/113_btdll.expect
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
154
x86_64-gen.c
154
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user