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:
Michael Matz 2020-01-16 01:19:59 +01:00
parent 4a70b2bc2d
commit 65f2fe390c
4 changed files with 47 additions and 156 deletions

View File

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

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

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

View File

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