diff --git a/Makefile b/Makefile index 9cf6f7e0..7679b688 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,6 @@ endif LIBTCC = libtcc.a LIBTCC1 = libtcc1.a -LIBTCCB1 = libtccb1.a LINK_LIBTCC = LIBS = CFLAGS += -I$(TOP) @@ -87,7 +86,7 @@ ifeq ($(INCLUDED),no) # running top Makefile PROGS = tcc$(EXESUF) -TCCLIBS = $(LIBTCC1) $(LIBTCCB1) $(LIBTCC) $(LIBTCCDEF) +TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF) TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info all: $(PROGS) $(TCCLIBS) $(TCCDOCS) @@ -101,15 +100,11 @@ TCC_X += riscv64 LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince LIBTCC1_X += riscv64 -# cross libtccb1.a targets to build -LIBTCCB1_X = i386 x86_64 i386-win32 x86_64-win32 - PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF)) LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a) -LIBTCCB1_CROSS = $(foreach X,$(LIBTCCB1_X),$X-libtcc1.a) # build cross compilers & libs -cross: $(LIBTCC1_CROSS) $(LIBTCCB1_CROSS) $(PROGS_CROSS) +cross: $(LIBTCC1_CROSS) $(PROGS_CROSS) # build specific cross compiler & lib cross-%: %-tcc$(EXESUF) %-libtcc1.a ; @@ -153,10 +148,10 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx)) ifneq ($(X),) ifeq ($(CONFIG_WIN32),yes) -DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\"" -DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"lib/$(X)libtccb1.a\"" +DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" +DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\"" else -DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\"" +DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\"" endif endif @@ -281,8 +276,6 @@ STRIP_yes = -s LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS)) LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS)) -LIBTCCB1_W = $(filter %-win32-libtccb1.a %-wince-libtccb1.a,$(LIBTCCB1_CROSS)) -LIBTCCB1_U = $(filter-out $(LIBTCCB1_W),$(LIBTCCB1_CROSS)) IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2) IBw = $(call IB,$(wildcard $1),$2) IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2) @@ -292,8 +285,7 @@ IR = mkdir -p $2 && cp -r $1/. $2 # install progs & libs install-unx: $(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)") - $(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)") - $(call IFw,$(LIBTCCB1) $(LIBTCCB1_U),"$(tccdir)") + $(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)") $(call IF,$(TOPSRC)/libtcc.h,"$(includedir)") @@ -318,8 +310,7 @@ uninstall-unx: install-win: $(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)") $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib") - $(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib") - $(call IFw,libtccb1.a $(LIBTCCB1_W),"$(tccdir)/lib") + $(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples") diff --git a/i386-gen.c b/i386-gen.c index a3ac548d..6ff096ad 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -425,6 +425,11 @@ ST_FUNC void gfunc_call(int nb_args) int size, align, r, args_size, i, func_call; Sym *func_sym; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + gbound_args(nb_args); +#endif + args_size = 0; for(i = 0;i < nb_args; i++) { if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { @@ -1051,119 +1056,18 @@ ST_FUNC void ggoto(void) /* bound check support functions */ #ifdef CONFIG_TCC_BCHECK - -ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec) -{ - addr_t *ptr; - int loc_glob; - 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(bound_sec, sizeof(*ptr)); - *ptr = 0; - loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL; - bsym_index = set_elf_sym(sym_sec, 0, 0, - ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0, - bound_sec->sh_num, "__bounds_start"); - /* pull bcheck.o from libtcc1.a */ - sym_index = set_elf_sym(sym_sec, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, "__bound_init"); - if (s1->output_type != TCC_OUTPUT_MEMORY) { - /* add 'call __bound_init()' in .init section */ - Section *init_section = find_section(s1, ".init"); - unsigned char *pinit; -#ifdef TCC_TARGET_PE - pinit = section_ptr_add(init_section, 3); - pinit[0] = 0x55; /* push %rbp */ - pinit[1] = 0x89; /* mov %esp,%ebp */ - pinit[2] = 0xe5; -#endif - pinit = section_ptr_add(init_section, 5); - pinit[0] = 0xe8; - write32le(pinit + 1, -4); - put_elf_reloc(sym_sec, 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, 6); - pinit[0] = 0xb8; /* mov xx,%eax */ - write32le(pinit + 1, 0); - pinit[5] = 0x50; /* push %eax */ - put_elf_reloc(sym_sec, init_section, - init_section->data_offset - 5, R_386_32, bsym_index); - sym_index = set_elf_sym(sym_sec, 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(sym_sec, 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, 3); - pinit[0] = 0x83; /* add $0x4,%esp */ - pinit[1] = 0xc4; - pinit[2] = 0x04; -#ifdef TCC_TARGET_PE - { - int init_index = set_elf_sym(sym_sec, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - init_section->sh_num, "__init_start"); - Sym sym; - init_section->sh_flags |= SHF_EXECINSTR; - pinit = section_ptr_add(init_section, 2); - pinit[0] = 0xc9; /* leave */ - pinit[1] = 0xc3; /* ret */ - sym.c = init_index; - add_init_array (s1, &sym); - } -#endif - } -} - /* generate a bounded pointer addition */ ST_FUNC void gen_bounded_ptr_add(void) { - /* save all temporary registers */ - save_regs(0); - /* prepare fast i386 function call (args in eax and edx) */ - gv2(RC_EAX, RC_EDX); - vtop -= 2; - /* add line, filename */ - { - static addr_t offset; - static char last_filename[1024]; - Sym *sym_data; - - if (strcmp (last_filename, file->filename) != 0) { - void *ptr; - int len = strlen (file->filename) + 1; - - offset = data_section->data_offset; - ptr = section_ptr_add(data_section, len); - memcpy (ptr, file->filename, len); - memcpy (last_filename, file->filename, len); - } - o(0xb9); /* mov $xx,%ecx */ - gen_le32 (0); - sym_data = get_sym_ref(&char_pointer_type, data_section, - offset, data_section->data_offset); - greloca(cur_text_section, sym_data, ind - 4, R_386_32, 0); - o(0x51); /* push %ecx */ - } - o(0xb9); /* mov $xx,%ecx */ - gen_le32 (file->line_num); - /* do a fast function call */ - gen_static_call(TOK___bound_ptr_add); - o(0x04c483); /* add $4,%esp */ + vpush_global_sym(&func_old_type, TOK___bound_ptr_add); + vrott(3); + gfunc_call(2); + vpushi(0); /* returned pointer is in eax */ - vtop++; vtop->r = TREG_EAX | VT_BOUNDED; - /* address of bounding function call point */ + if (nocode_wanted) + return; + /* relocation offset of the bounding function call point */ vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); } @@ -1176,6 +1080,9 @@ ST_FUNC void gen_bounded_ptr_deref(void) Elf32_Rel *rel; Sym *sym; + if (nocode_wanted) + return; + size = 0; /* XXX: put that code in generic part of tcc */ if (!is_float(vtop->type.t)) { @@ -1194,17 +1101,18 @@ ST_FUNC void gen_bounded_ptr_deref(void) 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; + /* may happen with struct member access */ + return; + //tcc_error("unhandled size when dereferencing bounded pointer"); + //func = 0; + //break; } - - /* patch relocation */ - /* XXX: find a better solution ? */ - rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); sym = external_global_sym(func, &func_old_type); if (!sym->c) put_extern_sym(sym, NULL, 0, 0); + /* patch relocation */ + /* XXX: find a better solution ? */ + rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); } #endif diff --git a/i386-link.c b/i386-link.c index e4929b43..23653b29 100644 --- a/i386-link.c +++ b/i386-link.c @@ -235,4 +235,79 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t } } +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void tcc_add_bcheck(TCCState *s1) +{ + addr_t *ptr; + int loc_glob; + 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; + loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL; + bsym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0, + bounds_section->sh_num, "__bounds_start"); + /* pull bcheck.o from libtcc1.a */ + sym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_UNDEF, "__bound_init"); + if (s1->output_type != TCC_OUTPUT_MEMORY) { + /* add 'call __bound_init()' in .init section */ + Section *init_section = find_section(s1, ".init"); + unsigned char *pinit; +#ifdef TCC_TARGET_PE + pinit = section_ptr_add(init_section, 3); + pinit[0] = 0x55; /* push %rbp */ + pinit[1] = 0x89; /* mov %esp,%ebp */ + pinit[2] = 0xe5; +#endif + 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 */ + pinit = section_ptr_add(init_section, 6); + pinit[0] = 0xb8; /* mov xx,%eax */ + write32le(pinit + 1, 0); + pinit[5] = 0x50; /* push %eax */ + put_elf_reloc(symtab_section, init_section, + init_section->data_offset - 5, R_386_32, 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 */ + pinit = section_ptr_add(init_section, 3); + pinit[0] = 0x83; /* add $0x4,%esp */ + pinit[1] = 0xc4; + pinit[2] = 0x04; +#ifdef TCC_TARGET_PE + { + int init_index = set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + init_section->sh_num, "__init_start"); + Sym sym; + init_section->sh_flags |= SHF_EXECINSTR; + pinit = section_ptr_add(init_section, 2); + pinit[0] = 0xc9; /* leave */ + pinit[1] = 0xc3; /* ret */ + sym.c = init_index; + add_init_array (s1, &sym); + } +#endif + } +} +#endif + #endif /* !TARGET_DEFS_ONLY */ diff --git a/lib/Makefile b/lib/Makefile index 2a9d7abe..b8c878bb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,8 +7,6 @@ include $(TOP)/Makefile VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown) X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-) -BIN = $(TOP)/$(X)libtcc1.a -BINB = $(TOP)/$(X)libtccb1.a XTCC ?= $(TOP)/$(X)tcc$(EXESUF) XCC = $(XTCC) @@ -20,8 +18,6 @@ XCFG = $(or $(findstring -win,$T),-unx) # in order to use gcc, tyoe: make -libtcc1-usegcc=yes arm-libtcc1-usegcc ?= no -x86_64-libtcc1-usegcc ?= no -i386-libtcc1-usegcc ?= no ifeq "$($(T)-libtcc1-usegcc)" "yes" XCC = $(CC) @@ -42,8 +38,6 @@ ifdef CONFIG_OSX XFLAGS += -D_ANSI_SOURCE endif -XFLAGS += -g - I386_O = libtcc1.o alloca86.o alloca86-bt.o X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o @@ -51,11 +45,11 @@ ARM64_O = lib-arm64.o RISCV64_O = lib-arm64.o WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o -OBJ-i386 = $(I386_O) $(DSO_O) -OBJ-x86_64 = $(X86_64_O) va_list.o $(DSO_O) +OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O) +OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O) OBJ-x86_64-osx = $(X86_64_O) va_list.o -OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O) -OBJ-x86_64-win32 = $(X86_64_O) chkstk.o (WIN_O) +OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O) +OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O) OBJ-arm64 = $(ARM64_O) $(DSO_O) OBJ-arm = $(ARM_O) $(DSO_O) OBJ-arm-fpa = $(ARM_O) $(DSO_O) @@ -66,27 +60,14 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O) OBJ-arm-wince = $(ARM_O) $(WIN_O) OBJ-riscv64 = $(RISCV64_O) $(DSO_O) -OBJB-i386 = $(BCHECK_O) -OBJB-x86_64 = $(BCHECK_O) -OBJB-x86_64-osx = dummy.o -OBJB-i386-win32 = bcheck.o -OBJB-x86_64-win32 = bcheck.o -OBJB-arm64 = dummy.o -OBJB-arm = dummy.o -OBJB-arm-fpa = dummy.o -OBJB-arm-fpa-ld = dummy.o -OBJB-arm-vfp = dummy.o -OBJB-arm-eabi = dummy.o -OBJB-arm-eabihf = dummy.o -OBJB-arm-wince = dummy.o -OBJB-riscv64 = dummy.o +OBJ-extra = $(filter bcheck.o,$(OBJ-$T)) +OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) -all: $(BIN) $(BINB) +ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra)) -$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T)) - $(XAR) rcs $@ $^ +all: $(ALL) -$(BINB) : $(patsubst %.o,$(X)%.o,$(OBJB-$T)) +$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1) $(XAR) rcs $@ $^ $(X)%.o : %.c @@ -95,8 +76,12 @@ $(X)%.o : %.c $(X)%.o : %.S $(XCC) -c $< -o $@ $(XFLAGS) +$(TOP)/%.o : %.c + $(XCC) -c $< -o $@ $(XFLAGS) + +$(TOP)/bcheck.o : XFLAGS += -g + $(X)crt1w.o : crt1.c $(X)wincrt1w.o : wincrt1.c - clean : - rm -f *.a *.o $(BIN) $(BINB) + rm -f *.a *.o $(ALL) diff --git a/lib/alloca86_64-bt.S b/lib/alloca86_64-bt.S index 15bca090..e1bac5f4 100644 --- a/lib/alloca86_64-bt.S +++ b/lib/alloca86_64-bt.S @@ -5,44 +5,25 @@ __bound_alloca: #ifdef _WIN32 - pop %rdx - mov %rcx,%rax - add $15,%rax - and $-16,%rax - jz p3 - -p1: - cmp $4096,%rax - jbe p2 - test %rax,-4096(%rsp) - sub $4096,%rsp - sub $4096,%rax - jmp p1 -p2: - - sub %rax,%rsp - mov %rsp,%rax - - push %rdx + inc %rcx # add one extra to separate regions + jmp alloca +.globl __bound_alloca_nr +__bound_alloca_nr: + dec %rcx push %rax mov %rcx,%rdx mov %rax,%rcx - sub $20,%rsp - call __bound_new_region - add $20,%rsp + sub $32,%rsp + call __bound_new_region + add $32,%rsp pop %rax - pop %rdx - - add $32,%rax -p3: - push %rdx ret #else pop %rdx mov %rdi,%rax mov %rax,%rsi # size, a second parm to the __bound_new_region - add $15,%rax + add $15 + 1,%rax # add one extra to separate regions and $-16,%rax jz p3 diff --git a/lib/alloca86_64.S b/lib/alloca86_64.S index 8f89fe48..a4aa173c 100644 --- a/lib/alloca86_64.S +++ b/lib/alloca86_64.S @@ -24,12 +24,8 @@ p1: jmp p1 p2: #endif - sub %rax,%rsp mov %rsp,%rax -#ifdef _WIN32 - add $32,%rax -#endif p3: push %rdx ret diff --git a/lib/bcheck.c b/lib/bcheck.c index 9c913784..ab8f4675 100644 --- a/lib/bcheck.c +++ b/lib/bcheck.c @@ -205,6 +205,9 @@ void __bound_checking (int no_check) no_checking = no_check; } +#define no_FASTCALL +//#define no_checking 1 + /* print a bound error message */ static void bound_error(const char *fmt, ...) { @@ -221,8 +224,7 @@ static void bound_alloc_error(void) /* return '(p + offset)' for pointer arithmetic (a pointer can reach the end of a region in this case */ -void * FASTCALL __bound_ptr_add(void *p, size_t offset, - size_t line, const char *filename) +void * no_FASTCALL __bound_ptr_add(void *p, size_t offset) { size_t addr = (size_t)p; @@ -230,8 +232,8 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset, return p + offset; } - dprintf(stderr, "%s %s (%s:%u): %p 0x%x\n", - __FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); + dprintf(stderr, "%s %s : %p 0x%x\n", + __FILE__, __FUNCTION__, p, (unsigned)offset); WAIT_SEM (); INCR_COUNT(bound_ptr_add_count); @@ -250,8 +252,10 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset, if (addr <= tree->size) { addr += offset; if (tree->is_invalid || addr > tree->size) { - fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", - __FILE__, __FUNCTION__, filename, line, p + offset); + #if 0 + fprintf(stderr,"%s %s : %p is outside of the region\n", + __FILE__, __FUNCTION__, p + offset); + #endif if (never_fatal == 0) { POST_SEM (); return INVALID_POINTER; /* return an invalid pointer */ @@ -266,16 +270,15 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset, /* return '(p + offset)' for pointer indirection (the resulting must be strictly inside the region */ #define BOUND_PTR_INDIR(dsize) \ -void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \ - size_t line, const char *filename) \ +void * no_FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \ { \ size_t addr = (size_t)p; \ \ if (no_checking) { \ return p + offset; \ } \ - dprintf(stderr, "%s %s (%s:%u): %p 0x%x start\n", \ - __FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); \ + dprintf(stderr, "%s %s : %p 0x%x start\n", \ + __FILE__, __FUNCTION__, p, (unsigned)offset); \ WAIT_SEM (); \ INCR_COUNT(bound_ptr_indir ## dsize ## _count); \ if (tree) { \ @@ -293,8 +296,8 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \ if (addr <= tree->size) { \ addr += offset + dsize; \ if (tree->is_invalid || addr > tree->size) { \ - fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", \ - __FILE__, __FUNCTION__, filename, line, p + offset); \ + fprintf(stderr,"%s %s : %p is outside of the region\n", \ + __FILE__, __FUNCTION__, p + offset); \ if (never_fatal == 0) { \ POST_SEM (); \ return INVALID_POINTER; /* return an invalid pointer */ \ @@ -907,7 +910,7 @@ static void __bound_check(const void *p, size_t size, const char *function) return; if (size == 0) return; - p = __bound_ptr_add((void *)p, size, 0, function); + p = __bound_ptr_add((void *)p, size); if (p == INVALID_POINTER) bound_error("invalid pointer"); } @@ -959,7 +962,7 @@ int __bound_strlen(const char *s) INCR_COUNT(bound_strlen_count); while (*p++); len = (p - s) - 1; - p = __bound_ptr_indir1((char *)s, len, 0, "strlen"); + p = __bound_ptr_indir1((char *)s, len); if (p == INVALID_POINTER) bound_error("bad pointer in strlen()"); return len; diff --git a/lib/dummy.c b/lib/dummy.c deleted file mode 100644 index c1548940..00000000 --- a/lib/dummy.c +++ /dev/null @@ -1 +0,0 @@ -static char dummy; diff --git a/libtcc.c b/libtcc.c index 0d58a30b..3094d2df 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1545,7 +1545,6 @@ static const TCCOption tcc_options[] = { #endif #ifdef CONFIG_TCC_BCHECK { "b", TCC_OPTION_b, 0 }, - { "ba", TCC_OPTION_ba, 0 }, #endif { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "c", TCC_OPTION_c, 0 }, @@ -1802,9 +1801,6 @@ reparse: s->do_bounds_check = 1; s->do_debug = 1; break; - case TCC_OPTION_ba: - s->do_bounds_check_address = 1; - break; #endif case TCC_OPTION_g: s->do_debug = 1; diff --git a/tcc.c b/tcc.c index ab054bfc..63250c69 100644 --- a/tcc.c +++ b/tcc.c @@ -59,7 +59,6 @@ static const char help[] = " -g generate runtime debug info\n" #ifdef CONFIG_TCC_BCHECK " -b compile with built-in memory and bounds checker (implies -g)\n" - " -ba Enable better address checking with bounds checker\n" #endif #ifdef CONFIG_TCC_BACKTRACE " -bt N show N callers in stack traces\n" diff --git a/tcc.h b/tcc.h index 127a19a9..13579894 100644 --- a/tcc.h +++ b/tcc.h @@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr); #ifndef TCC_LIBTCC1 # define TCC_LIBTCC1 "libtcc1.a" #endif -#ifndef TCC_LIBTCCB1 -# define TCC_LIBTCCB1 "libtccb1.a" -#endif /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ #if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC @@ -720,7 +717,6 @@ struct TCCState { #ifdef CONFIG_TCC_BCHECK /* compile with built-in memory and bounds checker */ unsigned char do_bounds_check; - unsigned char do_bounds_check_address; #endif #ifdef TCC_TARGET_ARM enum float_abi float_abi; /* float ABI of the generated code*/ @@ -1250,7 +1246,7 @@ ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); #endif ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); #ifdef CONFIG_TCC_BCHECK -ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec); +ST_FUNC void tcc_add_bcheck(TCCState *s1); #endif ST_FUNC void tcc_add_pragma_libs(TCCState *s1); PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); @@ -1437,6 +1433,9 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign #if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE ST_FUNC int classify_x86_64_va_arg(CType *ty); #endif +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void gbound_args(int nb_args); +#endif /* ------------ tccelf.c ------------ */ diff --git a/tccelf.c b/tccelf.c index 20fc20c5..f5f55b1c 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1321,7 +1321,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) { s1->filetype = 0; #ifdef CONFIG_TCC_BCHECK - tcc_add_bcheck(s1, bounds_section, symtab_section); + tcc_add_bcheck(s1); #endif tcc_add_pragma_libs(s1); #ifndef TCC_TARGET_PE @@ -1340,7 +1340,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) { tcc_add_library_err(s1, "pthread"); tcc_add_library_err(s1, "dl"); - tcc_add_support(s1, TCC_LIBTCCB1); + tcc_add_support(s1, "bcheck.o"); } #endif tcc_add_support(s1, TCC_LIBTCC1); diff --git a/tccgen.c b/tccgen.c index 32357f55..01473fff 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1230,6 +1230,11 @@ ST_FUNC void save_reg_upstack(int r, int n) type = &int_type; #endif size = type_size(type, &align); +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + l = loc = (loc - size) & -align; + else +#endif l=get_temp_local_var(size,align); sv.type.t = type->t; sv.r = VT_LOCAL | VT_LVAL; @@ -1417,7 +1422,7 @@ static void gbound(void) vtop->r &= ~VT_MUSTBOUND; /* if lvalue, then use checking code before dereferencing */ - if ((vtop->r & VT_LVAL) && !nocode_wanted) { + if (vtop->r & VT_LVAL) { /* if not VT_BOUNDED value, then make one */ if (!(vtop->r & VT_BOUNDED)) { lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); @@ -1434,6 +1439,19 @@ static void gbound(void) gen_bounded_ptr_deref(); } } + +/* we need to call __bound_ptr_add before we start to load function + args into registers */ +ST_FUNC void gbound_args(int nb_args) +{ + int i; + for (i = 1; i <= nb_args; ++i) + if (vtop[1 - i].r & VT_MUSTBOUND) { + vrotb(i); + gbound(); + vrott(i); + } +} #endif static void incr_bf_adr(int o) @@ -2499,25 +2517,7 @@ redo: } gen_op('*'); #ifdef CONFIG_TCC_BCHECK - /* The main reason to removing this code: - #include - int main () - { - int v[10]; - int i = 10; - int j = 9; - fprintf(stderr, "v+i-j = %p\n", v+i-j); - fprintf(stderr, "v+(i-j) = %p\n", v+(i-j)); - } - 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 && tcc_state->do_bounds_check_address - && !const_wanted && !nocode_wanted) { + if (tcc_state->do_bounds_check && !const_wanted) { /* if bounded pointers, we generate a special code to test bounds */ if (op == '-') { @@ -2525,6 +2525,7 @@ redo: vswap(); gen_op('-'); } + vtop[-1].r &= ~VT_MUSTBOUND; gen_bounded_ptr_add(); } else #endif diff --git a/tccpe.c b/tccpe.c index 6c15e048..01318598 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1836,6 +1836,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) #define PE_STDSYM(n,s) "_" n s #endif +static void tcc_add_support(TCCState *s1, const char *filename) +{ + if (tcc_add_dll(s1, filename, 0) < 0) + tcc_error_noabort("%s not found", filename); +} + static void pe_add_runtime(TCCState *s1, struct pe_info *pe) { const char *start_symbol; @@ -1884,35 +1890,21 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe) if (0 == s1->nostdlib) { static const char *libs[] = { - TCC_LIBTCC1, -#ifdef CONFIG_TCC_BCHECK - TCC_LIBTCCB1, -#endif "msvcrt", "kernel32", "", "user32", "gdi32", NULL }; const char **pp, *p; +#ifdef TCC_IS_NATIVE + if (s1->do_bounds_check) + tcc_add_support(s1, "bcheck.o"); +#endif + tcc_add_support(s1, TCC_LIBTCC1); for (pp = libs; 0 != (p = *pp); ++pp) { -#ifdef CONFIG_TCC_BCHECK - if (pp == libs + 1 && - (s1->do_bounds_check == 0 || s1->output_type == TCC_OUTPUT_DLL)) { - continue; - } -#endif - if (0 == *p) { - if (PE_DLL != pe_type && PE_GUI != pe_type) - break; - } else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) { - continue; -#ifdef CONFIG_TCC_BCHECK - } else if (pp == libs + 1 && tcc_add_dll(s1, p, 0) >= 0) { - continue; -#endif - } else { + if (*p) tcc_add_library_err(s1, p); - } + else if (PE_DLL != pe_type && PE_GUI != pe_type) + break; } } - if (TCC_OUTPUT_MEMORY == s1->output_type) pe_type = PE_RUN; pe->type = pe_type; diff --git a/tccpp.c b/tccpp.c index 8245a8fd..5f66cce1 100644 --- a/tccpp.c +++ b/tccpp.c @@ -392,16 +392,15 @@ 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); - va_copy (vc, v); - len = vsnprintf(NULL, 0, fmt, vc); - va_end(vc); + len = vsnprintf(NULL, 0, fmt, v); + va_end(v); 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/tcctok.h b/tcctok.h index 6de1c6e9..5adafb9c 100644 --- a/tcctok.h +++ b/tcctok.h @@ -306,6 +306,9 @@ DEF(TOK___bound_local_new, "__bound_local_new") DEF(TOK___bound_local_delete, "__bound_local_delete") # ifdef TCC_TARGET_PE +# ifdef TCC_TARGET_X86_64 + DEF(TOK___bound_alloca_nr, "__bound_alloca_nr") +# endif DEF(TOK_malloc, "malloc") DEF(TOK_free, "free") DEF(TOK_realloc, "realloc") diff --git a/tests/Makefile b/tests/Makefile index e8507f58..ce434b10 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -23,7 +23,7 @@ TESTS = \ tests2-dir \ pp-dir -BTESTS = test1b test3b btest test4 +BTESTS = btest test2b # test4_static -- Not all relocation types are implemented yet. # asmtest / asmtest2 -- minor differences with gcc @@ -115,7 +115,7 @@ test3 test3b: tcctest.c test.ref $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3 @diff -u test.ref test.out3 && echo "Auto Test3 OK" -test%b : TCCFLAGS += -b -ba +test%b : TCCFLAGS += -b # binary output test test4: tcctest.c test.ref @@ -130,7 +130,7 @@ test4: tcctest.c test.ref ./tcctest1 > test1.out @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi # dynamic output + bound check - $(TCC) -b -ba -o tcctest4 $< + $(TCC) -b -o tcctest4 $< ./tcctest4 > test4.out @if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi @@ -163,15 +163,14 @@ memtest: # memory and bound check auto test -BOUNDS_OK = 1 3 4 8 10 14 16 +BOUNDS_OK = 1 4 8 10 14 16 BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17 btest: boundtest.c @echo ------------ $@ ------------ - @ulimit -c 0; \ - for i in $(BOUNDS_OK); do \ + @for i in $(BOUNDS_OK); do \ echo ; echo --- boundtest $$i ---; \ - if $(TCC) -b -ba -run $< $$i ; then \ + if $(TCC) -b -run $< $$i ; then \ echo succeeded as expected; \ else\ echo Failed positive test $$i ; exit 1 ; \ @@ -179,7 +178,7 @@ btest: boundtest.c done ;\ for i in $(BOUNDS_FAIL); do \ echo ; echo --- boundtest $$i ---; \ - if $(TCC) -b -ba -run $< $$i ; then \ + if $(TCC) -b -run $< $$i ; then \ echo Failed negative test $$i ; exit 1 ;\ else\ echo failed as expected; \ diff --git a/x86_64-gen.c b/x86_64-gen.c index c1cce786..bdbd137d 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -142,9 +142,6 @@ ST_DATA const int reg_classes[NB_REGS] = { static unsigned long func_sub_sp_offset; static int func_ret_sub; -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) @@ -654,218 +651,19 @@ static void gen_bounds_call(int v) #endif } -ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec) -{ - addr_t *ptr; - int loc_glob; - 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(bound_sec, sizeof(*ptr)); - *ptr = 0; - loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL; - bsym_index = set_elf_sym(sym_sec, 0, 0, - ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0, - bound_sec->sh_num, "__bounds_start"); - /* pull bcheck.o from libtcc1.a */ - sym_index = set_elf_sym(sym_sec, 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - SHN_UNDEF, "__bound_init"); - if (s1->output_type != TCC_OUTPUT_MEMORY) { - /* add 'call __bound_init()' in .init section */ - Section *init_section = find_section(s1, ".init"); - unsigned char *pinit; -#ifdef TCC_TARGET_PE - pinit = section_ptr_add(init_section, 8); - pinit[0] = 0x55; /* push %rbp */ - pinit[1] = 0x48; /* mov %rsp,%rpb */ - pinit[2] = 0x89; - pinit[3] = 0xe5; - pinit[4] = 0x48; /* sub $0x10,%rsp */ - pinit[5] = 0x83; - pinit[6] = 0xec; - pinit[7] = 0x10; -#endif - pinit = section_ptr_add(init_section, 5); - pinit[0] = 0xe8; - write32le(pinit + 1, -4); - put_elf_reloc(sym_sec, 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); -#ifdef TCC_TARGET_PE - pinit[10] = 0x48; /* mov %rax,%rcx */ - pinit[11] = 0x89; - pinit[12] = 0xc1; -#else - pinit[10] = 0x48; /* mov %rax,%rdi */ - pinit[11] = 0x89; - pinit[12] = 0xc7; -#endif - put_elf_reloc(sym_sec, init_section, - init_section->data_offset - 11, R_X86_64_64, bsym_index); - sym_index = set_elf_sym(sym_sec, 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(sym_sec, init_section, - init_section->data_offset - 4, R_386_PC32, sym_index); - /* R_386_PC32 = R_X86_64_PC32 = 2 */ -#ifdef TCC_TARGET_PE - { - int init_index = set_elf_sym(sym_sec, - 0, 0, - ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, - init_section->sh_num, "__init_start"); - Sym sym; - init_section->sh_flags |= SHF_EXECINSTR; - pinit = section_ptr_add(init_section, 2); - pinit[0] = 0xc9; /* leave */ - pinit[1] = 0xc3; /* ret */ - sym.c = init_index; - add_init_array (s1, &sym); - } -#endif - } -} - /* generate a bounded pointer addition */ ST_FUNC void gen_bounded_ptr_add(void) { - int i; - - nested_call++; - - /* save all temporary registers */ - save_regs(0); - - 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 %rdx/%rcx */ - o(0x51415041); /* push %r8/%r9 */ -#else - o(0x51525657); /* push %rdi/%rsi/%rdx/%rcx */ -#endif - } - /* prepare fast x86_64 function call */ - gv(RC_RAX); -#ifdef TCC_TARGET_PE - o(0xc28948); // mov %rax,%rdx ## second arg in %rdx, this must be size -#else - o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size -#endif - vtop--; - - gv(RC_RAX); -#ifdef TCC_TARGET_PE - o(0xc18948); // mov %rax,%rcx ## first arg in %rcx, this must be ptr -#else - o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr -#endif - vtop--; - - /* add line, filename */ -#ifdef TCC_TARGET_PE - o(0xc0c749); /* mov $xx,%r8 */ -#else - o(0xba); /* mov $xx,%edx */ -#endif - gen_le32 (file->line_num); - { - static addr_t offset; - static char last_filename[1024]; - Sym *sym_data; - - if (strcmp (last_filename, file->filename) != 0) { - void *ptr; - int len = strlen (file->filename) + 1; - - offset = data_section->data_offset; - ptr = section_ptr_add(data_section, len); - memcpy (ptr, file->filename, len); - memcpy (last_filename, file->filename, len); - } -#ifdef TCC_TARGET_PE - o(0xb949); /* mov $xx,%r9 */ -#else - o(0xb948); /* mov $xx,%rcx */ -#endif - gen_le64 (0); - sym_data = get_sym_ref(&char_pointer_type, data_section, - offset, data_section->data_offset); - greloca(cur_text_section, sym_data, ind - 8, R_X86_64_64, 0); - } - -#ifdef TCC_TARGET_PE - o(0x20ec8348); /* sub $20, %rsp */ -#endif - - /* do a fast function call */ - gen_bounds_call(TOK___bound_ptr_add); - -#ifdef TCC_TARGET_PE - o(0x20c48348); /* add $20, %rsp */ -#endif - - if (nested_call > 1) { -#ifdef TCC_TARGET_PE - o(0x58415941); /* pop %r9/%r8 */ - o(0x5a59); /* pop %rcx/%rdx */ -#else - o(0x5f5e5a59); /* pop $rcx/%rdx/%rsi/%rdi */ -#endif - } + vpush_global_sym(&func_old_type, TOK___bound_ptr_add); + vrott(3); + gfunc_call(2); + vpushi(0); /* returned pointer is in rax */ - vtop++; vtop->r = TREG_RAX | VT_BOUNDED; - - 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; - } - } - + if (nocode_wanted) + return; /* 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 @@ -877,6 +675,9 @@ ST_FUNC void gen_bounded_ptr_deref(void) ElfW(Rela) *rel; Sym *sym; + if (nocode_wanted) + return; + size = 0; /* XXX: put that code in generic part of tcc */ if (!is_float(vtop->type.t)) { @@ -886,7 +687,7 @@ ST_FUNC void gen_bounded_ptr_deref(void) size = 2; } if (!size) - size = type_size(&vtop->type, &align); + size = type_size(&vtop->type, &align); switch(size) { case 1: func = TOK___bound_ptr_indir1; break; case 2: func = TOK___bound_ptr_indir2; break; @@ -895,18 +696,17 @@ ST_FUNC void gen_bounded_ptr_deref(void) 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; + /* may happen with struct member access */ + return; + //tcc_error("unhandled size when dereferencing bounded pointer"); + //func = 0; + //break; } - sym = external_global_sym(func, &func_old_type); 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)); } @@ -992,6 +792,11 @@ void gfunc_call(int nb_args) int size, r, args_size, i, d, bt, struct_size; int arg; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + gbound_args(nb_args); +#endif + args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE; arg = nb_args; @@ -1051,7 +856,6 @@ 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 { @@ -1070,7 +874,6 @@ 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) { @@ -1086,7 +889,6 @@ 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; } } } @@ -1105,7 +907,12 @@ void gfunc_call(int nb_args) if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) { /* need to add the "func_scratch" area after alloca */ - o(0x48); func_alloca = oad(0x2d, func_alloca); /* sub $NN, %rax */ + o(0x48); func_alloca = oad(0x05, func_alloca); /* add $NN, %rax */ +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + gen_bounds_call(TOK___bound_alloca_nr); /* new region */ +#endif + } /* other compilers don't clear the upper bits when returning char/short */ @@ -1125,7 +932,6 @@ void gfunc_call(int nb_args) o(0xc089); /* mov %eax,%eax */ #endif vtop--; - call_used_nr_reg = 0; } @@ -1141,7 +947,7 @@ void gfunc_prolog(Sym *func_sym) int n_arg = 0; func_ret_sub = 0; - func_scratch = 0; + func_scratch = 32; func_alloca = 0; loc = 0; @@ -1228,6 +1034,10 @@ void gfunc_epilog(void) { int v, saved_ind; + /* align local size to word & save local variables */ + func_scratch = (func_scratch + 15) & -16; + loc = (loc & -16) - func_scratch; + #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check && func_bound_offset != lbounds_section->data_offset) @@ -1273,9 +1083,7 @@ void gfunc_epilog(void) saved_ind = ind; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; - /* align local size to word & save local variables */ - func_scratch = (func_scratch + 15) & -16; - v = (func_scratch + -loc + 15) & -16; + v = -loc; if (v >= 4096) { Sym *sym = external_global_sym(TOK___chkstk, &func_old_type); @@ -1479,6 +1287,11 @@ void gfunc_call(int nb_args) int sse_reg, gen_reg; char _onstack[nb_args ? nb_args : 1], *onstack = _onstack; +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check) + gbound_args(nb_args); +#endif + /* 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 @@ -1611,14 +1424,11 @@ 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 */ @@ -1629,12 +1439,10 @@ 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--; @@ -1677,7 +1485,6 @@ void gfunc_call(int nb_args) else if (bt == (VT_SHORT | VT_UNSIGNED)) o(0xc0b70f); /* movzwl %al, %eax */ vtop--; - call_used_nr_reg = 0; } diff --git a/x86_64-link.c b/x86_64-link.c index dcb2b90c..0730c2db 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -287,4 +287,89 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t } } +#ifdef CONFIG_TCC_BCHECK +ST_FUNC void tcc_add_bcheck(TCCState *s1) +{ + addr_t *ptr; + int loc_glob; + 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; + loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL; + bsym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0, + bounds_section->sh_num, "__bounds_start"); + /* pull bcheck.o from libtcc1.a */ + sym_index = set_elf_sym(symtab_section, 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + SHN_UNDEF, "__bound_init"); + if (s1->output_type != TCC_OUTPUT_MEMORY) { + /* add 'call __bound_init()' in .init section */ + Section *init_section = find_section(s1, ".init"); + unsigned char *pinit; +#ifdef TCC_TARGET_PE + pinit = section_ptr_add(init_section, 8); + pinit[0] = 0x55; /* push %rbp */ + pinit[1] = 0x48; /* mov %rsp,%rpb */ + pinit[2] = 0x89; + pinit[3] = 0xe5; + pinit[4] = 0x48; /* sub $0x10,%rsp */ + pinit[5] = 0x83; + pinit[6] = 0xec; + pinit[7] = 0x10; +#endif + 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 */ + pinit = section_ptr_add(init_section, 13); + pinit[0] = 0x48; /* mov xx,%rax */ + pinit[1] = 0xb8; + write64le(pinit + 2, 0); +#ifdef TCC_TARGET_PE + pinit[10] = 0x48; /* mov %rax,%rcx */ + pinit[11] = 0x89; + pinit[12] = 0xc1; +#else + pinit[10] = 0x48; /* mov %rax,%rdi */ + pinit[11] = 0x89; + pinit[12] = 0xc7; +#endif + 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 */ +#ifdef TCC_TARGET_PE + { + int init_index = set_elf_sym(symtab_section, + 0, 0, + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, + init_section->sh_num, "__init_start"); + Sym sym; + init_section->sh_flags |= SHF_EXECINSTR; + pinit = section_ptr_add(init_section, 2); + pinit[0] = 0xc9; /* leave */ + pinit[1] = 0xc3; /* ret */ + sym.c = init_index; + add_init_array (s1, &sym); + } +#endif + } +} +#endif + #endif /* !TARGET_DEFS_ONLY */