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 <target>-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.
mob
grischka 2019-12-12 15:45:45 +01:00
parent a86f47889c
commit 56db092ab7
19 changed files with 322 additions and 504 deletions

View File

@ -16,7 +16,6 @@ endif
LIBTCC = libtcc.a LIBTCC = libtcc.a
LIBTCC1 = libtcc1.a LIBTCC1 = libtcc1.a
LIBTCCB1 = libtccb1.a
LINK_LIBTCC = LINK_LIBTCC =
LIBS = LIBS =
CFLAGS += -I$(TOP) CFLAGS += -I$(TOP)
@ -87,7 +86,7 @@ ifeq ($(INCLUDED),no)
# running top Makefile # running top Makefile
PROGS = tcc$(EXESUF) PROGS = tcc$(EXESUF)
TCCLIBS = $(LIBTCC1) $(LIBTCCB1) $(LIBTCC) $(LIBTCCDEF) TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS) 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 = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
LIBTCC1_X += riscv64 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)) PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a) LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
LIBTCCB1_CROSS = $(foreach X,$(LIBTCCB1_X),$X-libtcc1.a)
# build cross compilers & libs # build cross compilers & libs
cross: $(LIBTCC1_CROSS) $(LIBTCCB1_CROSS) $(PROGS_CROSS) cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib # build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) %-libtcc1.a ; cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
@ -153,10 +148,10 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx))
ifneq ($(X),) ifneq ($(X),)
ifeq ($(CONFIG_WIN32),yes) ifeq ($(CONFIG_WIN32),yes)
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\"" DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"lib/$(X)libtccb1.a\"" DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
else 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\"" DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif endif
endif endif
@ -281,8 +276,6 @@ STRIP_yes = -s
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS)) LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(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) IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
IBw = $(call IB,$(wildcard $1),$2) IBw = $(call IB,$(wildcard $1),$2)
IF = $(if $1,mkdir -p $2 && $(INSTALL) $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 progs & libs
install-unx: install-unx:
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)") $(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)") $(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)")
$(call IFw,$(LIBTCCB1) $(LIBTCCB1_U),"$(tccdir)")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)") $(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)") $(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
@ -318,8 +310,7 @@ uninstall-unx:
install-win: install-win:
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)") $(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib") $(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
$(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib") $(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib")
$(call IFw,libtccb1.a $(LIBTCCB1_W),"$(tccdir)/lib")
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include") $(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include") $(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples") $(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")

View File

@ -425,6 +425,11 @@ ST_FUNC void gfunc_call(int nb_args)
int size, align, r, args_size, i, func_call; int size, align, r, args_size, i, func_call;
Sym *func_sym; Sym *func_sym;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gbound_args(nb_args);
#endif
args_size = 0; args_size = 0;
for(i = 0;i < nb_args; i++) { for(i = 0;i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
@ -1051,119 +1056,18 @@ ST_FUNC void ggoto(void)
/* bound check support functions */ /* bound check support functions */
#ifdef CONFIG_TCC_BCHECK #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 */ /* generate a bounded pointer addition */
ST_FUNC void gen_bounded_ptr_add(void) ST_FUNC void gen_bounded_ptr_add(void)
{ {
/* save all temporary registers */ vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
save_regs(0); vrott(3);
/* prepare fast i386 function call (args in eax and edx) */ gfunc_call(2);
gv2(RC_EAX, RC_EDX); vpushi(0);
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 */
/* returned pointer is in eax */ /* returned pointer is in eax */
vtop++;
vtop->r = TREG_EAX | VT_BOUNDED; 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)); 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; Elf32_Rel *rel;
Sym *sym; Sym *sym;
if (nocode_wanted)
return;
size = 0; size = 0;
/* XXX: put that code in generic part of tcc */ /* XXX: put that code in generic part of tcc */
if (!is_float(vtop->type.t)) { 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 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break; case 16: func = TOK___bound_ptr_indir16; break;
default: default:
tcc_error("unhandled size when dereferencing bounded pointer"); /* may happen with struct member access */
func = 0; return;
break; //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); sym = external_global_sym(func, &func_old_type);
if (!sym->c) if (!sym->c)
put_extern_sym(sym, NULL, 0, 0); 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)); rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
} }
#endif #endif

View File

@ -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 */ #endif /* !TARGET_DEFS_ONLY */

View File

