Fix bounds checking for linux/windows

This commit is contained in:
herman ten brugge 2019-12-10 08:07:25 +01:00
parent 474f95dda8
commit 4461f38a9e
22 changed files with 1245 additions and 757 deletions

View File

@ -16,6 +16,7 @@ endif
LIBTCC = libtcc.a
LIBTCC1 = libtcc1.a
LIBTCCB1 = libtccb1.a
LINK_LIBTCC =
LIBS =
CFLAGS += -I$(TOP)
@ -86,7 +87,7 @@ ifeq ($(INCLUDED),no)
# running top Makefile
PROGS = tcc$(EXESUF)
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
TCCLIBS = $(LIBTCC1) $(LIBTCCB1) $(LIBTCC) $(LIBTCCDEF)
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
@ -100,11 +101,15 @@ 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) $(PROGS_CROSS)
cross: $(LIBTCC1_CROSS) $(LIBTCCB1_CROSS) $(PROGS_CROSS)
# build specific cross compiler & lib
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
@ -148,10 +153,10 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx))
ifneq ($(X),)
ifeq ($(CONFIG_WIN32),yes)
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
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\""
else
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\""
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif
endif
@ -269,6 +274,8 @@ 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)
@ -279,6 +286,7 @@ IR = mkdir -p $2 && cp -r $1/. $2
install-unx:
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
$(call IFw,$(LIBTCCB1) $(LIBTCCB1_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)")
@ -304,6 +312,7 @@ 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 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

@ -1264,8 +1264,9 @@ void gfunc_call(int nb_args)
}
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
Sym *sym,*sym2;
int n, nf, size, align, rs, struct_ret = 0;
int addr, pn, sn; /* pn=core, sn=stack */

View File

@ -996,8 +996,9 @@ static int arm64_func_va_list_gr_offs;
static int arm64_func_va_list_vr_offs;
static int arm64_func_sub_sp_offset;
ST_FUNC void gfunc_prolog(CType *func_type)
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int n = 0;
int i = 0;
Sym *sym;

View File

@ -1939,8 +1939,9 @@ void gfunc_call(int nb_args)
// parameters are loaded and restored upon return (or if/when needed).
/* generate function prolog of type 't' */
void gfunc_prolog(CType * func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, align, size, func_call, i;
Sym *sym;
CType *type;

View File

@ -512,10 +512,12 @@ ST_FUNC void gfunc_call(int nb_args)
#endif
/* generate function prolog of type 't' */
ST_FUNC void gfunc_prolog(CType *func_type)
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, align, size, func_call, fastcall_nb_regs;
int param_index, param_addr;
int n_arg = 0;
uint8_t *fastcall_regs_ptr;
Sym *sym;
CType *type;
@ -558,6 +560,7 @@ ST_FUNC void gfunc_prolog(CType *func_type)
}
/* define parameters */
while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type;
size = type_size(type, &align);
size = (size + 3) & ~3;
@ -597,6 +600,12 @@ ST_FUNC void gfunc_prolog(CType *func_type)
func_bound_ind = ind;
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
o(0x0c458b); /* mov 0x12(%ebp),%eax */
o(0x50); /* push %eax */
gen_static_call(TOK___bound_main_arg);
o(0x04c483); /* add $0x4,%esp */
}
}
#endif
}
@ -1003,6 +1012,7 @@ ST_FUNC void gen_cvt_itof(int t)
o(0x2404db); /* fildl (%esp) */
o(0x04c483); /* add $4, %esp */
}
vtop->r2 = VT_CONST;
vtop->r = TREG_ST0;
}
@ -1040,14 +1050,87 @@ ST_FUNC void ggoto(void)
/* bound check support functions */
#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
}
}
/* 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);
/* save all temporary registers */
vtop -= 2;
save_regs(0);
/* do a fast function call */
gen_static_call(TOK___bound_ptr_add);
/* returned pointer is in eax */

View File

