diff --git a/lib/bcheck.c b/lib/bcheck.c index 90f0ad2..7641532 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -28,6 +28,19 @@ && !defined(__OpenBSD__) \ && !defined(__NetBSD__) #include +#include +#include +#include +static sem_t bounds_sem; +#define INIT_SEM() sem_init (&bounds_sem, 0, 1) +#define WAIT_SEM() while (sem_wait (&bounds_sem) < 0 && errno == EINTR); +#define POST_SEM() sem_post (&bounds_sem) +#define HAS_BACKTRACE 1 +#else +#define INIT_SEM() +#define WAIT_SEM() +#define POST_SEM() +#define HAS_BACKTRACE 0 #endif #if !defined(_WIN32) @@ -65,7 +78,7 @@ #define BOUND_T1_BITS 13 #define BOUND_T2_BITS 11 #define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS) -#define BOUND_E_BITS (sizeof(size_t)) +#define BOUND_E_BITS (sizeof(size_t) == 4 ? 4 : 5) #define BOUND_T1_SIZE ((size_t)1 << BOUND_T1_BITS) #define BOUND_T2_SIZE ((size_t)1 << BOUND_T2_BITS) @@ -94,6 +107,9 @@ void __bound_init(void); void __bound_new_region(void *p, size_t size); int __bound_delete_region(void *p); +/* debug */ +void bound_dump(void); + #ifdef __attribute__ /* an __attribute__ macro is defined in the system headers */ #undef __attribute__ @@ -132,6 +148,8 @@ static BoundEntry **__bound_t1; /* page table */ static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */ static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */ +static never_fatal = 0; + static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) { size_t addr, tmp; @@ -141,7 +159,7 @@ static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) while (e != NULL) { addr = (size_t)p; addr -= e->start; - if (addr <= e->size) { + if (addr < e->size) { /* put region at the head */ tmp = e1->start; e1->start = e->start; @@ -149,6 +167,9 @@ static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) tmp = e1->size; e1->size = e->size; e->size = tmp; + tmp = e1->is_invalid; + e1->is_invalid = e->is_invalid; + e->is_invalid = tmp; return e1; } e = e->next; @@ -165,7 +186,23 @@ static void bound_error(const char *fmt, ...) { __bound_error_msg = fmt; fprintf(stderr,"%s %s: %s\n", __FILE__, __FUNCTION__, fmt); - *(void **)0 = 0; /* force a runtime error */ +#if HAS_BACKTRACE + restore_malloc_hooks(); + { + void *bt[10]; + int c; + int n = backtrace (bt, sizeof (bt) / sizeof (bt[0])); + char **s = backtrace_symbols (bt, n); + + for (c = 0; c < n; c++) { + fprintf (stderr, "%s\n", s[c]); + } + free (s); + } + install_malloc_hooks(); +#endif + if (never_fatal == 0) + *(void **)0 = 0; /* force a runtime error */ } static void bound_alloc_error(void) @@ -180,26 +217,31 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset) size_t addr = (size_t)p; BoundEntry *e; - dprintf(stderr, "%s %s: %p %x\n", + dprintf(stderr, "%s %s: %p 0x%x\n", __FILE__, __FUNCTION__, p, (unsigned)offset); __bound_init(); + WAIT_SEM (); e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; e = (BoundEntry *)((char *)e + ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); addr -= e->start; - if (addr > e->size) { + if (addr >= e->size) { e = __bound_find_region(e, p); addr = (size_t)p - e->start; } addr += offset; - if (addr >= e->size) { + if (addr > e->size) { fprintf(stderr,"%s %s: %p is outside of the region\n", __FILE__, __FUNCTION__, p + offset); - return INVALID_POINTER; /* return an invalid pointer */ + if (never_fatal == 0) { + POST_SEM (); + return INVALID_POINTER; /* return an invalid pointer */ + } } + POST_SEM (); return p + offset; } @@ -211,27 +253,32 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ size_t addr = (size_t)p; \ BoundEntry *e; \ \ - dprintf(stderr, "%s %s: %p %x start\n", \ + dprintf(stderr, "%s %s: %p 0x%x start\n", \ __FILE__, __FUNCTION__, p, (unsigned)offset); \ \ __bound_init(); \ + WAIT_SEM (); \ e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \ e = (BoundEntry *)((char *)e + \ ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \ ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \ addr -= e->start; \ - if (addr > e->size) { \ + if (addr >= e->size) { \ e = __bound_find_region(e, p); \ addr = (size_t)p - e->start; \ } \ addr += offset + dsize; \ - if (addr > e->size) { \ + if (addr > e->size) { \ fprintf(stderr,"%s %s: %p is outside of the region\n", \ __FILE__, __FUNCTION__, p + offset); \ - return INVALID_POINTER; /* return an invalid pointer */ \ + if (never_fatal == 0) { \ + POST_SEM (); \ + return INVALID_POINTER; /* return an invalid pointer */ \ + } \ } \ dprintf(stderr, "%s %s: return p+offset = %p\n", \ __FILE__, __FUNCTION__, p + offset); \ + POST_SEM (); \ return p + offset; \ } @@ -262,8 +309,8 @@ void FASTCALL __bound_local_new(void *p1) { size_t addr, size, fp, *p = p1; - dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p); GET_CALLER_FP(fp); + dprintf(stderr, "%s, %s local new p1=%p fp=%p\n", __FILE__, __FUNCTION__, p, fp); for(;;) { addr = p[0]; if (addr == 0) @@ -281,6 +328,7 @@ void FASTCALL __bound_local_delete(void *p1) { size_t addr, fp, *p = p1; GET_CALLER_FP(fp); + dprintf(stderr, "%s, %s local delete p1=%p fp=%p\n", __FILE__, __FUNCTION__, p, fp); for(;;) { addr = p[0]; if (addr == 0) @@ -317,13 +365,17 @@ static BoundEntry *__bound_new_page(void) static BoundEntry *bound_new_entry(void) { BoundEntry *e; - e = libc_malloc(sizeof(BoundEntry)); + restore_malloc_hooks(); + e = malloc(sizeof(BoundEntry)); + install_malloc_hooks(); return e; } static void bound_free_entry(BoundEntry *e) { - libc_free(e); + restore_malloc_hooks(); + free(e); + install_malloc_hooks(); } static BoundEntry *get_page(size_t index) @@ -345,6 +397,8 @@ static void mark_invalid(size_t addr, size_t size) BoundEntry *page; size_t t1_start, t1_end, i, j, t2_start, t2_end; + dprintf(stderr, "mark_invalid: start = %lx, size = %lx\n", (unsigned long) addr, (unsigned long) size); + start = addr; end = addr + size; @@ -354,9 +408,7 @@ static void mark_invalid(size_t addr, size_t size) else t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS); -#if 0 - dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end); -#endif + dprintf(stderr, "mark_invalid: start = %lx, end = %lx\n", (unsigned long) t2_start, (unsigned long) t2_end); /* first we handle full pages */ t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS; @@ -407,6 +459,9 @@ void __bound_init(void) dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__); + never_fatal = getenv ("TCC_BOUNDS_NEVER_FATAL") != NULL; + INIT_SEM (); + /* save malloc hooks and install bound check hooks */ install_malloc_hooks(); @@ -467,20 +522,25 @@ void __bound_init(void) mark_invalid(start, size); #endif + dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__); +} + +void __bounds_add_static_var (size_t *p) +{ /* add all static bound check values */ - p = (size_t *)&__bounds_start; while (p[0] != 0) { __bound_new_region((void *)p[0], p[1]); p += 2; } - - dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__); } -void __bound_main_arg(void **p) +void __bound_main_arg(char **p) { void *start = p; - while (*p++); + while (*p) { + __bound_new_region(*p, strlen (*p) + 1); + p++; + } dprintf(stderr, "%s, %s calling __bound_new_region(%p %x)\n", __FILE__, __FUNCTION__, start, (unsigned)((void *)p - start)); @@ -508,9 +568,11 @@ static inline void add_region(BoundEntry *e, e1->start = e->start; e1->size = e->size; e1->next = e->next; + e1->is_invalid = e->is_invalid; e->start = start; e->size = size; e->next = e1; + e1->is_invalid = 0; } } @@ -526,8 +588,9 @@ void __bound_new_region(void *p, size_t size) __bound_init(); + WAIT_SEM (); start = (size_t)p; - end = start + size; + end = start + size - 1; t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); @@ -579,6 +642,7 @@ void __bound_new_region(void *p, size_t size) } add_region(e, start, size); } + POST_SEM (); dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__); } @@ -591,7 +655,7 @@ static inline void delete_region(BoundEntry *e, void *p, size_t empty_size) addr = (size_t)p; addr -= e->start; - if (addr <= e->size) { + if (addr < e->size) { /* region found is first one */ e1 = e->next; if (e1 == NULL) { @@ -603,6 +667,7 @@ static inline void delete_region(BoundEntry *e, void *p, size_t empty_size) e->start = e1->start; e->size = e1->size; e->next = e1->next; + e->is_invalid = e1->is_invalid; bound_free_entry(e1); } } else { @@ -614,7 +679,7 @@ static inline void delete_region(BoundEntry *e, void *p, size_t empty_size) if (e == NULL) break; addr = (size_t)p - e->start; - if (addr <= e->size) { + if (addr < e->size) { /* found: remove entry */ e1->next = e->next; bound_free_entry(e); @@ -632,10 +697,11 @@ int __bound_delete_region(void *p) BoundEntry *page, *e, *e2; size_t t1_start, t1_end, t2_start, t2_end, i; - dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__); + dprintf(stderr, "%s %s(%p) start\n", __FILE__, __FUNCTION__, p); __bound_init(); + WAIT_SEM (); start = (size_t)p; t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & @@ -648,15 +714,18 @@ int __bound_delete_region(void *p) if (addr > e->size) e = __bound_find_region(e, p); /* test if invalid region */ - if (e->size == EMPTY_SIZE || (size_t)p != e->start) + if (e->size == EMPTY_SIZE || (size_t)p != e->start) { + POST_SEM (); return -1; + } + /* compute the size we put in invalid regions */ if (e->is_invalid) empty_size = INVALID_SIZE; else empty_size = EMPTY_SIZE; size = e->size; - end = start + size; + end = start + size - 1; /* now we can free each entry */ t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); @@ -702,6 +771,7 @@ int __bound_delete_region(void *p) } delete_region(e, p, empty_size); } + POST_SEM (); dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__); @@ -713,8 +783,10 @@ int __bound_delete_region(void *p) static size_t get_region_size(void *p) { size_t addr = (size_t)p; + size_t size; BoundEntry *e; + WAIT_SEM (); e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; e = (BoundEntry *)((char *)e + ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & @@ -723,8 +795,11 @@ static size_t get_region_size(void *p) if (addr > e->size) e = __bound_find_region(e, p); if (e->start != (size_t)p) - return EMPTY_SIZE; - return e->size; + size = EMPTY_SIZE; + else + size = e->size; + POST_SEM (); + return size; } /* patched memory functions */ @@ -763,17 +838,21 @@ static void restore_malloc_hooks(void) static void *libc_malloc(size_t size) { void *ptr; + WAIT_SEM (); restore_malloc_hooks(); ptr = malloc(size); install_malloc_hooks(); + POST_SEM (); return ptr; } static void libc_free(void *ptr) { + WAIT_SEM (); restore_malloc_hooks(); free(ptr); install_malloc_hooks(); + POST_SEM (); } /* XXX: we should use a malloc which ensure that it is unlikely that @@ -802,6 +881,7 @@ void *__bound_memalign(size_t size, size_t align, const void *caller) { void *ptr; + WAIT_SEM (); restore_malloc_hooks(); #ifndef HAVE_MEMALIGN @@ -820,6 +900,7 @@ void *__bound_memalign(size_t size, size_t align, const void *caller) #endif install_malloc_hooks(); + POST_SEM (); if (!ptr) return NULL; @@ -836,7 +917,11 @@ void __bound_free(void *ptr, const void *caller) if (ptr == NULL) return; if (__bound_delete_region(ptr) != 0) - bound_error("freeing invalid region"); +#if 0 /* glibc thread code fails with this */ + bound_error("freeing invalid region") +#endif + ; + libc_free(ptr); } @@ -856,7 +941,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller) old_size = get_region_size(ptr); if (old_size == EMPTY_SIZE) bound_error("realloc'ing invalid pointer"); - memcpy(ptr1, ptr, old_size); + memcpy(ptr1, ptr, old_size < size ? old_size : size); __bound_free(ptr, caller); return ptr1; } @@ -875,8 +960,7 @@ void *__bound_calloc(size_t nmemb, size_t size) } #endif -#if 0 -static void bound_dump(void) +void bound_dump(void) { BoundEntry *page, *e; size_t i, j; @@ -888,11 +972,15 @@ static void bound_dump(void) e = page + j; /* do not print invalid or empty entries */ if (e->size != EMPTY_SIZE && e->start != 0) { - fprintf(stderr, "%08x:", - (i << (BOUND_T2_BITS + BOUND_T3_BITS)) + - (j << BOUND_T3_BITS)); + fprintf(stderr, "%016lx:", + (unsigned long) + ((i << (BOUND_T2_BITS + BOUND_T3_BITS)) + + (j << BOUND_T3_BITS))); do { - fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size); + fprintf(stderr, " %p:%p(%u)", + (void *) e->start, + (void *) (e->start + e->size), + (unsigned)e->is_invalid); e = e->next; } while (e != NULL); fprintf(stderr, "\n"); @@ -900,7 +988,6 @@ static void bound_dump(void) } } } -#endif /* some useful checked functions */ diff --git a/tccelf.c b/tccelf.c index 70e4f87..4a7bb6e 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1322,14 +1322,15 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1) #ifdef CONFIG_TCC_BCHECK addr_t *ptr; int sym_index; + int bsym_index; if (0 == s1->do_bounds_check) return; /* XXX: add an object file to do that */ ptr = section_ptr_add(bounds_section, sizeof(*ptr)); *ptr = 0; - set_elf_sym(symtab_section, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + bsym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE), 0, bounds_section->sh_num, "__bounds_start"); /* pull bcheck.o from libtcc1.a */ sym_index = set_elf_sym(symtab_section, 0, 0, @@ -1344,6 +1345,24 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1) put_elf_reloc(symtab_section, init_section, init_section->data_offset - 4, R_386_PC32, sym_index); /* R_386_PC32 = R_X86_64_PC32 = 2 */ + pinit = section_ptr_add(init_section, 13); + pinit[0] = 0x48; /* mov xx,%rax */ + pinit[1] = 0xb8; + write64le(pinit + 2, 0); + pinit[10] = 0x48; /* mov %rax,%rdi */ + pinit[11] = 0x89; + pinit[12] = 0xc7; + put_elf_reloc(symtab_section, init_section, + init_section->data_offset - 11, R_X86_64_64, bsym_index); + sym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_UNDEF, "__bounds_add_static_var"); + pinit = section_ptr_add(init_section, 5); + pinit[0] = 0xe8; + write32le(pinit + 1, -4); + put_elf_reloc(symtab_section, init_section, + init_section->data_offset - 4, R_386_PC32, sym_index); + /* R_386_PC32 = R_X86_64_PC32 = 2 */ } #endif } @@ -1366,7 +1385,12 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) tcc_add_dll(s1, TCC_LIBGCC, 0); } #endif - tcc_add_support(s1, TCC_LIBTCC1); +#ifdef CONFIG_TCC_BCHECK + if (s1->do_bounds_check) + tcc_add_library_err(s1, "pthread"); + if (s1->do_bounds_check == 0 || s1->output_type != TCC_OUTPUT_DLL) +#endif + tcc_add_support(s1, TCC_LIBTCC1); /* add crt end if not memory output */ if (s1->output_type != TCC_OUTPUT_MEMORY) tcc_add_crt(s1, "crtn.o"); @@ -2814,6 +2838,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) const char *ar_names, *p; const uint8_t *ar_index; ElfW(Sym) *sym; + Section *s; data = tcc_malloc(size); if (full_read(fd, data, size) != size) @@ -2825,9 +2850,14 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) do { bound = 0; for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { - sym_index = find_elf_sym(symtab_section, p); + s = symtab_section; + sym_index = find_elf_sym(s, p); + if(sym_index == 0) { + s = s1->dynsymtab_section; + sym_index = find_elf_sym(s, p); + } if(sym_index) { - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; + sym = &((ElfW(Sym) *)s->data)[sym_index]; if(sym->st_shndx == SHN_UNDEF) { off = (entrysize == 4 ? get_be32(ar_index + i * 4) diff --git a/tccgen.c b/tccgen.c index a6181b0..415a722 100644 --- a/tccgen.c +++ b/tccgen.c @@ -74,7 +74,7 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ -ST_DATA const char *funcname; +const char *funcname; ST_DATA int g_debug; ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; @@ -1375,7 +1375,7 @@ static void gbound(void) vtop->r &= ~VT_MUSTBOUND; /* if lvalue, then use checking code before dereferencing */ - if (vtop->r & VT_LVAL) { + if ((vtop->r & VT_LVAL) && !nocode_wanted) { /* if not VT_BOUNDED value, then make one */ if (!(vtop->r & VT_BOUNDED)) { lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); @@ -7413,7 +7413,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if ((r & VT_VALMASK) == VT_LOCAL) { sec = NULL; #ifdef CONFIG_TCC_BCHECK - if (bcheck && (type->t & VT_ARRAY)) { + if (bcheck && ((type->t & VT_ARRAY) || + (type->t & VT_BTYPE) == VT_STRUCT)) { loc--; } #endif @@ -7422,8 +7423,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, #ifdef CONFIG_TCC_BCHECK /* handles bounds */ /* XXX: currently, since we do only one pass, we cannot track - '&' operators, so we add only arrays */ - if (bcheck && (type->t & VT_ARRAY)) { + '&' operators, so we add only arrays/structs/unions */ + if (bcheck && ((type->t & VT_ARRAY) || + (type->t & VT_BTYPE) == VT_STRUCT)) { addr_t *bounds_ptr; /* add padding between regions */ loc--; diff --git a/x86_64-gen.c b/x86_64-gen.c index cc66b60..45e3016 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -641,11 +641,15 @@ static addr_t func_bound_offset; static unsigned long func_bound_ind; #endif -static void gen_static_call(int v) +static void gen_bounds_call(int v) { Sym *sym = external_global_sym(v, &func_old_type); oad(0xe8, 0); +#ifdef TCC_TARGET_PE greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4); +#else + greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4); +#endif } /* generate a bounded pointer addition */ @@ -654,6 +658,10 @@ ST_FUNC void gen_bounded_ptr_add(void) /* save all temporary registers */ save_regs(0); + o(0x51525657); /* push $rdi/%rsi/%rdx/%rcx */ + o(0x51415041); /* push $r8/%r9 */ + o(0x53415241); /* push $r10/%r11 */ + /* prepare fast x86_64 function call */ gv(RC_RAX); o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size @@ -664,12 +672,15 @@ ST_FUNC void gen_bounded_ptr_add(void) vtop--; /* do a fast function call */ - gen_static_call(TOK___bound_ptr_add); + gen_bounds_call(TOK___bound_ptr_add); /* returned pointer is in rax */ vtop++; vtop->r = TREG_RAX | VT_BOUNDED; + o(0x5a415b41); /* pop $r11/%r10 */ + o(0x58415941); /* pop $r9/%r8 */ + o(0x5f5e5a59); /* pop $rcx/$rdx/$rsi/%rdi */ /* relocation offset of the bounding function call point */ vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); @@ -1435,6 +1446,7 @@ void gfunc_prolog(CType *func_type) X86_64_Mode mode; int i, addr, align, size, reg_count; int param_addr = 0, reg_param_index, sse_param_index; + int n_arg = 0; Sym *sym; CType *type; @@ -1518,6 +1530,7 @@ void gfunc_prolog(CType *func_type) } /* define parameters */ while ((sym = sym->next) != NULL) { + n_arg++; type = &sym->type; mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); switch (mode) { @@ -1574,9 +1587,15 @@ void gfunc_prolog(CType *func_type) if (tcc_state->do_bounds_check) { func_bound_offset = lbounds_section->data_offset; func_bound_ind = ind; - oad(0xb8, 0); /* lbound section pointer */ + o(0xb848); /* lbound section pointer */ + gen_le64 (0); o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */ oad(0xb8, 0); /* call to function */ +extern const char *funcname; + if (n_arg >= 2 && strcmp (funcname, "main") == 0) { + o(0xf07d8b48); /* mov -0x10(%rbp),%rdi */ + gen_bounds_call(TOK___bound_main_arg); + } } #endif } @@ -1603,17 +1622,18 @@ void gfunc_epilog(void) func_bound_offset, lbounds_section->data_offset); saved_ind = ind; ind = func_bound_ind; - greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); - ind = ind + 5 + 3; - gen_static_call(TOK___bound_local_new); + greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); + ind = ind + 10 + 3; + gen_bounds_call(TOK___bound_local_new); ind = saved_ind; /* generate bound check local freeing */ o(0x5250); /* save returned value, if any */ - greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0); - oad(0xb8, 0); /* mov xxx, %rax */ + greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0); + o(0xb848); /* mov xxx, %rax */ + gen_le64 (0); o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */ - gen_static_call(TOK___bound_local_delete); + gen_bounds_call(TOK___bound_local_delete); o(0x585a); /* restore returned value, if any */ } #endif @@ -1940,6 +1960,7 @@ void gen_opf(int op) v1.c.i = fc; load(r, &v1); fc = 0; + vtop->r = r = r | VT_LVAL; } if (op == TOK_EQ || op == TOK_NE) { @@ -2007,6 +2028,7 @@ void gen_opf(int op) v1.c.i = fc; load(r, &v1); fc = 0; + vtop->r = r = r | VT_LVAL; } assert(!(vtop[-1].r & VT_LVAL));