aboutsummaryrefslogtreecommitdiff
path: root/x86_64-gen.c
diff options
context:
space:
mode:
authorseyko <seyko2@gmail.com>2015-04-10 15:17:22 +0300
committerseyko <seyko2@gmail.com>2015-04-10 15:17:22 +0300
commit559675b90acec03b67ed3f2cece1940f00e44c49 (patch)
tree3875745ba543b7b8bb8474d9b7910272fcf75b9d /x86_64-gen.c
parente92dc595cd10405b3ed14b2663affeb50b47e169 (diff)
downloadtinycc-559675b90acec03b67ed3f2cece1940f00e44c49.tar.gz
tinycc-559675b90acec03b67ed3f2cece1940f00e44c49.tar.bz2
a bounds checking code for the ARCH=x86_64
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r--x86_64-gen.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c
index d5ed4f6..0083f8b 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -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.ull = (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.ull);
+ rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
+}
+#endif
+
#ifdef TCC_TARGET_PE
#define REGN 4
@@ -1520,6 +1604,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 */
@@ -1527,6 +1622,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 */