@ -8,6 +8,7 @@ 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)
@ -19,6 +20,8 @@ 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)
@ -39,6 +42,8 @@ ifdef CONFIG_OSX
XFLAGS += -D_ANSI_SOURCE
endif
XFLAGS += -g -Wno-deprecated-declarations
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
@ -46,11 +51,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) $(BCHECK_O) $(DSO_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
OBJ-i386 = $(I386_O) $(DSO_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(DSO_O)
OBJ-x86_64-osx = $(X86_64_O) va_list.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-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o (WIN_O)
OBJ-arm64 = $(ARM64_O) $(DSO_O)
OBJ-arm = $(ARM_O) $(DSO_O)
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
@ -61,9 +66,29 @@ 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 =
OBJB-i386-win32 = bcheck.o
OBJB-x86_64-win32 = bcheck.o
OBJB-arm64 =
OBJB-arm =
OBJB-arm-fpa =
OBJB-arm-fpa-ld =
OBJB-arm-vfp =
OBJB-arm-eabi =
OBJB-arm-eabihf =
OBJB-arm-wince =
OBJB-riscv64 =
all: $(BIN) $(BINB)
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
$(XAR) rcs $@ $^
$(BINB) : $(patsubst %.o,$(X)%.o,$(OBJB-$T))
$(XAR) rcs $@ $^
$(X)%.o : %.c
$(XCC) -c $< -o $@ $(XFLAGS)
@ -74,4 +99,4 @@ $(X)crt1w.o : crt1.c
$(X)wincrt1w.o : wincrt1.c
clean :
rm -f *.a *.o $(BIN)
rm -f *.a *.o $(BIN) $(BINB)

File diff suppressed because it is too large Load Diff

View File

@ -614,8 +614,9 @@ ST_FUNC void gfunc_call(int nb_args)
static int func_sub_sp_offset, num_va_regs, func_va_list_ofs;
ST_FUNC void gfunc_prolog(CType *func_type)
ST_FUNC void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int i, addr, align, size;
int param_addr = 0;
int areg[2];

8
tcc.h
View File

@ -292,6 +292,9 @@ 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
@ -1202,6 +1205,9 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
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);
#endif
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
@ -1518,7 +1524,7 @@ ST_FUNC void load(int r, SValue *sv);
ST_FUNC void store(int r, SValue *v);
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
ST_FUNC void gfunc_call(int nb_args);
ST_FUNC void gfunc_prolog(CType *func_type);
ST_FUNC void gfunc_prolog(Sym *func_sym);
ST_FUNC void gfunc_epilog(void);
ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t);

View File

