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.
This commit is contained in:
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
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")

View File

@ -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

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 */

View File

@ -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 <target>-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)

View File

@ -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
sub $32,%rsp
call __bound_new_region
add $20,%rsp
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

View File

@ -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

View File

@ -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;

View File

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

View File

@ -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;

1
tcc.c
View File

@ -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"

9
tcc.h
View File

@ -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 ------------ */

View File

@ -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);

View File

@ -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 <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 (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

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
#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;

View File

@ -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;

View File

@ -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")

View File

@ -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; \

View File

@ -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)) {
@ -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;
}

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 */