summaryrefslogtreecommitdiff
path: root/x86_64-gen.c
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2015-12-26 18:15:30 +0800
committerThomas Preud'homme <robotux@celest.fr>2015-12-26 18:15:30 +0800
commit9b58ceece89525bc832012f7b877de5615b12829 (patch)
tree9c085e51cc8754463d27fac5d516fe9d7533c3c6 /x86_64-gen.c
parent2946895a376add9d940bdbe4391e97cb846d26d1 (diff)
Imported Upstream version 0.9.27~git20151225.f15c0a9
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r--x86_64-gen.c211
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, &reg_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, &reg_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
}