diff --git a/tcc.c b/tcc.c index 5d9623e..1cca830 100644 --- a/tcc.c +++ b/tcc.c @@ -163,7 +163,9 @@ int section_num; Section *text_section, *data_section, *bss_section; /* predefined sections */ Section *cur_text_section; /* current section where function code is generated */ +/* bound check related sections */ Section *bounds_section; /* contains global data bound description */ +Section *lbounds_section; /* contains local data bound description */ /* debug sections */ Section *stab_section, *stabstr_section, *symtab_section, *strtab_section; @@ -209,18 +211,20 @@ int gnu_ext = 1; int tcc_ext = 1; /* The current value can be: */ -#define VT_VALMASK 0x00ff -#define VT_CONST 0x00f0 /* constant in vc +#define VT_VALMASK 0x00ff +#define VT_CONST 0x00f0 /* constant in vc (must be first non register value) */ -#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ -#define VT_LOCAL 0x00f2 /* offset on stack */ -#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ -#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ -#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ -#define VT_LVAL 0x0100 /* var is an lvalue */ -#define VT_FORWARD 0x0200 /* value is forward reference */ -#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for +#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ +#define VT_LOCAL 0x00f2 /* offset on stack */ +#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ +#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ +#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ +#define VT_LVAL 0x0100 /* var is an lvalue */ +#define VT_FORWARD 0x0200 /* value is forward reference */ +#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for char/short stored in integer registers) */ +#define VT_MUSTBOUND 0x0800 /* bound checking must be done before + dereferencing value */ /* types */ #define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */ @@ -402,6 +406,7 @@ void decl(int l); void decl_initializer(int t, int r, int c, int first, int size_only); int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init); int gv(int rc); +void gv2(int rc1, int rc2); void move_reg(int r, int s); void save_regs(void); void save_reg(int r); @@ -2339,6 +2344,20 @@ void gaddrof(void) vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; } +/* generate lvalue bound code */ +void gbound(void) +{ + vtop->r &= ~VT_MUSTBOUND; + /* if lvalue, then use checking code before dereferencing */ + if (vtop->r & VT_LVAL) { + gaddrof(); + vpushi(0); + gen_bounded_ptr_add1(); + gen_bounded_ptr_add2(1); + vtop->r |= VT_LVAL; + } +} + /* store vtop a register belonging to class 'rc'. lvalues are converted to values. Cannot be used if cannot be converted to register value (such as structures). */ @@ -2377,6 +2396,9 @@ int gv(int rc) data_offset += size << 2; data_section->data_ptr = (unsigned char *)data_offset; } + if (vtop->r & VT_MUSTBOUND) + gbound(); + r = vtop->r & VT_VALMASK; /* need to reload if: - constant @@ -2436,6 +2458,33 @@ int gv(int rc) return r; } +/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ +void gv2(int rc1, int rc2) +{ + /* generate more generic register first */ + if (rc1 <= rc2) { + vswap(); + gv(rc1); + vswap(); + gv(rc2); + /* test if reload is needed for first register */ + if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { + vswap(); + gv(rc1); + vswap(); + } + } else { + gv(rc2); + vswap(); + gv(rc1); + vswap(); + /* test if reload is needed for first register */ + if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { + gv(rc2); + } + } +} + /* expand long long on stack in two int registers */ void lexpand(void) { @@ -2454,10 +2503,7 @@ void lexpand(void) /* build a long long from two ints */ void lbuild(int t) { - vswap(); - gv(RC_INT); - vswap(); - gv(RC_INT); + gv2(RC_INT, RC_INT); vtop[-1].r2 = vtop[0].r; vtop[-1].t = t; vpop(); @@ -2890,13 +2936,15 @@ void gen_op(int op) vpushi(pointed_size(vtop[-1].t)); gen_op('*'); if (do_bounds_check) { - /* if bounded pointers, we generate a special code to test bounds */ + /* if bounded pointers, we generate a special code to + test bounds */ if (op == '-') { vpushi(0); vswap(); gen_op('-'); } - gen_bounded_ptr_add(); + gen_bounded_ptr_add1(); + gen_bounded_ptr_add2(0); } else { gen_opc(op); } @@ -3503,10 +3551,16 @@ void vstore(void) /* store result */ vstore(); } else { + /* bound check case */ + if (vtop[-1].r & VT_MUSTBOUND) { + vswap(); + gbound(); + vswap(); + } rc = RC_INT; if (is_float(ft)) rc = RC_FLOAT; - r = gv(rc); /* generate value (XXX: move that to store code) */ + r = gv(rc); /* generate value */ /* if lvalue was saved on stack, must read it */ if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { SValue sv; @@ -4043,8 +4097,13 @@ void indir(void) if (vtop->r & VT_LVAL) gv(RC_INT); vtop->t = pointed_type(vtop->t); - if (!(vtop->t & VT_ARRAY)) /* an array is never an lvalue */ + /* an array is never an lvalue */ + if (!(vtop->t & VT_ARRAY)) { vtop->r |= VT_LVAL; + /* if bound checking, the referenced pointer must be checked */ + if (do_bounds_check) + vtop->r |= VT_MUSTBOUND; + } } /* pass a parameter to a function and do type checking and casting */ @@ -4659,7 +4718,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg) } else { gv(RC_IRET); } - vpop(); + vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ } skip(';'); rsym = gjmp(rsym); /* jmp */ @@ -5195,8 +5254,23 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init) if (ad->aligned > align) align = ad->aligned; if ((r & VT_VALMASK) == VT_LOCAL) { + if (do_bounds_check && (t & VT_ARRAY)) + loc--; loc = (loc - size) & -align; addr = loc; + /* handles bounds */ + /* XXX: currently, since we do only one pass, we cannot track + '&' operators, so we add only arrays */ + if (do_bounds_check && (t & VT_ARRAY)) { + int *bounds_ptr; + /* add padding between regions */ + loc--; + /* then add local bound info */ + bounds_ptr = (int *)lbounds_section->data_ptr; + *bounds_ptr++ = addr; + *bounds_ptr++ = size; + lbounds_section->data_ptr = (unsigned char *)bounds_ptr; + } } else { /* compute section */ sec = ad->section; @@ -5219,7 +5293,7 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init) int *bounds_ptr; /* first, we need to add at least one byte between each region */ data_offset++; - /* then add global data info */ + /* then add global bound info */ bounds_ptr = (int *)bounds_section->data_ptr; *bounds_ptr++ = addr; *bounds_ptr++ = size; @@ -6059,9 +6133,11 @@ int main(int argc, char **argv) } else if (r[1] == 'b') { if (!do_bounds_check) { do_bounds_check = 1; - /* create bounds section for global data */ + /* create bounds sections */ bounds_section = new_section(".bounds", SHT_PROGBITS, SHF_ALLOC); + lbounds_section = new_section(".lbounds", + SHT_PROGBITS, SHF_ALLOC); /* debug is implied */ goto debug_opt; }