@ -1317,42 +1317,13 @@ ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
add_array (".fini_array", s1, sym);
}
ST_FUNC void tcc_add_bcheck(TCCState *s1)
{
#ifdef CONFIG_TCC_BCHECK
addr_t *ptr;
int sym_index;
if (0 == s1->do_bounds_check)
return;
/* XXX: add an object file to do that */
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
*ptr = 0;
set_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
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 = section_ptr_add(init_section, 5);
pinit[0] = 0xe8;
write32le(pinit + 1, -4);
put_elf_reloc(symtab_section, init_section,
init_section->data_offset - 4, R_386_PC32, sym_index);
/* R_386_PC32 = R_X86_64_PC32 = 2 */
}
#endif
}
/* add tcc runtime libraries */
ST_FUNC void tcc_add_runtime(TCCState *s1)
{
s1->filetype = 0;
#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
#endif
tcc_add_pragma_libs(s1);
#ifndef TCC_TARGET_PE
/* add libc */
@ -1365,6 +1336,13 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
else
tcc_add_dll(s1, TCC_LIBGCC, 0);
}
#endif
#ifdef CONFIG_TCC_BCHECK
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);
}
#endif
tcc_add_support(s1, TCC_LIBTCC1);
/* add crt end if not memory output */
@ -2814,6 +2792,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
const char *ar_names, *p;
const uint8_t *ar_index;
ElfW(Sym) *sym;
Section *s;
data = tcc_malloc(size);
if (full_read(fd, data, size) != size)
@ -2825,9 +2804,14 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
do {
bound = 0;
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
sym_index = find_elf_sym(symtab_section, p);
s = symtab_section;
sym_index = find_elf_sym(s, p);
if(sym_index == 0) {
s = s1->dynsymtab_section;
sym_index = find_elf_sym(s, p);
}
if(sym_index) {
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sym = &((ElfW(Sym) *)s->data)[sym_index];
if(sym->st_shndx == SHN_UNDEF) {
off = (entrysize == 4
? get_be32(ar_index + i * 4)

View File

@ -405,6 +405,8 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
case TOK_strlen:
case TOK_strcpy:
case TOK_alloca:
case TOK_mmap:
case TOK_munmap:
strcpy(buf, "__bound_");
strcat(buf, name);
name = buf;
@ -1191,6 +1193,10 @@ ST_FUNC void save_reg_upstack(int r, int n)
type = &int_type;
#endif
size = type_size(type, &align);
if ((p->r2 & VT_VALMASK) < VT_CONST) {
size *= 2;
align *= 2;
}
l=get_temp_local_var(size,align);
sv.type.t = type->t;
sv.r = VT_LOCAL | VT_LVAL;
@ -1375,7 +1381,7 @@ static void gbound(void)
vtop->r &= ~VT_MUSTBOUND;
/* if lvalue, then use checking code before dereferencing */
if (vtop->r & VT_LVAL) {
if ((vtop->r & VT_LVAL) && !nocode_wanted) {
/* if not VT_BOUNDED value, then make one */
if (!(vtop->r & VT_BOUNDED)) {
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
@ -5478,6 +5484,15 @@ special_math_val:
Sym *sa;
int nb_args, ret_nregs, ret_align, regsize, variadic;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && (vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
addr_t *bounds_ptr;
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = 1; /* marks alloca/vla used */
bounds_ptr[1] = 0;
}
#endif
/* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
/* pointer test (no array accepted) */
@ -7413,7 +7428,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if ((r & VT_VALMASK) == VT_LOCAL) {
sec = NULL;
#ifdef CONFIG_TCC_BCHECK
if (bcheck && (type->t & VT_ARRAY)) {
if (bcheck && ((type->t & VT_ARRAY) ||
(type->t & VT_BTYPE) == VT_STRUCT)) {
loc--;
}
#endif
@ -7422,8 +7438,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
#ifdef CONFIG_TCC_BCHECK
/* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track
'&' operators, so we add only arrays */
if (bcheck && (type->t & VT_ARRAY)) {
'&' operators, so we add only arrays/structs/unions */
if (bcheck && ((type->t & VT_ARRAY) ||
(type->t & VT_BTYPE) == VT_STRUCT)) {
addr_t *bounds_ptr;
/* add padding between regions */
loc--;
@ -7542,6 +7559,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
gen_vla_sp_save(addr);
cur_scope->vla.loc = addr;
cur_scope->vla.num++;
#ifdef CONFIG_TCC_BCHECK
if (bcheck) {
addr_t *bounds_ptr;
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
bounds_ptr[0] = 1; /* marks alloca/vla used */
bounds_ptr[1] = 0;
}
#endif
} else if (has_init) {
size_t oldreloc_offset = 0;
@ -7599,7 +7625,7 @@ static void gen_function(Sym *sym, AttributeDef *ad)
/* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0);
local_scope = 1; /* for function parameters */
gfunc_prolog(&sym->type);
gfunc_prolog(sym);
local_scope = 0;
rsym = 0;
clear_temp_local_var_list();

16
tccpe.c
View File

@ -1880,15 +1880,29 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
if (0 == s1->nostdlib) {
static const char *libs[] = {
TCC_LIBTCC1, "msvcrt", "kernel32", "", "user32", "gdi32", NULL
TCC_LIBTCC1,
#ifdef CONFIG_TCC_BCHECK
TCC_LIBTCCB1,
#endif
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
};
const char **pp, *p;
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 {
tcc_add_library_err(s1, p);
}

View File

@ -137,30 +137,23 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
if (s1->do_bounds_check) {
void (*bound_init)(void);
void (*bound_exit)(void);
void (*bound_new_region)(void *p, addr_t size);
int (*bound_delete_region)(void *p);
int i, ret;
void (*bounds_add_static_var)(size_t *p);
size_t *bounds_start;
int ret;
/* set error function */
rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
/* XXX: use .init section so that it also work in binary ? */
bound_init = tcc_get_symbol_err(s1, "__bound_init");
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
bound_new_region = tcc_get_symbol_err(s1, "__bound_new_region");
bound_delete_region = tcc_get_symbol_err(s1, "__bound_delete_region");
bounds_add_static_var = tcc_get_symbol_err(s1, "__bounds_add_static_var");
bounds_start = tcc_get_symbol_err(s1, "__bounds_start");
bound_init();
/* mark argv area as valid */
bound_new_region(argv, argc*sizeof(argv[0]));
for (i=0; i<argc; ++i)
bound_new_region(argv[i], strlen(argv[i]) + 1);
bounds_add_static_var (bounds_start);
ret = (*prog_main)(argc, argv);
/* unmark argv area */
for (i=0; i<argc; ++i)
bound_delete_region(argv[i]);
bound_delete_region(argv);
bound_exit();
return ret;
}

View File

@ -312,6 +312,8 @@
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
# endif
DEF(TOK_mmap, "mmap")
DEF(TOK_munmap, "munmap")
DEF(TOK_strlen, "strlen")
DEF(TOK_strcpy, "strcpy")
#endif

View File

@ -151,8 +151,9 @@ memtest:
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10 14
BOUNDS_FAIL= 2 5 7 9 11 12 13 15
# 3 is profiling test
BOUNDS_OK = 1 4 8 10 14 16
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
btest: boundtest.c
@echo ------------ $@ ------------

View File

@ -81,7 +81,6 @@ int test5(void)
}
/* error */
/* XXX: currently: bug */
int test6(void)
{
int i, sum = 0;
@ -253,10 +252,20 @@ int (*table_test[])(void) = {
int main(int argc, char **argv)
{
int i;
char *cp;
int index;
int (*ftest)(void);
int index_max = sizeof(table_test)/sizeof(table_test[0]);
/* check bounds checking main arg */
for (i = 0; i < argc; i++) {
cp = argv[i];
while (*cp) {
cp++;
}
}
if (argc < 2) {
printf(
"test TCC bound checking system\n"

View File

@ -123,6 +123,7 @@ void math_cmp_test(void);
void callsave_test(void);
void builtin_frame_address_test(void);
void attrib_test(void);
void bounds_check1_test(void);
int fib(int n);
void num(int n);
@ -771,6 +772,7 @@ int main(int argc, char **argv)
if (via_volatile (42) != 42)
printf ("via_volatile broken\n");
attrib_test();
bounds_check1_test();
return 0;
}
@ -3884,9 +3886,11 @@ void builtin_frame_address_test(void)
printf("str: %s\n", str);
#ifndef __riscv
#ifndef __BOUNDS_CHECKING_ON
bfa1(str-fp0);
#endif
#endif
#endif
}
char via_volatile (char i)
@ -3961,3 +3965,18 @@ int force_get_order(unsigned long s)
{
return __get_order(s);
}
#define pv(m) printf(sizeof (s->m + 0) == 8 ? "%016lx\n" : "%02x\n", s->m)
/* Test failed when using bounds checking */
void bounds_check1_test (void)
{
struct s {
int x;
long long y;
} _s, *s = &_s;
s->x = 10;
s->y = 20;
pv(x);
pv(y);
}

View File

@ -0,0 +1,27 @@
#include <stdio.h>
typedef struct
{
double average;
int count;
}
stats_type;
static void
testc (stats_type *s, long long data)
{
s->average = (s->average * s->count + data) / (s->count + 1);
s->count++;
}
int main (void)
{
stats_type s;
s.average = 0;
s.count = 0;
testc (&s, 10);
testc (&s, 20);
printf ("%g %d\n", s.average, s.count);
return 0;
}

View File

@ -0,0 +1 @@
15 2

View File

@ -0,0 +1,22 @@
#include <stdio.h>
union u {
unsigned long ul;
long double ld;
};
void
conv (union u *p)
{
p->ul = (unsigned int) p->ld;
}
int main (void)
{
union u v;
v.ld = 42;
conv (&v);
printf ("%lu\n", v.ul);
return 0;
}

View File

@ -0,0 +1 @@
42

View File

@ -141,6 +141,7 @@ ST_DATA const int reg_classes[NB_REGS] = {
static unsigned long func_sub_sp_offset;
static int func_ret_sub;
static int in_call;
/* XXX: make it faster ? */
ST_FUNC void g(int c)
@ -636,16 +637,101 @@ static void gcall_or_jmp(int is_jmp)
}
#if defined(CONFIG_TCC_BCHECK)
#ifndef TCC_TARGET_PE
static addr_t func_bound_offset;
static unsigned long func_bound_ind;
#endif
static void gen_static_call(int v)
static void gen_bounds_call(int v)
{
Sym *sym = external_global_sym(v, &func_old_type);
oad(0xe8, 0);
#ifdef TCC_TARGET_PE
greloca(cur_text_section, sym, ind-4, R_X86_64_PC32, -4);
#else
greloca(cur_text_section, sym, ind-4, R_X86_64_PLT32, -4);
#endif
}
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
}
}
/* generate a bounded pointer addition */
@ -654,22 +740,49 @@ ST_FUNC void gen_bounded_ptr_add(void)
/* save all temporary registers */
save_regs(0);
if (in_call) {
o(0x51525657); /* push $rdi/%rsi/%rdx/%rcx */
o(0x51415041); /* push $r8/%r9 */
o(0x53415241); /* push $r10/%r11 */
}
/* prepare fast x86_64 function call */
gv(RC_RAX);
#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--;
#ifdef TCC_TARGET_PE
o(0x20ec8348); /* sub $20, %rsp */
#endif
/* do a fast function call */
gen_static_call(TOK___bound_ptr_add);
gen_bounds_call(TOK___bound_ptr_add);
#ifdef TCC_TARGET_PE
o(0x20c48348); /* add $20, %rsp */
#endif
/* returned pointer is in rax */
vtop++;
vtop->r = TREG_RAX | VT_BOUNDED;
if (in_call) {
o(0x5a415b41); /* pop $r11/%r10 */
o(0x58415941); /* pop $r9/%r8 */
o(0x5f5e5a59); /* pop $rcx/$rdx/$rsi/%rdi */
}
/* relocation offset of the bounding function call point */
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela)));
@ -799,6 +912,8 @@ void gfunc_call(int nb_args)
int size, r, args_size, i, d, bt, struct_size;
int arg;
in_call = 1;
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
arg = nb_args;
@ -909,7 +1024,7 @@ 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(0x05, func_alloca); /* sub $NN, %rax */
o(0x48); func_alloca = oad(0x2d, func_alloca); /* sub $NN, %rax */
}
/* other compilers don't clear the upper bits when returning char/short */
@ -929,17 +1044,20 @@ void gfunc_call(int nb_args)
o(0xc089); /* mov %eax,%eax */
#endif
vtop--;
in_call = 0;
}
#define FUNC_PROLOG_SIZE 11
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
int addr, reg_param_index, bt, size;
Sym *sym;
CType *type;
int n_arg = 0;
func_ret_sub = 0;
func_scratch = 0;
@ -967,6 +1085,7 @@ void gfunc_prolog(CType *func_type)
/* define parameters */
while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type;
bt = type->t & VT_BTYPE;
size = gfunc_arg_size(type);
@ -1002,6 +1121,25 @@ void gfunc_prolog(CType *func_type)
}
reg_param_index++;
}
#ifdef CONFIG_TCC_BCHECK
/* leave some room for bound checking code */
if (tcc_state->do_bounds_check) {
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
o(0xb848); /* lbound section pointer */
gen_le64 (0);
o(0xc18948); /* mov %rax,%rcx ## first arg in %rdi, this must be ptr */
o(0x20ec8348); /* sub $20, %rsp */
oad(0xb8, 0); /* call to function */
o(0x20c48348); /* add $20, %rsp */
if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
o(0x184d8b48); /* mov 0x18(%rbp),%rcx */
o(0x20ec8348); /* sub $20, %rsp */
gen_bounds_call(TOK___bound_main_arg);
o(0x20c48348); /* add $20, %rsp */
}
}
#endif
}
/* generate function epilog */
@ -1009,6 +1147,40 @@ void gfunc_epilog(void)
{
int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check
&& func_bound_offset != lbounds_section->data_offset)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
/* add end of table info */
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
*bounds_ptr = 0;
/* generate bound local allocation */
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
func_bound_offset, lbounds_section->data_offset);
saved_ind = ind;
ind = func_bound_ind;
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
ind = ind + 10 + 3 + 4;
gen_bounds_call(TOK___bound_local_new);
ind = saved_ind;
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
o(0xb848); /* mov xxx, %rax */
gen_le64 (0);
o(0xc18948); /* mov %rax,%rcx # first arg in %rdi, this must be ptr */
o(0x20ec8348); /* sub $20, %rsp */
gen_bounds_call(TOK___bound_local_delete);
o(0x20c48348); /* add $20, %rsp */
o(0x585a); /* restore returned value, if any */
}
#endif
o(0xc9); /* leave */
if (func_ret_sub == 0) {
o(0xc3); /* ret */
@ -1226,6 +1398,8 @@ void gfunc_call(int nb_args)
int sse_reg, gen_reg;
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
in_call = 1;
/* 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
@ -1419,6 +1593,7 @@ void gfunc_call(int nb_args)
else if (bt == (VT_SHORT | VT_UNSIGNED))
o(0xc0b70f); /* movzwl %al, %eax */
vtop--;
in_call = 0;
}
@ -1430,11 +1605,13 @@ static void push_arg_reg(int i) {
}
/* generate function prolog of type 't' */
void gfunc_prolog(CType *func_type)
void gfunc_prolog(Sym *func_sym)
{
CType *func_type = &func_sym->type;
X86_64_Mode mode;
int i, addr, align, size, reg_count;
int param_addr = 0, reg_param_index, sse_param_index;
int n_arg = 0;
Sym *sym;
CType *type;
@ -1518,6 +1695,7 @@ void gfunc_prolog(CType *func_type)
}
/* define parameters */
while ((sym = sym->next) != NULL) {
n_arg++;
type = &sym->type;
mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);
switch (mode) {
@ -1574,9 +1752,14 @@ void gfunc_prolog(CType *func_type)
if (tcc_state->do_bounds_check) {
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
oad(0xb8, 0); /* lbound section pointer */
o(0xb848); /* lbound section pointer */
gen_le64 (0);
o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */
oad(0xb8, 0); /* call to function */
if (n_arg >= 2 && strcmp (get_tok_str(func_sym->v, NULL), "main") == 0) {
o(0xf07d8b48); /* mov -0x10(%rbp),%rdi */
gen_bounds_call(TOK___bound_main_arg);
}
}
#endif
}
@ -1603,17 +1786,18 @@ void gfunc_epilog(void)
func_bound_offset, lbounds_section->data_offset);
saved_ind = ind;
ind = func_bound_ind;
greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0);
ind = ind + 5 + 3;
gen_static_call(TOK___bound_local_new);
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
ind = ind + 10 + 3;
gen_bounds_call(TOK___bound_local_new);
ind = saved_ind;
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
greloca(cur_text_section, sym_data, ind + 1, R_X86_64_64, 0);
oad(0xb8, 0); /* mov xxx, %rax */
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
o(0xb848); /* mov xxx, %rax */
gen_le64 (0);
o(0xc78948); /* mov %rax,%rdi # first arg in %rdi, this must be ptr */
gen_static_call(TOK___bound_local_delete);
gen_bounds_call(TOK___bound_local_delete);
o(0x585a); /* restore returned value, if any */
}
#endif
@ -1940,6 +2124,7 @@ void gen_opf(int op)
v1.c.i = fc;
load(r, &v1);
fc = 0;
vtop->r = r = r | VT_LVAL;
}
if (op == TOK_EQ || op == TOK_NE) {
@ -2007,6 +2192,7 @@ void gen_opf(int op)
v1.c.i = fc;
load(r, &v1);
fc = 0;
vtop->r = r = r | VT_LVAL;
}
assert(!(vtop[-1].r & VT_LVAL));