From 56db092ab7df109508efa4e3d2034028b18fd101 Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 12 Dec 2019 15:45:45 +0100 Subject: [PATCH] bcheck cleanup - revert Makefiles to state before last bcheck additions Instead, just load bcheck.o explicitly if that is what is wanted. - move tcc_add_bcheck() to the -link.c files and remove revently added arguments. This function is to support tccelf.c with linking, not for tccgen.c to support compilation. - remove -ba option: It said: "-ba Enable better address checking with bounds checker" Okay, if it is better then to have it is not an option. - remove va_copy. It is C99 and we try to stay C89 in tinycc when possible. For example, MS compilers do not have va_copy. - win64: revert any 'fixes' to alloca It was correct as it was before, except for bound_checking where it was not implemented. This should now work too. - remove parasitic filename:linenum features Such feature is already present with rt_printline in tccrun.c. If it doesn't work it can be fixed. - revert changes to gen_bounded_ptr_add() gen_bounded_ptr_add() was working as it should before (mostly). For the sake of simplicity I switched it to CDECL. Anyway, FASTCALL means SLOWCALL with tinycc. In exchange you get one addition which is required for bounds_cnecking function arguments. The important thing is to check them *BEFORE* they are loaded into registers. New function gbound_args() does that. In any case, code instrumentation with the bounds-check functions as such now seems to work flawlessly again, which means when they are inserted as NOPs, any code that tcc can compile, seems to behave just the same as without them. What these functions then do when fully enabled, is a differnt story. I did not touch this. --- Makefile | 23 ++-- i386-gen.c | 138 ++++------------------ i386-link.c | 75 ++++++++++++ lib/Makefile | 45 +++----- lib/alloca86_64-bt.S | 37 ++---- lib/alloca86_64.S | 4 - lib/bcheck.c | 31 ++--- lib/dummy.c | 1 - libtcc.c | 4 - tcc.c | 1 - tcc.h | 9 +- tccelf.c | 4 +- tccgen.c | 41 +++---- tccpe.c | 36 +++--- tccpp.c | 7 +- tcctok.h | 3 + tests/Makefile | 15 ++- x86_64-gen.c | 267 ++++++------------------------------------- x86_64-link.c | 85 ++++++++++++++ 19 files changed, 322 insertions(+), 504 deletions(-) delete mode 100644 lib/dummy.c 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 */