From 65f2fe390c8fb7341f27172059e939efbcdaabf0 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Thu, 16 Jan 2020 01:19:59 +0100 Subject: [PATCH] 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. --- i386-gen.c | 9 +-- tcc.h | 12 ++-- tccgen.c | 165 ++++++++++++--------------------------------------- x86_64-gen.c | 17 +----- 4 files changed, 47 insertions(+), 156 deletions(-) diff --git a/i386-gen.c b/i386-gen.c index 51a514ae..7e1e0f49 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -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 diff --git a/tcc.h b/tcc.h index eb46bbda..9013e87d 100644 --- a/tcc.h +++ b/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 ------------ */ diff --git a/tccgen.c b/tccgen.c index 946a9e21..21aaac63 100644 --- a/tccgen.c +++ b/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;isizealign -#ifdef CONFIG_TCC_BCHECK - || (tcc_state->do_bounds_check && used_location[i]) -#endif - ){ + if(temp_var->sizealign){ 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); diff --git a/x86_64-gen.c b/x86_64-gen.c index b4a546c2..439fd988 100644 --- a/x86_64-gen.c +++ b/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