Cleanup new bound checking code
remove quadratic loops by not using side tables; address-taken can simply be a flag per local sym, and the lbounds section can be filled after symbols go out of scope at which point we know if the address was taken, so that there's no need to compress it again after the funcion is done.
This commit is contained in:
parent
4a70b2bc2d
commit
65f2fe390c
4 changed files with 47 additions and 156 deletions
|
@ -95,6 +95,7 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
|||
static unsigned long func_sub_sp_offset;
|
||||
static int func_ret_sub;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
#endif
|
||||
|
||||
|
@ -401,10 +402,8 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
Sym *func_sym;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
args_size = 0;
|
||||
|
@ -486,10 +485,6 @@ ST_FUNC void gfunc_call(int nb_args)
|
|||
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
|
12
tcc.h
12
tcc.h
|
@ -474,9 +474,8 @@ struct SymAttr {
|
|||
dllexport : 1,
|
||||
nodecorate : 1,
|
||||
dllimport : 1,
|
||||
constructor : 1,
|
||||
destructor : 1,
|
||||
unused : 2;
|
||||
addrtaken : 1,
|
||||
unused : 3;
|
||||
};
|
||||
|
||||
/* function attributes or temporary attributes for parsing */
|
||||
|
@ -620,6 +619,8 @@ typedef struct TokenString {
|
|||
typedef struct AttributeDef {
|
||||
struct SymAttr a;
|
||||
struct FuncAttr f;
|
||||
unsigned short constructor:1;
|
||||
unsigned short destructor:1;
|
||||
struct Section *section;
|
||||
Sym *cleanup_func;
|
||||
int alias_target; /* token */
|
||||
|
@ -1378,9 +1379,6 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi
|
|||
ST_DATA int func_var; /* true if current function is variadic */
|
||||
ST_DATA int func_vc;
|
||||
ST_DATA const char *funcname;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_DATA addr_t func_bound_offset;
|
||||
#endif
|
||||
|
||||
ST_FUNC void tcc_debug_start(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_end(TCCState *s1);
|
||||
|
@ -1446,8 +1444,6 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
|||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
ST_FUNC void save_temp_local(int nb_args);
|
||||
ST_FUNC void restore_temp_local(void);
|
||||
#endif
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
|
165
tccgen.c
165
tccgen.c
|
@ -111,16 +111,6 @@ ST_DATA struct temp_local_variable {
|
|||
short align;
|
||||
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
||||
short nb_temp_local_vars;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static short call_nesting;
|
||||
static char used_location[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
||||
static int nb_bound_local_param;
|
||||
struct {
|
||||
unsigned long data_offset;
|
||||
int v;
|
||||
} *bound_local_param;
|
||||
ST_DATA addr_t func_bound_offset;
|
||||
#endif
|
||||
|
||||
static struct scope {
|
||||
struct scope *prev;
|
||||
|
@ -1502,11 +1492,7 @@ static int get_temp_local_var(int size,int align){
|
|||
found=0;
|
||||
for(i=0;i<nb_temp_local_vars;i++){
|
||||
temp_var=&arr_temp_local_vars[i];
|
||||
if(temp_var->size<size||align!=temp_var->align
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|| (tcc_state->do_bounds_check && used_location[i])
|
||||
#endif
|
||||
){
|
||||
if(temp_var->size<size||align!=temp_var->align){
|
||||
continue;
|
||||
}
|
||||
/*check if temp_var is free*/
|
||||
|
@ -1607,51 +1593,37 @@ ST_FUNC void gbound_args(int nb_args)
|
|||
}
|
||||
}
|
||||
|
||||
ST_FUNC void save_temp_local(int nb_args)
|
||||
/* Add bounds for local symbols from S to E (via ->prev) */
|
||||
static void add_local_bounds(Sym *s, Sym *e)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (call_nesting++ == 0)
|
||||
for (i = 1; i <= nb_args; ++i)
|
||||
for (j = 0; j < nb_temp_local_vars; j++)
|
||||
if (vtop[1 - i].c.i == arr_temp_local_vars[j].location) {
|
||||
used_location[j] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void restore_temp_local()
|
||||
{
|
||||
if (--call_nesting == 0)
|
||||
memset (used_location, 0, sizeof (used_location));
|
||||
}
|
||||
|
||||
static void add_bound_param(CType *type, int size, int v, int c)
|
||||
{
|
||||
addr_t *bounds_ptr;
|
||||
/* Add arrays/structs/unions because we always take address */
|
||||
int taken = (type->t & VT_ARRAY)
|
||||
|| (type->t & VT_BTYPE) == VT_STRUCT;
|
||||
|
||||
if (taken == 0) {
|
||||
/* Add parameter to check */
|
||||
nb_bound_local_param++;
|
||||
bound_local_param =
|
||||
tcc_realloc (bound_local_param,
|
||||
nb_bound_local_param *
|
||||
sizeof (*bound_local_param));
|
||||
bound_local_param[nb_bound_local_param-1].data_offset =
|
||||
lbounds_section->data_offset;
|
||||
bound_local_param[nb_bound_local_param-1].v = v;
|
||||
for (; s != e; s = s->prev) {
|
||||
if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
|
||||
continue;
|
||||
/* Add arrays/structs/unions because we always take address */
|
||||
if ((s->type.t & VT_ARRAY)
|
||||
|| (s->type.t & VT_BTYPE) == VT_STRUCT
|
||||
|| s->a.addrtaken) {
|
||||
/* add local bound info */
|
||||
int align, size = type_size(&s->type, &align);
|
||||
addr_t *bounds_ptr = section_ptr_add(lbounds_section,
|
||||
2 * sizeof(addr_t));
|
||||
bounds_ptr[0] = s->c;
|
||||
bounds_ptr[1] = size;
|
||||
}
|
||||
}
|
||||
/* add local bound info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section,
|
||||
2 * sizeof(addr_t));
|
||||
bounds_ptr[0] = c;
|
||||
bounds_ptr[1] = taken ? size : ~size;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wrapper around sym_pop, that potentially also registers local bounds. */
|
||||
static void pop_local_syms(Sym **ptop, Sym *b, int keep)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (!keep && tcc_state->do_bounds_check)
|
||||
add_local_bounds(*ptop, b);
|
||||
#endif
|
||||
sym_pop(ptop, b, keep);
|
||||
}
|
||||
|
||||
static void incr_bf_adr(int o)
|
||||
{
|
||||
vtop->type = char_pointer_type;
|
||||
|
@ -3690,11 +3662,11 @@ redo:
|
|||
}
|
||||
case TOK_CONSTRUCTOR1:
|
||||
case TOK_CONSTRUCTOR2:
|
||||
ad->a.constructor = 1;
|
||||
ad->constructor = 1;
|
||||
break;
|
||||
case TOK_DESTRUCTOR1:
|
||||
case TOK_DESTRUCTOR2:
|
||||
ad->a.destructor = 1;
|
||||
ad->destructor = 1;
|
||||
break;
|
||||
case TOK_SECTION1:
|
||||
case TOK_SECTION2:
|
||||
|
@ -5138,23 +5110,8 @@ ST_FUNC void unary(void)
|
|||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
|
||||
!(vtop->type.t & VT_ARRAY))
|
||||
test_lvalue();
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && vtop->sym) {
|
||||
int i;
|
||||
|
||||
/* Mark parameter as being used for address off */
|
||||
for (i = 0; i < nb_bound_local_param; i++) {
|
||||
if (bound_local_param[i].v == vtop->sym->v) {
|
||||
addr_t *bounds_ptr =
|
||||
(addr_t *) (lbounds_section->data +
|
||||
bound_local_param[i].data_offset);
|
||||
bounds_ptr[1] = ~bounds_ptr[1];
|
||||
bound_local_param[i].v = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (vtop->sym)
|
||||
vtop->sym->a.addrtaken = 1;
|
||||
mk_pointer(&vtop->type);
|
||||
gaddrof();
|
||||
break;
|
||||
|
@ -6454,7 +6411,7 @@ void prev_scope(struct scope *o, int is_expr)
|
|||
tables, though. sym_pop will do that. */
|
||||
|
||||
/* pop locally defined symbols */
|
||||
sym_pop(&local_stack, o->lstk, is_expr);
|
||||
pop_local_syms(&local_stack, o->lstk, is_expr);
|
||||
|
||||
cur_scope = o->prev;
|
||||
--local_scope;
|
||||
|
@ -7426,17 +7383,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||
Sym *sym = NULL;
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
int bcheck;
|
||||
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
||||
#endif
|
||||
|
||||
/* Always allocate static or global variables */
|
||||
if (v && (r & VT_VALMASK) == VT_CONST)
|
||||
nocode_wanted |= 0x80000000;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
||||
#endif
|
||||
|
||||
flexible_array = NULL;
|
||||
if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
Sym *field = type->ref->next;
|
||||
|
@ -7508,17 +7461,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||
sec = NULL;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (bcheck && v) {
|
||||
/* add padding between stack variables */
|
||||
/* add padding between stack variables for bound checking */
|
||||
loc--;
|
||||
}
|
||||
#endif
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* handles bounds */
|
||||
if (bcheck && v) {
|
||||
add_bound_param (type, size, v, addr);
|
||||
/* add padding between stack variables */
|
||||
/* add padding between stack variables for bound checking */
|
||||
loc--;
|
||||
}
|
||||
#endif
|
||||
|
@ -7682,10 +7633,10 @@ static void gen_function(Sym *sym, AttributeDef *ad)
|
|||
/* NOTE: we patch the symbol size later */
|
||||
put_extern_sym(sym, cur_text_section, ind, 0);
|
||||
|
||||
if (ad && ad->a.constructor) {
|
||||
if (ad && ad->constructor) {
|
||||
add_init_array (tcc_state, sym);
|
||||
}
|
||||
if (ad && ad->a.destructor) {
|
||||
if (ad && ad->destructor) {
|
||||
add_fini_array (tcc_state, sym);
|
||||
}
|
||||
|
||||
|
@ -7698,56 +7649,16 @@ static void gen_function(Sym *sym, AttributeDef *ad)
|
|||
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
||||
local_scope = 1; /* for function parameters */
|
||||
gfunc_prolog(sym);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check
|
||||
&& sym->type.ref->f.func_type != FUNC_ELLIPSIS) {
|
||||
Sym *fpar;
|
||||
|
||||
/* Add function arguments in case & is used */
|
||||
for (fpar = sym->type.ref->next; fpar; fpar = fpar->next) {
|
||||
Sym *fsym = sym_find (fpar->v & ~SYM_FIELD);
|
||||
|
||||
if (fsym && (fsym->r & VT_VALMASK) == VT_LOCAL) {
|
||||
int align;
|
||||
int size = type_size(&fsym->type, &align);
|
||||
|
||||
if (size > 0)
|
||||
add_bound_param (&fsym->type, size, fsym->v, fsym->c);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
local_scope = 0;
|
||||
rsym = 0;
|
||||
clear_temp_local_var_list();
|
||||
block(0);
|
||||
gsym(rsym);
|
||||
nocode_wanted = 0;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check) {
|
||||
addr_t o = func_bound_offset;
|
||||
|
||||
/* Remove parameters where address off is not used */
|
||||
while (o != lbounds_section->data_offset) {
|
||||
addr_t *bounds_ptr = (addr_t *) (lbounds_section->data + o);
|
||||
if ((ssize_t) bounds_ptr[1] < 0) {
|
||||
lbounds_section->data_offset -= 2 * sizeof (addr_t);
|
||||
memmove(bounds_ptr, bounds_ptr + 2,
|
||||
lbounds_section->data_offset - o);
|
||||
}
|
||||
else {
|
||||
o += 2 * sizeof (addr_t);
|
||||
}
|
||||
}
|
||||
tcc_free (bound_local_param);
|
||||
nb_bound_local_param = 0;
|
||||
bound_local_param = NULL;
|
||||
}
|
||||
#endif
|
||||
gfunc_epilog();
|
||||
cur_text_section->data_offset = ind;
|
||||
/* reset local stack */
|
||||
sym_pop(&local_stack, NULL, 0);
|
||||
pop_local_syms(&local_stack, NULL, 0);
|
||||
local_scope = 0;
|
||||
label_pop(&global_label_stack, NULL, 0);
|
||||
sym_pop(&all_cleanups, NULL, 0);
|
||||
|
|
17
x86_64-gen.c
17
x86_64-gen.c
|
@ -637,6 +637,7 @@ static void gcall_or_jmp(int is_jmp)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
|
||||
static void gen_bounds_call(int v)
|
||||
|
@ -783,10 +784,8 @@ void gfunc_call(int nb_args)
|
|||
int arg;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
|
||||
|
@ -907,10 +906,6 @@ void gfunc_call(int nb_args)
|
|||
|
||||
}
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1276,10 +1271,8 @@ void gfunc_call(int nb_args)
|
|||
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* calculate the number of integer/float register arguments, remember
|
||||
|
@ -1460,10 +1453,6 @@ void gfunc_call(int nb_args)
|
|||
if (args_size)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FUNC_PROLOG_SIZE 11
|
||||
|
|
Loading…
Reference in a new issue