mirror of
https://github.com/frida/tinycc
synced 2024-12-24 05:56:49 +03:00
Update bound checking code.
Add __attribute__((constructor)) to __bounds_init. - remove tcc_add_bcheck from i386-link.c and x86_64-link.c - add simplified tcc_add_bcheck to tccelf.c - Update tccrun.c to call constructor/destructor. Set dynsym sh_info to number of local symbols in tccelf.c Reduce stack size when bounds checking is enabled. Added variable TCC_LIBBCHECK for windows support. Add signal stack to detect stack overflow. Add all & parameters in lbound_section and remove them if not used. Close fd in tcc_relocate in tccrun.c Fix section type constructor/destructor in tccelf.c Add check code in tests/boundtest.c for mem/str functions. Remove -ba from documentation. Add bounds check signal info in documentation. bcheck.c: - Fix initial_pool alignment. . Fix printf statements. . Add prototypes for all external interface functions. - Add TCC_BOUNDS_WARN_POINTER_ADD environment variable. . Add ctype and errno data. - Fix alloca when multithreading is used. - Add lock for __bound_checking and __bound_never_fatal. - Catch pthread_create and use locks when called. - Detect in loaded in shared lib and use locks when found - Use spin locks instead of semaphore locks. - Make spin locked code as small as possible. - Fix mem/str functions checking. - Fix overlap checking mem/str functions.
This commit is contained in:
parent
0d6801b130
commit
3877618785
@ -95,7 +95,6 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
||||
static unsigned long func_sub_sp_offset;
|
||||
static int func_ret_sub;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
#endif
|
||||
|
||||
@ -402,8 +401,10 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
Sym *func_sym;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
args_size = 0;
|
||||
@ -485,6 +486,10 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
75
i386-link.c
75
i386-link.c
@ -235,79 +235,4 @@ 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 */
|
||||
|
1132
lib/bcheck.c
1132
lib/bcheck.c
File diff suppressed because it is too large
Load Diff
43
tcc-doc.texi
43
tcc-doc.texi
@ -356,8 +356,10 @@ memory allocations and array/pointer bounds. @option{-g} is implied. Note
|
||||
that the generated code is slower and bigger in this case.
|
||||
The bound checking code is not included in shared libaries. The main executable should always be compiled with the @option{-b}.
|
||||
|
||||
There are four environment variables that can be used:
|
||||
There are five environment variables that can be used:
|
||||
@table @option
|
||||
@item TCC_BOUNDS_WARN_POINTER_ADD
|
||||
Print warning when pointer add creates an illegal pointer.
|
||||
@item TCC_BOUNDS_PRINT_CALLS
|
||||
Print bound checking calls. Can be used for debugging.
|
||||
@item TCC_BOUNDS_PRINT_HEAP
|
||||
@ -368,10 +370,7 @@ Print statistic information at exit of program.
|
||||
Try to continue in case of a bound checking error.
|
||||
@end table
|
||||
|
||||
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) when using libtcc for the moment.
|
||||
|
||||
@item -ba
|
||||
Generate address checking tests when using @option{-b}. This will be a lot slower but finds more errors.
|
||||
Note: @option{-b} is only available on i386 (linux and windows) and x86_64 (linux and windows) for the moment.
|
||||
|
||||
@item -bt N
|
||||
Display N callers in stack traces. This is useful with @option{-g} or
|
||||
@ -947,6 +946,40 @@ Here are some examples of caught errors:
|
||||
|
||||
@end table
|
||||
|
||||
Signal handlers are not compatible with bounds checking. The code
|
||||
below can be used to protect signal handlers.
|
||||
The call to __bound_checking(1) will disable bounds checking in the
|
||||
whole application.
|
||||
|
||||
The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to
|
||||
disable bounds checking for some code. This is not recommended.
|
||||
It is better to fix the code.
|
||||
|
||||
@example
|
||||
|
||||
#ifdef __BOUNDS_CHECKING_ON
|
||||
extern void __bound_checking (int no_check);
|
||||
#define BOUNDS_CHECKING_OFF __bound_checking(1)
|
||||
#define BOUNDS_CHECKING_ON __bound_checking(-1)
|
||||
#else
|
||||
#define BOUNDS_CHECKING_OFF
|
||||
#define BOUNDS_CHECKING_ON
|
||||
#endif
|
||||
|
||||
void real_signal_handler(int sig, siginfo_t *info, void *ucontext)
|
||||
@{
|
||||
...
|
||||
@}
|
||||
|
||||
void signal_handler(int sig, void *info, void *ucontext)
|
||||
@{
|
||||
BOUNDS_CHECKING_OFF;
|
||||
real_signal_handler(sig, info, data);
|
||||
BOUNDS_CHECKING_ON;
|
||||
@}
|
||||
|
||||
@end example
|
||||
|
||||
@node Libtcc
|
||||
@chapter The @code{libtcc} library
|
||||
|
||||
|
8
tcc.h
8
tcc.h
@ -292,6 +292,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#ifndef TCC_LIBTCC1
|
||||
# define TCC_LIBTCC1 "libtcc1.a"
|
||||
#endif
|
||||
#ifndef TCC_LIBBCHECK
|
||||
# define TCC_LIBBCHECK "bcheck.o"
|
||||
#endif
|
||||
|
||||
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
|
||||
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
|
||||
@ -1375,6 +1378,9 @@ ST_DATA CType func_vt; /* current function return type (used by return instructi
|
||||
ST_DATA int func_var; /* true if current function is variadic */
|
||||
ST_DATA int func_vc;
|
||||
ST_DATA const char *funcname;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_DATA addr_t func_bound_offset;
|
||||
#endif
|
||||
|
||||
ST_FUNC void tcc_debug_start(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_end(TCCState *s1);
|
||||
@ -1440,6 +1446,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
ST_FUNC void save_temp_local(int nb_args);
|
||||
ST_FUNC void restore_temp_local(void);
|
||||
#endif
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
33
tccelf.c
33
tccelf.c
@ -85,6 +85,23 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
|
||||
lbounds_section = new_section(s, ".lbounds",
|
||||
SHT_PROGBITS, SHF_ALLOC);
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
{
|
||||
addr_t *ptr;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
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 */
|
||||
set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bound_init");
|
||||
}
|
||||
#endif
|
||||
|
||||
ST_FUNC void tccelf_stab_new(TCCState *s)
|
||||
@ -1288,7 +1305,7 @@ static int tcc_add_support(TCCState *s1, const char *filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_array (const char *section, TCCState *s1, Sym *sym)
|
||||
static void add_array (const char *section, TCCState *s1, Sym *sym, int sh_type)
|
||||
{
|
||||
Section *s;
|
||||
unsigned char *ptr;
|
||||
@ -1296,6 +1313,9 @@ static void add_array (const char *section, TCCState *s1, Sym *sym)
|
||||
s = find_section(s1, section);
|
||||
if (s) {
|
||||
s->sh_flags |= SHF_WRITE;
|
||||
#ifndef TCC_TARGET_PE
|
||||
s->sh_type = sh_type;
|
||||
#endif
|
||||
ptr = section_ptr_add(s, PTR_SIZE);
|
||||
memset (ptr, 0, PTR_SIZE);
|
||||
put_elf_reloc (s1->symtab, s, ptr - s->data, R_DATA_PTR, sym->c);
|
||||
@ -1304,12 +1324,12 @@ static void add_array (const char *section, TCCState *s1, Sym *sym)
|
||||
|
||||
ST_FUNC void add_init_array (TCCState *s1, Sym *sym)
|
||||
{
|
||||
add_array (".init_array", s1, sym);
|
||||
add_array (".init_array", s1, sym, SHT_INIT_ARRAY);
|
||||
}
|
||||
|
||||
ST_FUNC void add_fini_array (TCCState *s1, Sym *sym)
|
||||
{
|
||||
add_array (".fini_array", s1, sym);
|
||||
add_array (".fini_array", s1, sym, SHT_FINI_ARRAY);
|
||||
}
|
||||
|
||||
/* add tcc runtime libraries */
|
||||
@ -1336,7 +1356,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, "bcheck.o");
|
||||
tcc_add_support(s1, TCC_LIBBCHECK);
|
||||
}
|
||||
#endif
|
||||
tcc_add_support(s1, TCC_LIBTCC1);
|
||||
@ -2040,6 +2060,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
||||
Section *s;
|
||||
ElfW(Ehdr) ehdr;
|
||||
ElfW(Shdr) shdr, *sh;
|
||||
ElfW(Sym) *sym;
|
||||
|
||||
file_type = s1->output_type;
|
||||
shnum = s1->nb_sections;
|
||||
@ -2110,6 +2131,10 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
||||
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
|
||||
|
||||
sort_syms(s1, symtab_section);
|
||||
if (s1->dynsym)
|
||||
for_each_elem(s1->dynsym, 0, sym, ElfW(Sym))
|
||||
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
||||
s1->dynsym->sh_info++;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
s = s1->sections[sec_order[i]];
|
||||
if (s->sh_type != SHT_NOBITS) {
|
||||
|
140
tccgen.c
140
tccgen.c
@ -110,6 +110,16 @@ ST_DATA struct temp_local_variable {
|
||||
short align;
|
||||
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
||||
short nb_temp_local_vars;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
static short call_nesting;
|
||||
static char used_location[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
||||
static int nb_bound_local_param;
|
||||
struct {
|
||||
unsigned long data_offset;
|
||||
int v;
|
||||
} *bound_local_param;
|
||||
ST_DATA addr_t func_bound_offset;
|
||||
#endif
|
||||
|
||||
static struct scope {
|
||||
struct scope *prev;
|
||||
@ -1383,11 +1393,6 @@ ST_FUNC void save_reg_upstack(int r, int n)
|
||||
bt = VT_PTR;
|
||||
sv.type.t = bt;
|
||||
size = type_size(&sv.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.r = VT_LOCAL | VT_LVAL;
|
||||
sv.c.i = l;
|
||||
@ -1496,7 +1501,11 @@ static int get_temp_local_var(int size,int align){
|
||||
found=0;
|
||||
for(i=0;i<nb_temp_local_vars;i++){
|
||||
temp_var=&arr_temp_local_vars[i];
|
||||
if(temp_var->size<size||align!=temp_var->align){
|
||||
if(temp_var->size<size||align!=temp_var->align
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|| (tcc_state->do_bounds_check && used_location[i])
|
||||
#endif
|
||||
){
|
||||
continue;
|
||||
}
|
||||
/*check if temp_var is free*/
|
||||
@ -1596,6 +1605,50 @@ ST_FUNC void gbound_args(int nb_args)
|
||||
vrott(i);
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void save_temp_local(int nb_args)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (call_nesting++ == 0)
|
||||
for (i = 1; i <= nb_args; ++i)
|
||||
for (j = 0; j < nb_temp_local_vars; j++)
|
||||
if (vtop[1 - i].c.i == arr_temp_local_vars[j].location) {
|
||||
used_location[j] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void restore_temp_local()
|
||||
{
|
||||
if (--call_nesting == 0)
|
||||
memset (used_location, 0, sizeof (used_location));
|
||||
}
|
||||
|
||||
static void add_bound_param(CType *type, int size, int v, int c)
|
||||
{
|
||||
addr_t *bounds_ptr;
|
||||
/* Add arrays/structs/unions because we always take address */
|
||||
int taken = (type->t & VT_ARRAY)
|
||||
|| (type->t & VT_BTYPE) == VT_STRUCT;
|
||||
|
||||
if (taken == 0) {
|
||||
/* Add parameter to check */
|
||||
nb_bound_local_param++;
|
||||
bound_local_param =
|
||||
tcc_realloc (bound_local_param,
|
||||
nb_bound_local_param *
|
||||
sizeof (*bound_local_param));
|
||||
bound_local_param[nb_bound_local_param-1].data_offset =
|
||||
lbounds_section->data_offset;
|
||||
bound_local_param[nb_bound_local_param-1].v = v;
|
||||
}
|
||||
/* add local bound info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section,
|
||||
2 * sizeof(addr_t));
|
||||
bounds_ptr[0] = c;
|
||||
bounds_ptr[1] = taken ? size : ~size;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void incr_bf_adr(int o)
|
||||
@ -3418,6 +3471,7 @@ ST_FUNC void vstore(void)
|
||||
|
||||
vswap();
|
||||
/* source */
|
||||
vtop->r &= ~VT_MUSTBOUND;
|
||||
vpushv(vtop - 2);
|
||||
vtop->type.t = VT_PTR;
|
||||
gaddrof();
|
||||
@ -5083,6 +5137,23 @@ ST_FUNC void unary(void)
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC &&
|
||||
!(vtop->type.t & VT_ARRAY))
|
||||
test_lvalue();
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && vtop->sym) {
|
||||
int i;
|
||||
|
||||
/* Mark parameter as being used for address off */
|
||||
for (i = 0; i < nb_bound_local_param; i++) {
|
||||
if (bound_local_param[i].v == vtop->sym->v) {
|
||||
addr_t *bounds_ptr =
|
||||
(addr_t *) (lbounds_section->data +
|
||||
bound_local_param[i].data_offset);
|
||||
bounds_ptr[1] = ~bounds_ptr[1];
|
||||
bound_local_param[i].v = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mk_pointer(&vtop->type);
|
||||
gaddrof();
|
||||
break;
|
||||
@ -7435,8 +7506,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) ||
|
||||
(type->t & VT_BTYPE) == VT_STRUCT)) {
|
||||
if (bcheck && v) {
|
||||
/* add padding between stack variables */
|
||||
loc--;
|
||||
}
|
||||
#endif
|
||||
@ -7444,17 +7515,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
addr = loc;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* handles bounds */
|
||||
/* XXX: currently, since we do only one pass, we cannot track
|
||||
'&' 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 */
|
||||
if (bcheck && v) {
|
||||
add_bound_param (type, size, v, addr);
|
||||
/* add padding between stack variables */
|
||||
loc--;
|
||||
/* then add local bound info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t));
|
||||
bounds_ptr[0] = addr;
|
||||
bounds_ptr[1] = size;
|
||||
}
|
||||
#endif
|
||||
if (v) {
|
||||
@ -7633,12 +7697,52 @@ static void gen_function(Sym *sym, AttributeDef *ad)
|
||||
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
||||
local_scope = 1; /* for function parameters */
|
||||
gfunc_prolog(sym);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check
|
||||
&& sym->type.ref->f.func_type != FUNC_ELLIPSIS) {
|
||||
Sym *fpar;
|
||||
|
||||
/* Add function arguments in case & is used */
|
||||
for (fpar = sym->type.ref->next; fpar; fpar = fpar->next) {
|
||||
Sym *fsym = sym_find (fpar->v & ~SYM_FIELD);
|
||||
|
||||
if (fsym && (fsym->r & VT_VALMASK) == VT_LOCAL) {
|
||||
int align;
|
||||
int size = type_size(&fsym->type, &align);
|
||||
|
||||
if (size > 0)
|
||||
add_bound_param (&fsym->type, size, fsym->v, fsym->c);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
local_scope = 0;
|
||||
rsym = 0;
|
||||
clear_temp_local_var_list();
|
||||
block(0);
|
||||
gsym(rsym);
|
||||
nocode_wanted = 0;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check) {
|
||||
addr_t o = func_bound_offset;
|
||||
|
||||
/* Remove parameters where address off is not used */
|
||||
while (o != lbounds_section->data_offset) {
|
||||
addr_t *bounds_ptr = (addr_t *) (lbounds_section->data + o);
|
||||
if ((ssize_t) bounds_ptr[1] < 0) {
|
||||
lbounds_section->data_offset -= 2 * sizeof (addr_t);
|
||||
memmove(bounds_ptr, bounds_ptr + 2,
|
||||
lbounds_section->data_offset - o);
|
||||
}
|
||||
else {
|
||||
o += 2 * sizeof (addr_t);
|
||||
}
|
||||
}
|
||||
tcc_free (bound_local_param);
|
||||
nb_bound_local_param = 0;
|
||||
bound_local_param = NULL;
|
||||
}
|
||||
#endif
|
||||
gfunc_epilog();
|
||||
cur_text_section->data_offset = ind;
|
||||
/* reset local stack */
|
||||
|
2
tccpe.c
2
tccpe.c
@ -1897,7 +1897,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
const char **pp, *p;
|
||||
#ifdef TCC_IS_NATIVE
|
||||
if (s1->do_bounds_check)
|
||||
tcc_add_support(s1, "bcheck.o");
|
||||
tcc_add_support(s1, TCC_LIBBCHECK);
|
||||
#endif
|
||||
tcc_add_support(s1, TCC_LIBTCC1);
|
||||
for (pp = libs; 0 != (p = *pp); ++pp) {
|
||||
|
68
tccrun.c
68
tccrun.c
@ -86,6 +86,7 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);
|
||||
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, prx);
|
||||
ptr_diff = (char*)prx - (char*)ptr;
|
||||
close(fd);
|
||||
}
|
||||
#else
|
||||
ptr = tcc_malloc(size);
|
||||
@ -119,6 +120,17 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
/* launch the compiled program with the given arguments */
|
||||
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
{
|
||||
/* PE target overwrites runtime_main */
|
||||
#ifndef TCC_TARGET_PE
|
||||
typedef void (*init_array_func)(int, char **, char **);
|
||||
typedef void (*fini_array_func)(void);
|
||||
init_array_func *__init_array_start;
|
||||
init_array_func *__init_array_end;
|
||||
fini_array_func *__fini_array_start;
|
||||
fini_array_func *__fini_array_end;
|
||||
#endif
|
||||
int i;
|
||||
int ret;
|
||||
int (*prog_main)(int, char **);
|
||||
|
||||
s1->runtime_main = s1->nostdlib ? "_start" : "main";
|
||||
@ -140,31 +152,34 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
errno = 0; /* clean errno value */
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
void (*bound_init)(void);
|
||||
void (*bound_exit)(void);
|
||||
void (*bounds_add_static_var)(size_t *p);
|
||||
size_t *bounds_start;
|
||||
int ret;
|
||||
|
||||
if (s1->do_bounds_check)
|
||||
/* set error function */
|
||||
s1->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");
|
||||
bounds_add_static_var = tcc_get_symbol_err(s1, "__bounds_add_static_var");
|
||||
bounds_start = tcc_get_symbol_err(s1, "__bounds_start");
|
||||
#endif
|
||||
|
||||
bound_init();
|
||||
bounds_add_static_var (bounds_start);
|
||||
#ifndef TCC_TARGET_PE
|
||||
__init_array_start = tcc_get_symbol_err(s1, "__init_array_start");
|
||||
__init_array_end = tcc_get_symbol_err(s1, "__init_array_end");
|
||||
__fini_array_start = tcc_get_symbol_err(s1, "__fini_array_start");
|
||||
__fini_array_end = tcc_get_symbol_err(s1, "__fini_array_end");
|
||||
|
||||
ret = (*prog_main)(argc, argv);
|
||||
|
||||
bound_exit();
|
||||
return ret;
|
||||
if (__init_array_start && __init_array_end) {
|
||||
i = 0;
|
||||
while (&__init_array_start[i] != __init_array_end)
|
||||
(*__init_array_start[i++])(argc, argv, environ);
|
||||
}
|
||||
#endif
|
||||
return (*prog_main)(argc, argv);
|
||||
|
||||
ret = (*prog_main)(argc, argv);
|
||||
|
||||
#ifndef TCC_TARGET_PE
|
||||
if (__fini_array_start && __fini_array_end) {
|
||||
i = 0;
|
||||
while (&__fini_array_end[i] != __fini_array_start)
|
||||
(*__fini_array_end[--i])();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
@ -649,6 +664,9 @@ static void set_exception_handler(void)
|
||||
/* install TCC signal handlers to print debug info on fatal
|
||||
runtime errors */
|
||||
sigact.sa_flags = SA_SIGINFO | SA_RESETHAND;
|
||||
#ifdef SIGSTKSZ
|
||||
sigact.sa_flags |= SA_ONSTACK;
|
||||
#endif
|
||||
sigact.sa_sigaction = sig_error;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGFPE, &sigact, NULL);
|
||||
@ -656,6 +674,18 @@ static void set_exception_handler(void)
|
||||
sigaction(SIGSEGV, &sigact, NULL);
|
||||
sigaction(SIGBUS, &sigact, NULL);
|
||||
sigaction(SIGABRT, &sigact, NULL);
|
||||
#ifdef SIGSTKSZ
|
||||
/* This allows stack overflow to be reported instead of a SEGV */
|
||||
{
|
||||
stack_t ss;
|
||||
static unsigned char stack[SIGSTKSZ] __attribute__((aligned(16)));
|
||||
|
||||
ss.ss_sp = stack;
|
||||
ss.ss_size = SIGSTKSZ;
|
||||
ss.ss_flags = 0;
|
||||
sigaltstack(&ss, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* WIN32 */
|
||||
|
@ -168,7 +168,7 @@ memtest:
|
||||
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 4 8 10 14 16
|
||||
BOUNDS_OK = 1 4 8 10 14 16 18
|
||||
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
|
||||
|
||||
btest: boundtest.c
|
||||
|
@ -230,6 +230,202 @@ int test17()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHECK(s) if (strstr (__bound_error_msg, s) == 0) abort();
|
||||
|
||||
extern void __bound_never_fatal (int neverfatal);
|
||||
extern const char *__bound_error_msg;
|
||||
|
||||
static void init18(char *a, char *b)
|
||||
{
|
||||
memset (a, 'a', 10);
|
||||
a[3] = 0;
|
||||
a[9] = 0;
|
||||
memset (b, 'b', 10);
|
||||
__bound_error_msg = "";
|
||||
}
|
||||
|
||||
/* ok (catch all errors) */
|
||||
int test18()
|
||||
{
|
||||
char pad1[10];
|
||||
char a[10];
|
||||
char pad2[10];
|
||||
char b[10];
|
||||
char pad3[10];
|
||||
|
||||
memset (pad1, 0, sizeof(pad1));
|
||||
memset (pad2, 0, sizeof(pad2));
|
||||
memset (pad3, 0, sizeof(pad3));
|
||||
|
||||
/* -2 in case TCC_BOUNDS_NEVER_FATAL is set */
|
||||
__bound_never_fatal (-2);
|
||||
|
||||
/* memcpy */
|
||||
init18(a,b);
|
||||
memcpy(&a[1],&b[0],10);
|
||||
CHECK("memcpy dest");
|
||||
init18(a,b);
|
||||
memcpy(&a[0],&b[1],10);
|
||||
CHECK("memcpy src");
|
||||
init18(a,b);
|
||||
memcpy(&a[0],&a[3],4);
|
||||
CHECK("overlapping regions");
|
||||
init18(a,b);
|
||||
memcpy(&a[3],&a[0],4);
|
||||
CHECK("overlapping regions");
|
||||
|
||||
/* memcmp */
|
||||
init18(a,b);
|
||||
memcmp(&b[1],&b[0],10);
|
||||
CHECK("memcmp s1");
|
||||
init18(a,b);
|
||||
memcmp(&b[0],&b[1],10);
|
||||
CHECK("memcmp s2");
|
||||
|
||||
/* memmove */
|
||||
init18(a,b);
|
||||
memmove(&b[1],&b[0],10);
|
||||
CHECK("memmove dest");
|
||||
init18(a,b);
|
||||
memmove(&b[0],&b[1],10);
|
||||
CHECK("memmove src");
|
||||
|
||||
/* memset */
|
||||
init18(a,b);
|
||||
memset(&b[1],'b',10);
|
||||
CHECK("memset");
|
||||
|
||||
/* strlen */
|
||||
init18(a,b);
|
||||
strlen(&b[0]);
|
||||
CHECK("strlen");
|
||||
|
||||
/* strcpy */
|
||||
init18(a,b);
|
||||
strcpy(&a[7], &a[0]);
|
||||
CHECK("strcpy dest");
|
||||
init18(a,b);
|
||||
strcpy(&a[0], &b[7]);
|
||||
CHECK("strcpy src");
|
||||
init18(a,b);
|
||||
strcpy(&a[0], &a[1]);
|
||||
CHECK("overlapping regions");
|
||||
init18(a,b);
|
||||
strcpy(&a[2], &a[0]);
|
||||
CHECK("overlapping regions");
|
||||
|
||||
/* strncpy */
|
||||
init18(a,b);
|
||||
strncpy(&a[7], &a[0], 10);
|
||||
CHECK("strncpy dest");
|
||||
init18(a,b);
|
||||
strncpy(&a[0], &b[7], 10);
|
||||
CHECK("strncpy src");
|
||||
init18(a,b);
|
||||
strncpy(&a[0], &a[1], 10);
|
||||
CHECK("overlapping regions");
|
||||
strncpy(&a[2], &a[0], 10);
|
||||
CHECK("overlapping regions");
|
||||
|
||||
/* strcmp */
|
||||
init18(a,b);
|
||||
strcmp(&b[2], &b[0]);
|
||||
CHECK("strcmp s1");
|
||||
init18(a,b);
|
||||
strcmp(&b[0], &b[2]);
|
||||
CHECK("strcmp s2");
|
||||
|
||||
/* strncmp */
|
||||
init18(a,b);
|
||||
strncmp(&b[5], &b[0], 10);
|
||||
CHECK("strncmp s1");
|
||||
init18(a,b);
|
||||
strncmp(&b[0], &b[5], 10);
|
||||
CHECK("strncmp s2");
|
||||
|
||||
/* strcat */
|
||||
init18(a,b);
|
||||
strcat(&a[7], &a[0]);
|
||||
CHECK("strcat dest");
|
||||
init18(a,b);
|
||||
strcat(&a[0], &b[5]);
|
||||
CHECK("strcat src");
|
||||
init18(a,b);
|
||||
strcat(&a[0], &a[4]);
|
||||
CHECK("overlapping regions");
|
||||
init18(a,b);
|
||||
strcat(&a[3], &a[0]);
|
||||
CHECK("overlapping regions");
|
||||
|
||||
/* strchr */
|
||||
init18(a,b);
|
||||
strchr(&b[0], 'a');
|
||||
CHECK("strchr");
|
||||
|
||||
/* strdup */
|
||||
init18(a,b);
|
||||
free(strdup(&b[0]));
|
||||
CHECK("strdup");
|
||||
|
||||
__bound_never_fatal (2);
|
||||
|
||||
/* memcpy */
|
||||
init18(a,b);
|
||||
memcpy(&a[0],&b[0],10);
|
||||
init18(a,b);
|
||||
memcpy(&a[0],&a[3],3);
|
||||
init18(a,b);
|
||||
memcpy(&a[3],&a[0],3);
|
||||
|
||||
/* memcmp */
|
||||
init18(a,b);
|
||||
memcmp(&b[0],&b[0],10);
|
||||
|
||||
/* memmove */
|
||||
init18(a,b);
|
||||
memmove(&b[0],&b[5],5);
|
||||
init18(a,b);
|
||||
memmove(&b[5],&b[0],5);
|
||||
|
||||
/* memset */
|
||||
init18(a,b);
|
||||
memset(&b[0],'b',10);
|
||||
|
||||
/* strlen */
|
||||
init18(a,b);
|
||||
strlen (&a[0]);
|
||||
|
||||
/* strcpy */
|
||||
init18(a,b);
|
||||
strcpy (&a[0], &a[7]);
|
||||
|
||||
/* strncpy */
|
||||
init18(a,b);
|
||||
strncpy (&a[0], &a[7], 4);
|
||||
|
||||
/* strcmp */
|
||||
init18(a,b);
|
||||
strcmp (&a[0], &a[4]);
|
||||
|
||||
/* strncmp */
|
||||
init18(a,b);
|
||||
strncmp (&a[0], &a[4], 10);
|
||||
|
||||
/* strcat */
|
||||
init18(a,b);
|
||||
strcat (&a[0], &a[7]);
|
||||
|
||||
/* strchr */
|
||||
init18(a,b);
|
||||
strchr (&a[0], 0);
|
||||
|
||||
/* strdup */
|
||||
init18(a,b);
|
||||
free (strdup (&a[0]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int (*table_test[])(void) = {
|
||||
test1,
|
||||
test2,
|
||||
@ -248,6 +444,7 @@ int (*table_test[])(void) = {
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
test18,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
17
x86_64-gen.c
17
x86_64-gen.c
@ -637,7 +637,6 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
|
||||
static void gen_bounds_call(int v)
|
||||
@ -784,8 +783,10 @@ void gfunc_call(int nb_args)
|
||||
int arg;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
|
||||
@ -906,6 +907,10 @@ void gfunc_call(int nb_args)
|
||||
|
||||
}
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1271,8 +1276,10 @@ void gfunc_call(int nb_args)
|
||||
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
if (tcc_state->do_bounds_check) {
|
||||
save_temp_local (nb_args);
|
||||
gbound_args(nb_args);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* calculate the number of integer/float register arguments, remember
|
||||
@ -1453,6 +1460,10 @@ void gfunc_call(int nb_args)
|
||||
if (args_size)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
restore_temp_local ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FUNC_PROLOG_SIZE 11
|
||||
|
@ -287,89 +287,4 @@ 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 */
|
||||
|
Loading…
Reference in New Issue
Block a user