diff options
author | Thomas Preud'homme <robotux@celest.fr> | 2015-12-26 18:15:30 +0800 |
---|---|---|
committer | Thomas Preud'homme <robotux@celest.fr> | 2015-12-26 18:15:30 +0800 |
commit | 9b58ceece89525bc832012f7b877de5615b12829 (patch) | |
tree | 9c085e51cc8754463d27fac5d516fe9d7533c3c6 /x86_64-gen.c | |
parent | 2946895a376add9d940bdbe4391e97cb846d26d1 (diff) |
Imported Upstream version 0.9.27~git20151225.f15c0a9
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r-- | x86_64-gen.c | 211 |
1 files changed, 165 insertions, 46 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c index c8fed85..692b420 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -77,7 +77,7 @@ enum { TREG_ST0 = 24, - TREG_MEM = 0x20, + TREG_MEM = 0x20 }; #define REX_BASE(reg) (((reg) >> 3) & 1) @@ -214,11 +214,10 @@ void orex(int ll, int r, int r2, int b) /* output a symbol and patch all calls to it */ void gsym_addr(int t, int a) { - int n, *ptr; while (t) { - ptr = (int *)(cur_text_section->data + t); - n = *ptr; /* next value */ - *ptr = a - t - 4; + unsigned char *ptr = cur_text_section->data + t; + uint32_t n = read32le(ptr); /* next value */ + write32le(ptr, a - t - 4); t = n; } } @@ -248,7 +247,7 @@ ST_FUNC int oad(int c, int s) ind1 = ind + 4; if (ind1 > cur_text_section->data_allocated) section_realloc(cur_text_section, ind1); - *(int *)(cur_text_section->data + ind) = s; + write32le(cur_text_section->data + ind, s); s = ind; ind = ind1; return s; @@ -368,7 +367,7 @@ void load(int r, SValue *sv) fr = sv->r; ft = sv->type.t & ~VT_DEFSIGN; - fc = sv->c.ul; + fc = sv->c.i; #ifndef TCC_TARGET_PE /* we use indirect access via got */ @@ -393,9 +392,9 @@ void load(int r, SValue *sv) if (v == VT_LLOCAL) { v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; - v1.c.ul = fc; + v1.c.i = fc; fr = r; - if (!(reg_classes[fr] & RC_INT)) + if (!(reg_classes[fr] & (RC_INT|RC_R11))) fr = get_reg(RC_INT); load(fr, &v1); } @@ -449,7 +448,7 @@ void load(int r, SValue *sv) #endif } else if (is64_type(ft)) { orex(1,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ - gen_le64(sv->c.ull); + gen_le64(sv->c.i); } else { orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */ gen_le32(fc); @@ -531,7 +530,7 @@ void store(int r, SValue *v) #endif ft = v->type.t; - fc = v->c.ul; + fc = v->c.i; fr = v->r & VT_VALMASK; bt = ft & VT_BTYPE; @@ -540,7 +539,7 @@ void store(int r, SValue *v) if (fr == VT_CONST && (v->r & VT_SYM)) { /* mov xx(%rip), %r11 */ o(0x1d8b4c); - gen_gotpcrel(TREG_R11, v->sym, v->c.ul); + gen_gotpcrel(TREG_R11, v->sym, v->c.i); pic = is64_type(bt) ? 0x49 : 0x41; } #endif @@ -600,7 +599,8 @@ void store(int r, SValue *v) static void gcall_or_jmp(int is_jmp) { int r; - if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && + ((vtop->r & VT_SYM) || (vtop->c.i-4) == (int)(vtop->c.i-4))) { /* constant case */ if (vtop->r & VT_SYM) { /* relocation case */ @@ -614,7 +614,7 @@ static void gcall_or_jmp(int is_jmp) put_elf_reloc(symtab_section, cur_text_section, ind + 1, R_X86_64_PC32, 0); } - oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */ + oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ } else { /* otherwise, indirect call */ r = TREG_R11; @@ -625,6 +625,90 @@ static void gcall_or_jmp(int is_jmp) } } +#if defined(CONFIG_TCC_BCHECK) +#ifndef TCC_TARGET_PE +static addr_t func_bound_offset; +static unsigned long func_bound_ind; +#endif + +static void gen_static_call(int v) +{ + Sym *sym = external_global_sym(v, &func_old_type, 0); + oad(0xe8, -4); + greloc(cur_text_section, sym, ind-4, R_X86_64_PC32); +} + +/* generate a bounded pointer addition */ +ST_FUNC void gen_bounded_ptr_add(void) +{ + /* save all temporary registers */ + save_regs(0); + + /* prepare fast x86_64 function call */ + gv(RC_RAX); + o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size + vtop--; + + gv(RC_RAX); + o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr + vtop--; + + /* do a fast function call */ + gen_static_call(TOK___bound_ptr_add); + + /* returned pointer is in rax */ + vtop++; + vtop->r = TREG_RAX | VT_BOUNDED; + + + /* relocation offset of the bounding function call point */ + vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); +} + +/* patch pointer addition in vtop so that pointer dereferencing is + also tested */ +ST_FUNC void gen_bounded_ptr_deref(void) +{ + addr_t func; + int size, align; + ElfW(Rela) *rel; + Sym *sym; + + size = 0; + /* XXX: put that code in generic part of tcc */ + if (!is_float(vtop->type.t)) { + if (vtop->r & VT_LVAL_BYTE) + size = 1; + else if (vtop->r & VT_LVAL_SHORT) + size = 2; + } + if (!size) + size = type_size(&vtop->type, &align); + switch(size) { + case 1: func = TOK___bound_ptr_indir1; break; + case 2: func = TOK___bound_ptr_indir2; break; + case 4: func = TOK___bound_ptr_indir4; break; + case 8: func = TOK___bound_ptr_indir8; break; + case 12: func = TOK___bound_ptr_indir12; break; + case 16: func = TOK___bound_ptr_indir16; break; + default: + tcc_error("unhandled size when dereferencing bounded pointer"); + func = 0; + break; + } + + sym = external_global_sym(func, &func_old_type, 0); + if (!sym->c) + put_extern_sym(sym, NULL, 0, 0); + + /* patch relocation */ + /* XXX: find a better solution ? */ + + 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)); +} +#endif + #ifdef TCC_TARGET_PE #define REGN 4 @@ -662,9 +746,10 @@ void gen_offs_sp(int b, int r, int d) /* Return the number of registers needed to return the struct, or 0 if returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { int size, align; + *regsize = 8; *ret_align = 1; // Never have to re-align return values for x86-64 size = type_size(vt, &align); ret->ref = NULL; @@ -980,12 +1065,8 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) case VT_STRUCT: f = ty->ref; - // Detect union - if (f->next && (f->c == f->next->c)) - return x86_64_mode_memory; - mode = x86_64_mode_none; - for (; f; f = f->next) + for (f = f->next; f; f = f->next) mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); return mode; @@ -1069,10 +1150,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) /* Return the number of registers needed to return the struct, or 0 if returning via struct pointer. */ -ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) +ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { int size, align, reg_count; *ret_align = 1; // Never have to re-align return values for x86-64 + *regsize = 8; return (classify_x86_64_arg(vt, ret, &size, &align, ®_count) != x86_64_mode_memory); } @@ -1171,12 +1253,12 @@ void gfunc_call(int nb_args) in on the stack and swap it back to its original position if it is a register. */ SValue tmp = vtop[0]; + int arg_stored = 1; + vtop[0] = vtop[-i]; vtop[-i] = tmp; - mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, ®_count); - int arg_stored = 1; switch (vtop->type.t & VT_BTYPE) { case VT_STRUCT: if (mode == x86_64_mode_sse) { @@ -1330,9 +1412,10 @@ void gfunc_call(int nb_args) } else if (mode == x86_64_mode_integer) { /* simple type */ /* XXX: implicit cast ? */ + int d; gen_reg -= reg_count; r = gv(RC_INT); - int d = arg_prepare_reg(gen_reg); + d = arg_prepare_reg(gen_reg); orex(1,d,r,0x89); /* mov */ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); if (reg_count == 2) { @@ -1485,7 +1568,6 @@ void gfunc_prolog(CType *func_type) addr = (addr + align - 1) & -align; param_addr = addr; addr += size; - sse_param_index += reg_count; } break; @@ -1509,7 +1591,6 @@ void gfunc_prolog(CType *func_type) addr = (addr + align - 1) & -align; param_addr = addr; addr += size; - reg_param_index += reg_count; } break; } @@ -1518,6 +1599,17 @@ void gfunc_prolog(CType *func_type) sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, param_addr); } + +#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 */ + o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ + oad(0xb8, 0); /* call to function */ + } +#endif } /* generate function epilog */ @@ -1525,6 +1617,37 @@ 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; + greloc(cur_text_section, sym_data, ind + 1, R_386_32); + ind = ind + 5 + 3; + 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 xxx, %rax */ + o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ + gen_static_call(TOK___bound_local_delete); + o(0x585a); /* restore returned value, if any */ + } +#endif o(0xc9); /* leave */ if (func_ret_sub == 0) { o(0xc3); /* ret */ @@ -1567,9 +1690,7 @@ void gjmp_addr(int a) /* generate a test. set 'inv' to invert test. Stack entry is popped */ int gtst(int inv, int t) { - int v, *p; - - v = vtop->r & VT_VALMASK; + int v = vtop->r & VT_VALMASK; if (v == VT_CMP) { /* fast case : can jump directly since flags are set */ if (vtop->c.i & 0x100) @@ -1582,7 +1703,7 @@ int gtst(int inv, int t) to our target if the result was unordered and test wasn't NE, otherwise if unordered we don't want to jump. */ vtop->c.i &= ~0x100; - if (!inv == (vtop->c.i != TOK_NE)) + if (inv == (vtop->c.i == TOK_NE)) o(0x067a); /* jp +6 */ else { @@ -1592,15 +1713,17 @@ int gtst(int inv, int t) } g(0x0f); t = psym((vtop->c.i - 16) ^ inv, t); - } else { /* VT_JMP || VT_JMPI */ + } else if (v == VT_JMP || v == VT_JMPI) { /* && or || optimization */ if ((v & 1) == inv) { /* insert vtop->c jump list in t */ - p = &vtop->c.i; - while (*p != 0) - p = (int *)(cur_text_section->data + *p); - *p = t; - t = vtop->c.i; + uint32_t n1, n = vtop->c.i; + if (n) { + while ((n1 = read32le(cur_text_section->data + n))) + n = n1; + write32le(cur_text_section->data + n, t); + t = vtop->c.i; + } } else { t = gjmp(t); gsym(vtop->c.i); @@ -1625,7 +1748,7 @@ void gen_opi(int op) case TOK_ADDC1: /* add with carry generation */ opc = 0; gen_op8: - if (cc && (!ll || (int)vtop->c.ll == vtop->c.ll)) { + if (cc && (!ll || (int)vtop->c.i == vtop->c.i)) { /* constant case */ vswap(); r = gv(RC_INT); @@ -1833,7 +1956,7 @@ void gen_opf(int op) break; } ft = vtop->type.t; - fc = vtop->c.ul; + fc = vtop->c.i; o(0xde); /* fxxxp %st, %st(1) */ o(0xc1 + (a << 3)); vtop--; @@ -1842,13 +1965,13 @@ void gen_opf(int op) if (op >= TOK_ULT && op <= TOK_GT) { /* if saved lvalue, then we must reload it */ r = vtop->r; - fc = vtop->c.ul; + fc = vtop->c.i; if ((r & VT_VALMASK) == VT_LLOCAL) { SValue v1; r = get_reg(RC_INT); v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; - v1.c.ul = fc; + v1.c.i = fc; load(r, &v1); fc = 0; } @@ -1905,7 +2028,7 @@ void gen_opf(int op) break; } ft = vtop->type.t; - fc = vtop->c.ul; + fc = vtop->c.i; assert((ft & VT_BTYPE) != VT_LDOUBLE); r = vtop->r; @@ -1915,7 +2038,7 @@ void gen_opf(int op) r = get_reg(RC_INT); v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; - v1.c.ul = fc; + v1.c.i = fc; load(r, &v1); fc = 0; } @@ -2117,11 +2240,7 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) { /* We align to 16 bytes rather than align */ /* and ~15, %rsp */ o(0xf0e48348); - /* mov %rsp, r */ - o(0x8948); - o(0xe0 | REG_VALUE(r)); vpop(); - vset(type, r, 0); #endif } |