diff --git a/i386-gen.c b/i386-gen.c index 647974f8..66af785a 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -1130,6 +1130,24 @@ ST_FUNC void gen_bounded_ptr_add(void) { /* save all temporary registers */ save_regs(0); + /* trick to get line/file_name in code */ + o(0xb8); + gen_le32 (file->line_num); + { + int i; + int len; + char *cp = file->filename; + while (*cp) cp++; + while (cp != file->filename && cp[-1] != '/') cp--; + len = strlen (cp); + while (len > 0) { + memcpy (&i, cp, 4); + o(0xb8); + gen_le32 (i); + cp += 4; + len -= 4; + } + } /* prepare fast i386 function call (args in eax and edx) */ gv2(RC_EAX, RC_EDX); vtop -= 2; @@ -1199,22 +1217,31 @@ ST_FUNC void gen_vla_sp_restore(int addr) { /* Subtract from the stack pointer, and push the resulting value onto the stack */ ST_FUNC void gen_vla_alloc(CType *type, int align) { -#ifdef TCC_TARGET_PE - /* alloca does more than just adjust %rsp on Windows */ - vpush_global_sym(&func_old_type, TOK_alloca); - vswap(); /* Move alloca ref past allocation size */ - gfunc_call(1); -#else - int r; - r = gv(RC_INT); /* allocation size */ - /* sub r,%rsp */ - o(0x2b); - o(0xe0 | r); - /* We align to 16 bytes rather than align */ - /* and ~15, %esp */ - o(0xf0e483); - vpop(); + int use_call = 0; + +#if defined(CONFIG_TCC_BCHECK) + use_call = tcc_state->do_bounds_check; #endif +#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */ + use_call = 1; +#endif + if (use_call) + { + vpush_global_sym(&func_old_type, TOK_alloca); + vswap(); /* Move alloca ref past allocation size */ + gfunc_call(1); + } + else { + int r; + r = gv(RC_INT); /* allocation size */ + /* sub r,%rsp */ + o(0x2b); + o(0xe0 | r); + /* We align to 16 bytes rather than align */ + /* and ~15, %esp */ + o(0xf0e483); + vpop(); + } } /* end of X86 code generator */ diff --git a/lib/bcheck.c b/lib/bcheck.c index 22d91a9b..bb716418 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -196,7 +196,7 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset) } if (addr <= tree->size) { addr += offset; - if (tree->is_invalid || addr >= tree->size) { + if (tree->is_invalid || addr > tree->size) { fprintf(stderr,"%s %s: %p is outside of the region\n", __FILE__, __FUNCTION__, p + offset); if (never_fatal == 0) { @@ -804,7 +804,7 @@ static void __bound_check(const void *p, size_t size) return; if (size == 0) return; - p = __bound_ptr_add((void *)p, size - 1); + p = __bound_ptr_add((void *)p, size); if (p == INVALID_POINTER) bound_error("invalid pointer"); } diff --git a/tccelf.c b/tccelf.c index 1e5b8c31..20fc20c5 100644 --- a/tccelf.c +++ b/tccelf.c @@ -591,7 +591,7 @@ version_add (TCCState *s1) prev = sv->prev_same_lib; if (sv->out_index > 0) { vna = section_ptr_add(verneed_section, sizeof(*vna)); - vna->vna_hash = elf_hash (sv->version); + vna->vna_hash = elf_hash ((const unsigned char *)sv->version); vna->vna_flags = 0; vna->vna_other = sv->out_index; sv->out_index = -2; @@ -599,7 +599,8 @@ version_add (TCCState *s1) vna->vna_next = sizeof (*vna); n_same_libs++; } - sv = &sym_versions[prev]; + if (prev >= 0) + sv = &sym_versions[prev]; } while(prev >= 0); vna->vna_next = 0; vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); diff --git a/tccgen.c b/tccgen.c index af119673..63d1ae23 100644 --- a/tccgen.c +++ b/tccgen.c @@ -2491,9 +2491,8 @@ redo: #endif } gen_op('*'); -#if 0 -/* #ifdef CONFIG_TCC_BCHECK - The main reason to removing this code: +#ifdef CONFIG_TCC_BCHECK + /* The main reason to removing this code: #include int main () { @@ -2506,10 +2505,11 @@ redo: When this code is on. then the output looks like v+i-j = 0xfffffffe v+(i-j) = 0xbff84000 + This should now work in updated bcheck.c version. */ /* if evaluating constant expression, no code should be generated, so no bound check */ - if (tcc_state->do_bounds_check && !const_wanted) { + if (tcc_state->do_bounds_check && !const_wanted && !nocode_wanted) { /* if bounded pointers, we generate a special code to test bounds */ if (op == '-') { diff --git a/tccpp.c b/tccpp.c index a6ad8218..3eb5213a 100644 --- a/tccpp.c +++ b/tccpp.c @@ -111,7 +111,9 @@ ST_FUNC void expect(const char *msg) /* ------------------------------------------------------------------------- */ /* Custom allocator for tiny objects */ +#ifndef __BOUNDS_CHECKING_ON #define USE_TAL +#endif #ifndef USE_TAL #define tal_free(al, p) tcc_free(p) @@ -390,15 +392,16 @@ ST_FUNC void cstr_reset(CString *cstr) ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...) { va_list v; + va_list vc; int len, size; va_start(v, fmt); - len = vsnprintf(NULL, 0, fmt, v); - va_end(v); + va_copy (vc, v); + len = vsnprintf(NULL, 0, fmt, vc); + va_end(vc); size = cstr->size + len + 1; if (size > cstr->size_allocated) cstr_realloc(cstr, size); - va_start(v, fmt); vsnprintf((char*)cstr->data + cstr->size, size, fmt, v); va_end(v); cstr->size += len; diff --git a/tests/tests2/46_grep.c b/tests/tests2/46_grep.c index 049dfb15..acda7930 100644 --- a/tests/tests2/46_grep.c +++ b/tests/tests2/46_grep.c @@ -456,11 +456,13 @@ char *pmatch(char *line, char *pattern) while (*l && (e = pmatch(l, p))) l = e; /* Get longest match */ while (*p++ != ENDPAT); /* Skip over pattern */ - while (l >= are) { /* Try to match rest */ + while (l > are) { /* Try to match rest */ if (e = pmatch(l, p)) return(e); --l; /* Nope, try earlier */ } + if (e = pmatch(l, p)) + return(e); return(0); /* Nothing else worked */ default: diff --git a/x86_64-gen.c b/x86_64-gen.c index e5d99fa7..803e6203 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -142,7 +142,9 @@ ST_DATA const int reg_classes[NB_REGS] = { static unsigned long func_sub_sp_offset; static int func_ret_sub; -static int in_call; +static int nested_call; +static int call_used_nr_reg; +static int call_used_regs[20]; /* XXX: make it faster ? */ ST_FUNC void g(int c) @@ -738,15 +740,55 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec) /* generate a bounded pointer addition */ ST_FUNC void gen_bounded_ptr_add(void) { + int i; + + nested_call++; + /* save all temporary registers */ save_regs(0); - if (in_call) { - o(0x51525657); /* push $rdi/%rsi/%rdx/%rcx */ - o(0x51415041); /* push $r8/%r9 */ - o(0x53415241); /* push $r10/%r11 */ + for (i = 0; i < call_used_nr_reg; i++) { + switch (call_used_regs[i]) { + case TREG_RAX: case TREG_RCX: case TREG_RDX: case TREG_RSP: + case TREG_RSI: case TREG_RDI: + o(0x50 + call_used_regs[i]); /* push reg */ + break; + case TREG_R8: case TREG_R9: case TREG_R10: case TREG_R11: + o(0x5041 + (call_used_regs[i] - TREG_R8) * 0x100); /* push reg */ + break; + case TREG_XMM0: case TREG_XMM1: case TREG_XMM2: case TREG_XMM3: + case TREG_XMM4: case TREG_XMM5: case TREG_XMM6: case TREG_XMM7: + o(0x10ec8348); /* sub $10,%rsp */ + /* vmovdqu %xmmx,(%rsp) */ + o(0x047ffac5 + (call_used_regs[i] - TREG_XMM0) * 0x8000000); o(0x24); + break; + } } + if (nested_call > 1) { +#ifdef TCC_TARGET_PE + o(0x5152); /* push %rcx/%rdx */ +#else + o(0x5657); /* push %rdi/%rsi */ +#endif + } + /* trick to get line/file_name in code */ + o(0xb8); + gen_le32 (file->line_num); + { + int len; + char *cp = file->filename; + while (*cp) cp++; + while (cp != file->filename && cp[-1] != '/') cp--; + len = strlen (cp); + while (len > 0) { + memcpy (&i, cp, 4); + o(0xb8); + gen_le32 (i); + cp += 4; + len -= 4; + } + } /* prepare fast x86_64 function call */ gv(RC_RAX); #ifdef TCC_TARGET_PE @@ -775,18 +817,38 @@ ST_FUNC void gen_bounded_ptr_add(void) o(0x20c48348); /* add $20, %rsp */ #endif + if (nested_call > 1) { +#ifdef TCC_TARGET_PE + o(0x5a59); /* pop %rcx/%rdx */ +#else + o(0x5f5e); /* pop %rsi/%rdi */ +#endif + } /* returned pointer is in rax */ vtop++; vtop->r = TREG_RAX | VT_BOUNDED; - if (in_call) { - o(0x5a415b41); /* pop $r11/%r10 */ - o(0x58415941); /* pop $r9/%r8 */ - o(0x5f5e5a59); /* pop $rcx/$rdx/$rsi/%rdi */ + for (i = call_used_nr_reg - 1; i >= 0; i--) { + switch (call_used_regs[i]) { + case TREG_RAX: case TREG_RCX: case TREG_RDX: case TREG_RSP: + case TREG_RSI: case TREG_RDI: + o(0x58 + call_used_regs[i]); /* pop reg */ + break; + case TREG_R8: case TREG_R9: case TREG_R10: case TREG_R11: + o(0x5841 + (call_used_regs[i] - TREG_R8) * 0x100); /* pop reg */ + break; + case TREG_XMM0: case TREG_XMM1: case TREG_XMM2: case TREG_XMM3: + case TREG_XMM4: case TREG_XMM5: case TREG_XMM6: case TREG_XMM7: + /* vmovdqu (%rsp),%xmmx */ + o(0x046ffac5 + (call_used_regs[i] - TREG_XMM0) * 0x8000000); o(0x24); + o(0x10c48348); /* add $10,%rsp */ + break; + } } /* relocation offset of the bounding function call point */ vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); + nested_call--; } /* patch pointer addition in vtop so that pointer dereferencing is @@ -913,8 +975,6 @@ void gfunc_call(int nb_args) int size, r, args_size, i, d, bt, struct_size; int arg; - in_call = 1; - args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; arg = nb_args; @@ -974,6 +1034,7 @@ void gfunc_call(int nb_args) } else { d = arg_prepare_reg(arg); gen_offs_sp(0x8d, d, struct_size); + call_used_regs[call_used_nr_reg++] = d; } struct_size += size; } else { @@ -992,6 +1053,7 @@ void gfunc_call(int nb_args) o(0x66); orex(1,d,0, 0x7e0f); o(0xc0 + arg*8 + REG_VALUE(d)); + call_used_regs[call_used_nr_reg++] = d; } } else { if (bt == VT_STRUCT) { @@ -1007,6 +1069,7 @@ void gfunc_call(int nb_args) d = arg_prepare_reg(arg); orex(1,d,r,0x89); /* mov */ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); + call_used_regs[call_used_nr_reg++] = d; } } } @@ -1045,7 +1108,7 @@ void gfunc_call(int nb_args) o(0xc089); /* mov %eax,%eax */ #endif vtop--; - in_call = 0; + call_used_nr_reg = 0; } @@ -1399,8 +1462,6 @@ void gfunc_call(int nb_args) int sse_reg, gen_reg; char _onstack[nb_args ? nb_args : 1], *onstack = _onstack; - in_call = 1; - /* calculate the number of integer/float register arguments, remember arguments to be passed via stack (in onstack[]), and also remember if we have to align the stack pointer to 16 (onstack[i] == 2). Needs @@ -1533,11 +1594,14 @@ void gfunc_call(int nb_args) o(0x280f); o(0xc0 + (sse_reg << 3)); } + call_used_regs[call_used_nr_reg++] = sse_reg + TREG_XMM0; + call_used_regs[call_used_nr_reg++] = sse_reg + 1 + TREG_XMM0; } else { assert(reg_count == 1); --sse_reg; /* Load directly to register */ gv(RC_XMM0 << sse_reg); + call_used_regs[call_used_nr_reg++] = sse_reg + TREG_XMM0; } } else if (mode == x86_64_mode_integer) { /* simple type */ @@ -1548,10 +1612,12 @@ void gfunc_call(int nb_args) d = arg_prepare_reg(gen_reg); orex(1,d,r,0x89); /* mov */ o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); + call_used_regs[call_used_nr_reg++] = d; if (reg_count == 2) { d = arg_prepare_reg(gen_reg+1); orex(1,d,vtop->r2,0x89); /* mov */ o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); + call_used_regs[call_used_nr_reg++] = d; } } vtop--; @@ -1594,7 +1660,7 @@ void gfunc_call(int nb_args) else if (bt == (VT_SHORT | VT_UNSIGNED)) o(0xc0b70f); /* movzwl %al, %eax */ vtop--; - in_call = 0; + call_used_nr_reg = 0; } @@ -2386,22 +2452,31 @@ ST_FUNC void gen_vla_result(int addr) { /* Subtract from the stack pointer, and push the resulting value onto the stack */ ST_FUNC void gen_vla_alloc(CType *type, int align) { -#ifdef TCC_TARGET_PE - /* alloca does more than just adjust %rsp on Windows */ - vpush_global_sym(&func_old_type, TOK_alloca); - vswap(); /* Move alloca ref past allocation size */ - gfunc_call(1); -#else - int r; - r = gv(RC_INT); /* allocation size */ - /* sub r,%rsp */ - o(0x2b48); - o(0xe0 | REG_VALUE(r)); - /* We align to 16 bytes rather than align */ - /* and ~15, %rsp */ - o(0xf0e48348); - vpop(); + int use_call = 0; + +#if defined(CONFIG_TCC_BCHECK) + use_call = tcc_state->do_bounds_check; #endif +#ifdef TCC_TARGET_PE /* alloca does more than just adjust %rsp on Windows */ + use_call = 1; +#endif + if (use_call) + { + vpush_global_sym(&func_old_type, TOK_alloca); + vswap(); /* Move alloca ref past allocation size */ + gfunc_call(1); + } + else { + int r; + r = gv(RC_INT); /* allocation size */ + /* sub r,%rsp */ + o(0x2b48); + o(0xe0 | REG_VALUE(r)); + /* We align to 16 bytes rather than align */ + /* and ~15, %rsp */ + o(0xf0e48348); + vpop(); + } } diff --git a/x86_64-link.c b/x86_64-link.c index 61c2d1b0..dcb2b90c 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -155,7 +155,7 @@ ST_FUNC void relocate_plt(TCCState *s1) add32le(p + 8, x - 6); p += 16; while (p < p_end) { - add32le(p + 2, x + s1->plt->data - p); + add32le(p + 2, x + (s1->plt->data - p)); p += 16; } }