@ -7,8 +7,6 @@ include $(TOP)/Makefile
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown) T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-) X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
BIN = $(TOP)/$(X)libtcc1.a
BINB = $(TOP)/$(X)libtccb1.a
XTCC ?= $(TOP)/$(X)tcc$(EXESUF) XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
XCC = $(XTCC) XCC = $(XTCC)
@ -20,8 +18,6 @@ XCFG = $(or $(findstring -win,$T),-unx)
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes # in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
arm-libtcc1-usegcc ?= no arm-libtcc1-usegcc ?= no
x86_64-libtcc1-usegcc ?= no
i386-libtcc1-usegcc ?= no
ifeq "$($(T)-libtcc1-usegcc)" "yes" ifeq "$($(T)-libtcc1-usegcc)" "yes"
XCC = $(CC) XCC = $(CC)
@ -42,8 +38,6 @@ ifdef CONFIG_OSX
XFLAGS += -D_ANSI_SOURCE XFLAGS += -D_ANSI_SOURCE
endif endif
XFLAGS += -g
I386_O = libtcc1.o alloca86.o alloca86-bt.o I386_O = libtcc1.o alloca86.o alloca86-bt.o
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-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 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 RISCV64_O = lib-arm64.o
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
OBJ-i386 = $(I386_O) $(DSO_O) OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
OBJ-x86_64 = $(X86_64_O) va_list.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-x86_64-osx = $(X86_64_O) va_list.o
OBJ-i386-win32 = $(I386_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 (WIN_O) OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
OBJ-arm64 = $(ARM64_O) $(DSO_O) OBJ-arm64 = $(ARM64_O) $(DSO_O)
OBJ-arm = $(ARM_O) $(DSO_O) OBJ-arm = $(ARM_O) $(DSO_O)
OBJ-arm-fpa = $(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-arm-wince = $(ARM_O) $(WIN_O)
OBJ-riscv64 = $(RISCV64_O) $(DSO_O) OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
OBJB-i386 = $(BCHECK_O) OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
OBJB-x86_64 = $(BCHECK_O) OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
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
all: $(BIN) $(BINB) ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T)) all: $(ALL)
$(XAR) rcs $@ $^
$(BINB) : $(patsubst %.o,$(X)%.o,$(OBJB-$T)) $(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
$(XAR) rcs $@ $^ $(XAR) rcs $@ $^
$(X)%.o : %.c $(X)%.o : %.c
@ -95,8 +76,12 @@ $(X)%.o : %.c
$(X)%.o : %.S $(X)%.o : %.S
$(XCC) -c $< -o $@ $(XFLAGS) $(XCC) -c $< -o $@ $(XFLAGS)
$(TOP)/%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
$(TOP)/bcheck.o : XFLAGS += -g
$(X)crt1w.o : crt1.c $(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c $(X)wincrt1w.o : wincrt1.c
clean : clean :
rm -f *.a *.o $(BIN) $(BINB) rm -f *.a *.o $(ALL)

View File

@ -5,44 +5,25 @@
__bound_alloca: __bound_alloca:
#ifdef _WIN32 #ifdef _WIN32
pop %rdx inc %rcx # add one extra to separate regions
mov %rcx,%rax jmp alloca
add $15,%rax .globl __bound_alloca_nr
and $-16,%rax __bound_alloca_nr:
jz p3 dec %rcx
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
push %rax push %rax
mov %rcx,%rdx mov %rcx,%rdx
mov %rax,%rcx mov %rax,%rcx
sub $20,%rsp sub $32,%rsp
call __bound_new_region call __bound_new_region
add $20,%rsp add $32,%rsp
pop %rax pop %rax
pop %rdx
add $32,%rax
p3:
push %rdx
ret ret
#else #else
pop %rdx pop %rdx
mov %rdi,%rax mov %rdi,%rax
mov %rax,%rsi # size, a second parm to the __bound_new_region 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 and $-16,%rax
jz p3 jz p3

View File

@ -24,12 +24,8 @@ p1:
jmp p1 jmp p1
p2: p2:
#endif #endif
sub %rax,%rsp sub %rax,%rsp
mov %rsp,%rax mov %rsp,%rax
#ifdef _WIN32
add $32,%rax
#endif
p3: p3:
push %rdx push %rdx
ret ret

View File

@ -205,6 +205,9 @@ void __bound_checking (int no_check)
no_checking = no_check; no_checking = no_check;
} }
#define no_FASTCALL
//#define no_checking 1
/* print a bound error message */ /* print a bound error message */
static void bound_error(const char *fmt, ...) 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 /* return '(p + offset)' for pointer arithmetic (a pointer can reach
the end of a region in this case */ the end of a region in this case */
void * FASTCALL __bound_ptr_add(void *p, size_t offset, void * no_FASTCALL __bound_ptr_add(void *p, size_t offset)
size_t line, const char *filename)
{ {
size_t addr = (size_t)p; size_t addr = (size_t)p;
@ -230,8 +232,8 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset,
return p + offset; return p + offset;
} }
dprintf(stderr, "%s %s (%s:%u): %p 0x%x\n", dprintf(stderr, "%s %s : %p 0x%x\n",
__FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); __FILE__, __FUNCTION__, p, (unsigned)offset);
WAIT_SEM (); WAIT_SEM ();
INCR_COUNT(bound_ptr_add_count); INCR_COUNT(bound_ptr_add_count);
@ -250,8 +252,10 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset,
if (addr <= tree->size) { if (addr <= tree->size) {
addr += offset; addr += offset;
if (tree->is_invalid || addr > tree->size) { if (tree->is_invalid || addr > tree->size) {
fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", #if 0
__FILE__, __FUNCTION__, filename, line, p + offset); fprintf(stderr,"%s %s : %p is outside of the region\n",
__FILE__, __FUNCTION__, p + offset);
#endif
if (never_fatal == 0) { if (never_fatal == 0) {
POST_SEM (); POST_SEM ();
return INVALID_POINTER; /* return an invalid pointer */ 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 /* return '(p + offset)' for pointer indirection (the resulting must
be strictly inside the region */ be strictly inside the region */
#define BOUND_PTR_INDIR(dsize) \ #define BOUND_PTR_INDIR(dsize) \
void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \ void * no_FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
size_t line, const char *filename) \
{ \ { \
size_t addr = (size_t)p; \ size_t addr = (size_t)p; \
\ \
if (no_checking) { \ if (no_checking) { \
return p + offset; \ return p + offset; \
} \ } \
dprintf(stderr, "%s %s (%s:%u): %p 0x%x start\n", \ dprintf(stderr, "%s %s : %p 0x%x start\n", \
__FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); \ __FILE__, __FUNCTION__, p, (unsigned)offset); \
WAIT_SEM (); \ WAIT_SEM (); \
INCR_COUNT(bound_ptr_indir ## dsize ## _count); \ INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
if (tree) { \ if (tree) { \
@ -293,8 +296,8 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \
if (addr <= tree->size) { \ if (addr <= tree->size) { \
addr += offset + dsize; \ addr += offset + dsize; \
if (tree->is_invalid || addr > tree->size) { \ if (tree->is_invalid || addr > tree->size) { \
fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", \ fprintf(stderr,"%s %s : %p is outside of the region\n", \
__FILE__, __FUNCTION__, filename, line, p + offset); \ __FILE__, __FUNCTION__, p + offset); \
if (never_fatal == 0) { \ if (never_fatal == 0) { \
POST_SEM (); \ POST_SEM (); \
return INVALID_POINTER; /* return an invalid pointer */ \ 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; return;
if (size == 0) if (size == 0)
return; return;
p = __bound_ptr_add((void *)p, size, 0, function); p = __bound_ptr_add((void *)p, size);
if (p == INVALID_POINTER) if (p == INVALID_POINTER)
bound_error("invalid pointer"); bound_error("invalid pointer");
} }
@ -959,7 +962,7 @@ int __bound_strlen(const char *s)
INCR_COUNT(bound_strlen_count); INCR_COUNT(bound_strlen_count);
while (*p++); while (*p++);
len = (p - s) - 1; len = (p - s) - 1;
p = __bound_ptr_indir1((char *)s, len, 0, "strlen"); p = __bound_ptr_indir1((char *)s, len);
if (p == INVALID_POINTER) if (p == INVALID_POINTER)
bound_error("bad pointer in strlen()"); bound_error("bad pointer in strlen()");
return len; return len;

View File

@ -1 +0,0 @@
static char dummy;

View File

@ -1545,7 +1545,6 @@ static const TCCOption tcc_options[] = {
#endif #endif
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
{ "b", TCC_OPTION_b, 0 }, { "b", TCC_OPTION_b, 0 },
{ "ba", TCC_OPTION_ba, 0 },
#endif #endif
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
{ "c", TCC_OPTION_c, 0 }, { "c", TCC_OPTION_c, 0 },
@ -1802,9 +1801,6 @@ reparse:
s->do_bounds_check = 1; s->do_bounds_check = 1;
s->do_debug = 1; s->do_debug = 1;
break; break;
case TCC_OPTION_ba:
s->do_bounds_check_address = 1;
break;
#endif #endif
case TCC_OPTION_g: case TCC_OPTION_g:
s->do_debug = 1; s->do_debug = 1;

1
tcc.c
View File

@ -59,7 +59,6 @@ static const char help[] =
" -g generate runtime debug info\n" " -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
" -b compile with built-in memory and bounds checker (implies -g)\n" " -b compile with built-in memory and bounds checker (implies -g)\n"
" -ba Enable better address checking with bounds checker\n"
#endif #endif
#ifdef CONFIG_TCC_BACKTRACE #ifdef CONFIG_TCC_BACKTRACE
" -bt N show N callers in stack traces\n" " -bt N show N callers in stack traces\n"

9
tcc.h
View File

@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifndef TCC_LIBTCC1 #ifndef TCC_LIBTCC1
# define TCC_LIBTCC1 "libtcc1.a" # define TCC_LIBTCC1 "libtcc1.a"
#endif #endif
#ifndef TCC_LIBTCCB1
# define TCC_LIBTCCB1 "libtccb1.a"
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */ /* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC #if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
@ -720,7 +717,6 @@ struct TCCState {
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* compile with built-in memory and bounds checker */ /* compile with built-in memory and bounds checker */
unsigned char do_bounds_check; unsigned char do_bounds_check;
unsigned char do_bounds_check_address;
#endif #endif
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
enum float_abi float_abi; /* float ABI of the generated code*/ 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 #endif
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags); ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
#ifdef CONFIG_TCC_BCHECK #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 #endif
ST_FUNC void tcc_add_pragma_libs(TCCState *s1); ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f); 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 #if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
ST_FUNC int classify_x86_64_va_arg(CType *ty); ST_FUNC int classify_x86_64_va_arg(CType *ty);
#endif #endif
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void gbound_args(int nb_args);
#endif
/* ------------ tccelf.c ------------ */ /* ------------ tccelf.c ------------ */

View File

@ -1321,7 +1321,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
{ {
s1->filetype = 0; s1->filetype = 0;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1, bounds_section, symtab_section); tcc_add_bcheck(s1);
#endif #endif
tcc_add_pragma_libs(s1); tcc_add_pragma_libs(s1);
#ifndef TCC_TARGET_PE #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) { if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
tcc_add_library_err(s1, "pthread"); tcc_add_library_err(s1, "pthread");
tcc_add_library_err(s1, "dl"); tcc_add_library_err(s1, "dl");
tcc_add_support(s1, TCC_LIBTCCB1); tcc_add_support(s1, "bcheck.o");
} }
#endif #endif
tcc_add_support(s1, TCC_LIBTCC1); tcc_add_support(s1, TCC_LIBTCC1);

View File

@ -1230,6 +1230,11 @@ ST_FUNC void save_reg_upstack(int r, int n)
type = &int_type; type = &int_type;
#endif #endif
size = type_size(type, &align); 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); l=get_temp_local_var(size,align);
sv.type.t = type->t; sv.type.t = type->t;
sv.r = VT_LOCAL | VT_LVAL; sv.r = VT_LOCAL | VT_LVAL;
@ -1417,7 +1422,7 @@ static void gbound(void)
vtop->r &= ~VT_MUSTBOUND; vtop->r &= ~VT_MUSTBOUND;
/* if lvalue, then use checking code before dereferencing */ /* 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 not VT_BOUNDED value, then make one */
if (!(vtop->r & VT_BOUNDED)) { if (!(vtop->r & VT_BOUNDED)) {
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
@ -1434,6 +1439,19 @@ static void gbound(void)
gen_bounded_ptr_deref(); 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 #endif
static void incr_bf_adr(int o) static void incr_bf_adr(int o)
@ -2499,25 +2517,7 @@ redo:
} }
gen_op('*'); gen_op('*');
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* The main reason to removing this code: if (tcc_state->do_bounds_check && !const_wanted) {
#include <stdio.h>
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 bounded pointers, we generate a special code to /* if bounded pointers, we generate a special code to
test bounds */ test bounds */
if (op == '-') { if (op == '-') {
@ -2525,6 +2525,7 @@ redo:
vswap(); vswap();
gen_op('-'); gen_op('-');
} }
vtop[-1].r &= ~VT_MUSTBOUND;
gen_bounded_ptr_add(); gen_bounded_ptr_add();
} else } else
#endif #endif

36
tccpe.c
View File

@ -1836,6 +1836,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
#define PE_STDSYM(n,s) "_" n s #define PE_STDSYM(n,s) "_" n s
#endif #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) static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{ {
const char *start_symbol; const char *start_symbol;
@ -1884,35 +1890,21 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
if (0 == s1->nostdlib) { if (0 == s1->nostdlib) {
static const char *libs[] = { static const char *libs[] = {
TCC_LIBTCC1,
#ifdef CONFIG_TCC_BCHECK
TCC_LIBTCCB1,
#endif
"msvcrt", "kernel32", "", "user32", "gdi32", NULL "msvcrt", "kernel32", "", "user32", "gdi32", NULL
}; };
const char **pp, *p; 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) { for (pp = libs; 0 != (p = *pp); ++pp) {
#ifdef CONFIG_TCC_BCHECK if (*p)
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 {
tcc_add_library_err(s1, 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) if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN; pe_type = PE_RUN;
pe->type = pe_type; pe->type = pe_type;

View File

@ -392,16 +392,15 @@ ST_FUNC void cstr_reset(CString *cstr)
ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...) ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
{ {
va_list v; va_list v;
va_list vc;
int len, size; int len, size;
va_start(v, fmt); va_start(v, fmt);
va_copy (vc, v); len = vsnprintf(NULL, 0, fmt, v);
len = vsnprintf(NULL, 0, fmt, vc); va_end(v);
va_end(vc);
size = cstr->size + len + 1; size = cstr->size + len + 1;
if (size > cstr->size_allocated) if (size > cstr->size_allocated)
cstr_realloc(cstr, size); cstr_realloc(cstr, size);
va_start(v, fmt);
vsnprintf((char*)cstr->data + cstr->size, size, fmt, v); vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
va_end(v); va_end(v);
cstr->size += len; cstr->size += len;

View File

@ -306,6 +306,9 @@
DEF(TOK___bound_local_new, "__bound_local_new") DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete") DEF(TOK___bound_local_delete, "__bound_local_delete")
# ifdef TCC_TARGET_PE # ifdef TCC_TARGET_PE
# ifdef TCC_TARGET_X86_64
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
# endif
DEF(TOK_malloc, "malloc") DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free") DEF(TOK_free, "free")
DEF(TOK_realloc, "realloc") DEF(TOK_realloc, "realloc")

View File

@ -23,7 +23,7 @@ TESTS = \
tests2-dir \ tests2-dir \
pp-dir pp-dir
BTESTS = test1b test3b btest test4 BTESTS = btest test2b
# test4_static -- Not all relocation types are implemented yet. # test4_static -- Not all relocation types are implemented yet.
# asmtest / asmtest2 -- minor differences with gcc # 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 $(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
@diff -u test.ref test.out3 && echo "Auto Test3 OK" @diff -u test.ref test.out3 && echo "Auto Test3 OK"
test%b : TCCFLAGS += -b -ba test%b : TCCFLAGS += -b
# binary output test # binary output test
test4: tcctest.c test.ref test4: tcctest.c test.ref
@ -130,7 +130,7 @@ test4: tcctest.c test.ref
./tcctest1 > test1.out ./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi @if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
# dynamic output + bound check # dynamic output + bound check
$(TCC) -b -ba -o tcctest4 $< $(TCC) -b -o tcctest4 $<
./tcctest4 > test4.out ./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi @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 # 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 BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
btest: boundtest.c btest: boundtest.c
@echo ------------ $@ ------------ @echo ------------ $@ ------------
@ulimit -c 0; \ @for i in $(BOUNDS_OK); do \
for i in $(BOUNDS_OK); do \
echo ; echo --- boundtest $$i ---; \ echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -ba -run $< $$i ; then \ if $(TCC) -b -run $< $$i ; then \
echo succeeded as expected; \ echo succeeded as expected; \
else\ else\
echo Failed positive test $$i ; exit 1 ; \ echo Failed positive test $$i ; exit 1 ; \
@ -179,7 +178,7 @@ btest: boundtest.c
done ;\ done ;\
for i in $(BOUNDS_FAIL); do \ for i in $(BOUNDS_FAIL); do \
echo ; echo --- boundtest $$i ---; \ echo ; echo --- boundtest $$i ---; \
if $(TCC) -b -ba -run $< $$i ; then \ if $(TCC) -b -run $< $$i ; then \
echo Failed negative test $$i ; exit 1 ;\ echo Failed negative test $$i ; exit 1 ;\
else\ else\
echo failed as expected; \ echo failed as expected; \

View File

@ -142,9 +142,6 @@ ST_DATA const int reg_classes[NB_REGS] = {
static unsigned long func_sub_sp_offset; static unsigned long func_sub_sp_offset;
static int func_ret_sub; 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 ? */ /* XXX: make it faster ? */
ST_FUNC void g(int c) ST_FUNC void g(int c)
@ -654,218 +651,19 @@ static void gen_bounds_call(int v)
#endif #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 */ /* generate a bounded pointer addition */
ST_FUNC void gen_bounded_ptr_add(void) ST_FUNC void gen_bounded_ptr_add(void)
{ {
int i; vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
vrott(3);
nested_call++; gfunc_call(2);
vpushi(0);
/* 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
}
/* returned pointer is in rax */ /* returned pointer is in rax */
vtop++;
vtop->r = TREG_RAX | VT_BOUNDED; vtop->r = TREG_RAX | VT_BOUNDED;
if (nocode_wanted)
for (i = call_used_nr_reg - 1; i >= 0; i--) { return;
switch (call_used_regs[i]) {
case TREG_RAX: case TREG_RCX: case TREG_RDX: case TREG_RSP:
case TREG_RSI: case TREG_RDI:
o(0x58 + call_used_regs[i]); /* pop reg */
break;
case TREG_R8: case TREG_R9: case TREG_R10: case TREG_R11:
o(0x5841 + (call_used_regs[i] - TREG_R8) * 0x100); /* pop reg */
break;
case TREG_XMM0: case TREG_XMM1: case TREG_XMM2: case TREG_XMM3:
case TREG_XMM4: case TREG_XMM5: case TREG_XMM6: case TREG_XMM7:
/* vmovdqu (%rsp),%xmmx */
o(0x046ffac5 + (call_used_regs[i] - TREG_XMM0) * 0x8000000); o(0x24);
o(0x10c48348); /* add $10,%rsp */
break;
}
}
/* relocation offset of the bounding function call point */ /* relocation offset of the bounding function call point */
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela))); vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela)));
nested_call--;
} }
/* patch pointer addition in vtop so that pointer dereferencing is /* 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; ElfW(Rela) *rel;
Sym *sym; Sym *sym;
if (nocode_wanted)
return;
size = 0; size = 0;
/* XXX: put that code in generic part of tcc */ /* XXX: put that code in generic part of tcc */
if (!is_float(vtop->type.t)) { if (!is_float(vtop->type.t)) {
@ -886,7 +687,7 @@ ST_FUNC void gen_bounded_ptr_deref(void)
size = 2; size = 2;
} }
if (!size) if (!size)
size = type_size(&vtop->type, &align); size = type_size(&vtop->type, &align);
switch(size) { switch(size) {
case 1: func = TOK___bound_ptr_indir1; break; case 1: func = TOK___bound_ptr_indir1; break;
case 2: func = TOK___bound_ptr_indir2; 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 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break; case 16: func = TOK___bound_ptr_indir16; break;
default: default:
tcc_error("unhandled size when dereferencing bounded pointer"); /* may happen with struct member access */
func = 0; return;
break; //tcc_error("unhandled size when dereferencing bounded pointer");
//func = 0;
//break;
} }
sym = external_global_sym(func, &func_old_type); sym = external_global_sym(func, &func_old_type);
if (!sym->c) if (!sym->c)
put_extern_sym(sym, NULL, 0, 0); put_extern_sym(sym, NULL, 0, 0);
/* patch relocation */ /* patch relocation */
/* XXX: find a better solution ? */ /* XXX: find a better solution ? */
rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i); 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)); 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 size, r, args_size, i, d, bt, struct_size;
int arg; 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; args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
arg = nb_args; arg = nb_args;
@ -1051,7 +856,6 @@ void gfunc_call(int nb_args)
} else { } else {
d = arg_prepare_reg(arg); d = arg_prepare_reg(arg);
gen_offs_sp(0x8d, d, struct_size); gen_offs_sp(0x8d, d, struct_size);
call_used_regs[call_used_nr_reg++] = d;
} }
struct_size += size; struct_size += size;
} else { } else {
@ -1070,7 +874,6 @@ void gfunc_call(int nb_args)
o(0x66); o(0x66);
orex(1,d,0, 0x7e0f); orex(1,d,0, 0x7e0f);
o(0xc0 + arg*8 + REG_VALUE(d)); o(0xc0 + arg*8 + REG_VALUE(d));
call_used_regs[call_used_nr_reg++] = d;
} }
} else { } else {
if (bt == VT_STRUCT) { if (bt == VT_STRUCT) {
@ -1086,7 +889,6 @@ void gfunc_call(int nb_args)
d = arg_prepare_reg(arg); d = arg_prepare_reg(arg);
orex(1,d,r,0x89); /* mov */ orex(1,d,r,0x89); /* mov */
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); 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) { if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
/* need to add the "func_scratch" area after 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 */ /* 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 */ o(0xc089); /* mov %eax,%eax */
#endif #endif
vtop--; vtop--;
call_used_nr_reg = 0;
} }
@ -1141,7 +947,7 @@ void gfunc_prolog(Sym *func_sym)
int n_arg = 0; int n_arg = 0;
func_ret_sub = 0; func_ret_sub = 0;
func_scratch = 0; func_scratch = 32;
func_alloca = 0; func_alloca = 0;
loc = 0; loc = 0;
@ -1228,6 +1034,10 @@ void gfunc_epilog(void)
{ {
int v, saved_ind; 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 #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check if (tcc_state->do_bounds_check
&& func_bound_offset != lbounds_section->data_offset) && func_bound_offset != lbounds_section->data_offset)
@ -1273,9 +1083,7 @@ void gfunc_epilog(void)
saved_ind = ind; saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
/* align local size to word & save local variables */ v = -loc;
func_scratch = (func_scratch + 15) & -16;
v = (func_scratch + -loc + 15) & -16;
if (v >= 4096) { if (v >= 4096) {
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type); 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; int sse_reg, gen_reg;
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack; 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 /* calculate the number of integer/float register arguments, remember
arguments to be passed via stack (in onstack[]), and also 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 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(0x280f);
o(0xc0 + (sse_reg << 3)); 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 { } else {
assert(reg_count == 1); assert(reg_count == 1);
--sse_reg; --sse_reg;
/* Load directly to register */ /* Load directly to register */
gv(RC_XMM0 << sse_reg); gv(RC_XMM0 << sse_reg);
call_used_regs[call_used_nr_reg++] = sse_reg + TREG_XMM0;
} }
} else if (mode == x86_64_mode_integer) { } else if (mode == x86_64_mode_integer) {
/* simple type */ /* simple type */
@ -1629,12 +1439,10 @@ void gfunc_call(int nb_args)
d = arg_prepare_reg(gen_reg); d = arg_prepare_reg(gen_reg);
orex(1,d,r,0x89); /* mov */ orex(1,d,r,0x89); /* mov */
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d)); o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
call_used_regs[call_used_nr_reg++] = d;
if (reg_count == 2) { if (reg_count == 2) {
d = arg_prepare_reg(gen_reg+1); d = arg_prepare_reg(gen_reg+1);
orex(1,d,vtop->r2,0x89); /* mov */ orex(1,d,vtop->r2,0x89); /* mov */
o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d)); o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
call_used_regs[call_used_nr_reg++] = d;
} }
} }
vtop--; vtop--;
@ -1677,7 +1485,6 @@ void gfunc_call(int nb_args)
else if (bt == (VT_SHORT | VT_UNSIGNED)) else if (bt == (VT_SHORT | VT_UNSIGNED))
o(0xc0b70f); /* movzwl %al, %eax */ o(0xc0b70f); /* movzwl %al, %eax */
vtop--; vtop--;
call_used_nr_reg = 0;
} }

View File

@ -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 */ #endif /* !TARGET_DEFS_ONLY */