mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-13 05:10:07 +08:00
a bounds checking code for the ARCH=x86_64
This commit is contained in:
parent
e92dc595cd
commit
559675b90a
@ -44,7 +44,7 @@ native : TCC = $(TOP)/tcc$(EXESUF)
|
||||
cross : TCC = $(TOP)/$(TARGET)-tcc$(EXESUF)
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BCHECK_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BCHECK_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o
|
||||
WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
|
||||
|
60
lib/alloca86_64-bt.S
Normal file
60
lib/alloca86_64-bt.S
Normal file
@ -0,0 +1,60 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86_64.S */
|
||||
|
||||
.globl __bound_alloca
|
||||
__bound_alloca:
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
# bound checking is not implemented
|
||||
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
|
||||
add $32,%rax
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
#else
|
||||
pop %rdx
|
||||
mov %rdi,%rax
|
||||
movl %rax,%rsi # size, a second parm to the __bound_new_region
|
||||
|
||||
add $15,%rax
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
|
||||
mov %rsp,%rax
|
||||
|
||||
push %rdx
|
||||
push %rax
|
||||
call __bound_new_region
|
||||
pop %rax
|
||||
pop %rdx
|
||||
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
#endif
|
||||
|
||||
/* mark stack as nonexecutable */
|
||||
#if defined __ELF__ && defined __linux__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
/* ---------------------------------------------- */
|
111
lib/bcheck.c
111
lib/bcheck.c
@ -31,6 +31,12 @@
|
||||
|
||||
/* #define BOUND_DEBUG */
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
#define dprintf(a...) fprintf(a)
|
||||
#else
|
||||
#define dprintf(a...)
|
||||
#endif
|
||||
|
||||
/* define so that bound array is static (faster, but use memory if
|
||||
bound checking not used) */
|
||||
/* #define BOUND_STATIC */
|
||||
@ -50,12 +56,12 @@
|
||||
|
||||
#define BOUND_T1_BITS 13
|
||||
#define BOUND_T2_BITS 11
|
||||
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
|
||||
#define BOUND_T3_BITS (sizeof(size_t)*8 - BOUND_T1_BITS - BOUND_T2_BITS)
|
||||
#define BOUND_E_BITS (sizeof(size_t))
|
||||
|
||||
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
|
||||
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
|
||||
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
|
||||
#define BOUND_E_BITS 4
|
||||
|
||||
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
|
||||
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
|
||||
@ -64,7 +70,7 @@
|
||||
/* this pointer is generated when bound check is incorrect */
|
||||
#define INVALID_POINTER ((void *)(-2))
|
||||
/* size of an empty region */
|
||||
#define EMPTY_SIZE 0xffffffff
|
||||
#define EMPTY_SIZE ((size_t)(-1))
|
||||
/* size of an invalid region */
|
||||
#define INVALID_SIZE 0
|
||||
|
||||
@ -168,9 +174,7 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset)
|
||||
|
||||
__bound_init();
|
||||
|
||||
#if defined(BOUND_DEBUG)
|
||||
printf("%s %s: 0x%x %d\n", __FILE__, __FUNCTION__, (int)p, offset);
|
||||
#endif
|
||||
dprintf(stderr, "%s %s: %p %p\n", __FILE__, __FUNCTION__, p, offset);
|
||||
|
||||
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
|
||||
e = (BoundEntry *)((char *)e +
|
||||
@ -197,6 +201,8 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
||||
size_t addr = (size_t)p; \
|
||||
BoundEntry *e; \
|
||||
\
|
||||
dprintf(stderr, "%s %s: %p %p start\n", __FILE__, __FUNCTION__, p, offset); \
|
||||
\
|
||||
__bound_init(); \
|
||||
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
|
||||
e = (BoundEntry *)((char *)e + \
|
||||
@ -212,6 +218,7 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
||||
fprintf(stderr,"%s %s: %p is outside of the region\n", __FILE__, __FUNCTION__, p + offset); \
|
||||
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||
} \
|
||||
dprintf(stderr, "%s %s: return p+offset = %p\n", __FILE__, __FUNCTION__, p + offset); \
|
||||
return p + offset; \
|
||||
}
|
||||
|
||||
@ -232,9 +239,8 @@ BOUND_PTR_INDIR(16)
|
||||
void FASTCALL __bound_local_new(void *p1)
|
||||
{
|
||||
size_t addr, size, fp, *p = p1;
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s start p1=%p *p1=%p\n", __FILE__, __FUNCTION__, p, *p);
|
||||
#endif
|
||||
|
||||
dprintf(stderr, "%s, %s start p1=%p\n", __FILE__, __FUNCTION__, p);
|
||||
GET_CALLER_FP(fp);
|
||||
for(;;) {
|
||||
addr = p[0];
|
||||
@ -245,9 +251,7 @@ void FASTCALL __bound_local_new(void *p1)
|
||||
p += 2;
|
||||
__bound_new_region((void *)addr, size);
|
||||
}
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
/* called when leaving a function to delete all the local regions */
|
||||
@ -268,7 +272,7 @@ void FASTCALL __bound_local_delete(void *p1)
|
||||
static BoundEntry *__bound_new_page(void)
|
||||
{
|
||||
BoundEntry *page;
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
|
||||
if (!page)
|
||||
@ -296,11 +300,11 @@ static void bound_free_entry(BoundEntry *e)
|
||||
libc_free(e);
|
||||
}
|
||||
|
||||
static inline BoundEntry *get_page(int index)
|
||||
static BoundEntry *get_page(size_t index)
|
||||
{
|
||||
BoundEntry *page;
|
||||
page = __bound_t1[index];
|
||||
if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
|
||||
if (!page || page == __bound_empty_t2 || page == __bound_invalid_t2) {
|
||||
/* create a new page if necessary */
|
||||
page = __bound_new_page();
|
||||
__bound_t1[index] = page;
|
||||
@ -325,7 +329,7 @@ static void mark_invalid(size_t addr, size_t size)
|
||||
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
|
||||
|
||||
#if 0
|
||||
printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
|
||||
dprintf(stderr, "mark_invalid: start = %x %x\n", t2_start, t2_end);
|
||||
#endif
|
||||
|
||||
/* first we handle full pages */
|
||||
@ -364,7 +368,7 @@ static void mark_invalid(size_t addr, size_t size)
|
||||
|
||||
void __bound_init(void)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
BoundEntry *page;
|
||||
size_t start, size;
|
||||
size_t *p;
|
||||
@ -375,9 +379,7 @@ void __bound_init(void)
|
||||
|
||||
inited = 1;
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
dprintf(stderr, "%s, %s() start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
/* save malloc hooks and install bound check hooks */
|
||||
install_malloc_hooks();
|
||||
@ -445,19 +447,18 @@ void __bound_init(void)
|
||||
__bound_new_region((void *)p[0], p[1]);
|
||||
p += 2;
|
||||
}
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
|
||||
dprintf(stderr, "%s, %s() end\n\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
void __bound_main_arg(void **p)
|
||||
{
|
||||
void *start = p;
|
||||
while (*p++);
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
__FILE__, __FUNCTION__, (void *) p - start);
|
||||
#endif
|
||||
|
||||
__bound_new_region(start, (void *) p - start);
|
||||
}
|
||||
|
||||
@ -495,10 +496,8 @@ void __bound_new_region(void *p, size_t size)
|
||||
|
||||
__bound_init();
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s(%p, %p) start\n",
|
||||
dprintf(stderr, "%s, %s(%p, %p) start\n",
|
||||
__FILE__, __FUNCTION__, p, size);
|
||||
#endif
|
||||
|
||||
start = (size_t)p;
|
||||
end = start + size;
|
||||
@ -553,9 +552,8 @@ void __bound_new_region(void *p, size_t size)
|
||||
}
|
||||
add_region(e, start, size);
|
||||
}
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
|
||||
dprintf(stderr, "%s, %s end\n", __FILE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
/* delete a region */
|
||||
@ -610,9 +608,7 @@ int __bound_delete_region(void *p)
|
||||
|
||||
__bound_init();
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
dprintf(stderr, "%s %s() start\n", __FILE__, __FUNCTION__);
|
||||
|
||||
start = (size_t)p;
|
||||
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||
@ -681,9 +677,7 @@ int __bound_delete_region(void *p)
|
||||
delete_region(e, p, empty_size);
|
||||
}
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
|
||||
#endif
|
||||
dprintf(stderr, "%s %s() end\n", __FILE__, __FUNCTION__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -771,10 +765,9 @@ void *__bound_malloc(size_t size, const void *caller)
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
__FILE__, __FUNCTION__, ptr, size);
|
||||
#endif
|
||||
|
||||
__bound_new_region(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
@ -805,10 +798,9 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
#ifdef BOUND_DEBUG
|
||||
fprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
dprintf(stderr, "%s, %s calling __bound_new_region(%p, %p)\n",
|
||||
__FILE__, __FUNCTION__, ptr, size);
|
||||
#endif
|
||||
|
||||
__bound_new_region(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
@ -861,23 +853,23 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
static void bound_dump(void)
|
||||
{
|
||||
BoundEntry *page, *e;
|
||||
int i, j;
|
||||
size_t i, j;
|
||||
|
||||
printf("region dump:\n");
|
||||
fprintf(stderr, "region dump:\n");
|
||||
for(i=0;i<BOUND_T1_SIZE;i++) {
|
||||
page = __bound_t1[i];
|
||||
for(j=0;j<BOUND_T2_SIZE;j++) {
|
||||
e = page + j;
|
||||
/* do not print invalid or empty entries */
|
||||
if (e->size != EMPTY_SIZE && e->start != 0) {
|
||||
printf("%08x:",
|
||||
fprintf(stderr, "%08x:",
|
||||
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
|
||||
(j << BOUND_T3_BITS));
|
||||
do {
|
||||
printf(" %08lx:%08lx", e->start, e->start + e->size);
|
||||
fprintf(stderr, " %08lx:%08lx", e->start, e->start + e->size);
|
||||
e = e->next;
|
||||
} while (e != NULL);
|
||||
printf("\n");
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -891,19 +883,27 @@ static void __bound_check(const void *p, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
p = __bound_ptr_add((void *)p, size);
|
||||
p = __bound_ptr_add((void *)p, size - 1);
|
||||
if (p == INVALID_POINTER)
|
||||
bound_error("invalid pointer");
|
||||
}
|
||||
|
||||
void *__bound_memcpy(void *dst, const void *src, size_t size)
|
||||
{
|
||||
void* p;
|
||||
|
||||
dprintf(stderr, "%s %s: start, dst=%p src=%p size=%p\n", __FILE__, __FUNCTION__, dst, src, size);
|
||||
|
||||
__bound_check(dst, size);
|
||||
__bound_check(src, size);
|
||||
/* check also region overlap */
|
||||
if (src >= dst && src < dst + size)
|
||||
bound_error("overlapping regions in memcpy()");
|
||||
return memcpy(dst, src, size);
|
||||
|
||||
p = memcpy(dst, src, size);
|
||||
|
||||
dprintf(stderr, "%s %s: end, p=%p\n", __FILE__, __FUNCTION__, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *__bound_memmove(void *dst, const void *src, size_t size)
|
||||
@ -939,7 +939,12 @@ int __bound_strlen(const char *s)
|
||||
|
||||
char *__bound_strcpy(char *dst, const char *src)
|
||||
{
|
||||
int len;
|
||||
size_t len;
|
||||
void *p;
|
||||
|
||||
dprintf(stderr, "%s %s: strcpy start, dst=%p src=%p\n", __FILE__, __FUNCTION__, dst, src);
|
||||
len = __bound_strlen(src);
|
||||
return __bound_memcpy(dst, src, len + 1);
|
||||
p = __bound_memcpy(dst, src, len + 1);
|
||||
dprintf(stderr, "%s %s: strcpy end, p=%p\n", __FILE__, __FUNCTION__, dst, src, p);
|
||||
return p;
|
||||
}
|
||||
|
2
tcc.h
2
tcc.h
@ -164,7 +164,7 @@
|
||||
|
||||
#if !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
|
||||
!defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_C67) && \
|
||||
!defined(TCC_TARGET_X86_64) && !defined(CONFIG_USE_LIBGCC)
|
||||
!defined(CONFIG_USE_LIBGCC)
|
||||
#define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||
#endif
|
||||
|
||||
|
2
tccelf.c
2
tccelf.c
@ -1579,7 +1579,6 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
add_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
bounds_section->sh_num, "__bounds_start");
|
||||
#ifdef TCC_TARGET_I386
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
|
||||
@ -1601,7 +1600,6 @@ ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
tcc_warning("__bound_init not defined");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* add tcc runtime libraries */
|
||||
|
19
tccgen.c
19
tccgen.c
@ -708,7 +708,7 @@ static void gbound(void)
|
||||
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
|
||||
/* must save type because we must set it to int to get pointer */
|
||||
type1 = vtop->type;
|
||||
vtop->type.t = VT_INT;
|
||||
vtop->type.t = VT_PTR;
|
||||
gaddrof();
|
||||
vpushi(0);
|
||||
gen_bounded_ptr_add();
|
||||
@ -1752,7 +1752,22 @@ ST_FUNC void gen_op(int op)
|
||||
#endif
|
||||
}
|
||||
gen_op('*');
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
#if 0
|
||||
/* #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
|
||||
*/
|
||||
/* if evaluating constant expression, no code should be
|
||||
generated, so no bound check */
|
||||
if (tcc_state->do_bounds_check && !const_wanted) {
|
||||
|
@ -50,12 +50,15 @@ int test4(void)
|
||||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<20;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -65,12 +68,15 @@ int test5(void)
|
||||
int i, sum = 0;
|
||||
int *tab4;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
tab4 = malloc(20 * sizeof(int));
|
||||
for(i=0;i<21;i++) {
|
||||
sum += tab4[i];
|
||||
}
|
||||
free(tab4);
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
return sum;
|
||||
}
|
||||
|
||||
@ -187,8 +193,43 @@ int test15(void)
|
||||
return strlen(p);
|
||||
}
|
||||
|
||||
/* ok */
|
||||
int test16()
|
||||
{
|
||||
char *demo = "This is only a test.";
|
||||
char *p;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
printf("alloca: p is %s\n", p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
/* error */
|
||||
int test17()
|
||||
{
|
||||
char *demo = "This is only a test.";
|
||||
char *p;
|
||||
|
||||
fprintf(stderr, "%s start\n", __FUNCTION__);
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
printf("alloca: p is %s\n", p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca: %s\n", strcpy(alloca(strlen(demo)),demo) );
|
||||
|
||||
fprintf(stderr, "%s end\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
int (*table_test[])(void) = {
|
||||
test1,
|
||||
test1,
|
||||
test2,
|
||||
test3,
|
||||
@ -204,23 +245,33 @@ int (*table_test[])(void) = {
|
||||
test13,
|
||||
test14,
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int index;
|
||||
int (*ftest)(void);
|
||||
int index_max = sizeof(table_test)/sizeof(table_test[0]);
|
||||
|
||||
if (argc < 2) {
|
||||
printf("usage: boundtest n\n"
|
||||
"test TCC bound checking system\n"
|
||||
);
|
||||
printf(
|
||||
"test TCC bound checking system\n"
|
||||
"usage: boundtest N\n"
|
||||
" 1 <= N <= %d\n", index_max);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
if (argc >= 2)
|
||||
index = atoi(argv[1]);
|
||||
index = atoi(argv[1]) - 1;
|
||||
|
||||
if ((index < 0) || (index >= index_max)) {
|
||||
printf("N is outside of the valid range (%d)\n", index);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* well, we also use bounds on this ! */
|
||||
ftest = table_test[index];
|
||||
ftest();
|
||||
|
126
x86_64-gen.c
126
x86_64-gen.c
@ -625,6 +625,90 @@ 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)
|
||||
{
|
||||
Sym *sym = external_global_sym(v, &func_old_type, 0);
|
||||
oad(0xe8, -4);
|
||||
greloc(cur_text_section, sym, ind-4, R_X86_64_PC32);
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
/* save all temporary registers */
|
||||
save_regs(0);
|
||||
|
||||
/* prepare fast x86_64 function call */
|
||||
gv(RC_RAX);
|
||||
o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size
|
||||
vtop--;
|
||||
|
||||
gv(RC_RAX);
|
||||
o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr
|
||||
vtop--;
|
||||
|
||||
/* do a fast function call */
|
||||
gen_static_call(TOK___bound_ptr_add);
|
||||
|
||||
/* returned pointer is in rax */
|
||||
vtop++;
|
||||
vtop->r = TREG_RAX | VT_BOUNDED;
|
||||
|
||||
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.ull = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela)));
|
||||
}
|
||||
|
||||
/* patch pointer addition in vtop so that pointer dereferencing is
|
||||
also tested */
|
||||
ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
{
|
||||
addr_t func;
|
||||
int size, align;
|
||||
ElfW(Rela) *rel;
|
||||
Sym *sym;
|
||||
|
||||
size = 0;
|
||||
/* XXX: put that code in generic part of tcc */
|
||||
if (!is_float(vtop->type.t)) {
|
||||
if (vtop->r & VT_LVAL_BYTE)
|
||||
size = 1;
|
||||
else if (vtop->r & VT_LVAL_SHORT)
|
||||
size = 2;
|
||||
}
|
||||
if (!size)
|
||||
size = type_size(&vtop->type, &align);
|
||||
switch(size) {
|
||||
case 1: func = TOK___bound_ptr_indir1; break;
|
||||
case 2: func = TOK___bound_ptr_indir2; break;
|
||||
case 4: func = TOK___bound_ptr_indir4; break;
|
||||
case 8: func = TOK___bound_ptr_indir8; break;
|
||||
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;
|
||||
}
|
||||
|
||||
sym = external_global_sym(func, &func_old_type, 0);
|
||||
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.ull);
|
||||
rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
||||
#define REGN 4
|
||||
@ -1520,6 +1604,17 @@ void gfunc_prolog(CType *func_type)
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
}
|
||||
|
||||
#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;
|
||||
oad(0xb8, 0); /* lbound section pointer */
|
||||
o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */
|
||||
oad(0xb8, 0); /* call to function */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* generate function epilog */
|
||||
@ -1527,6 +1622,37 @@ 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;
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
ind = ind + 5 + 3;
|
||||
gen_static_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0x5250); /* save returned value, if any */
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
oad(0xb8, 0); /* mov xxx, %rax */
|
||||
o(0xc78948); /* mov %rax,%rdi ## first arg in %rdi, this must be ptr */
|
||||
gen_static_call(TOK___bound_local_delete);
|
||||
o(0x585a); /* restore returned value, if any */
|
||||
}
|
||||
#endif
|
||||
o(0xc9); /* leave */
|
||||
if (func_ret_sub == 0) {
|
||||
o(0xc3); /* ret */
|
||||
|
Loading…
Reference in New Issue
Block a user