aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Makefile2
-rw-r--r--lib/alloca86_64-bt.S60
-rw-r--r--lib/bcheck.c111
-rw-r--r--tcc.h2
-rw-r--r--tccelf.c2
-rw-r--r--tccgen.c19
-rw-r--r--tests/boundtest.c61
-rw-r--r--x86_64-gen.c126
8 files changed, 319 insertions, 64 deletions
diff --git a/lib/Makefile b/lib/Makefile
index aa3984b..348cb72 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/alloca86_64-bt.S b/lib/alloca86_64-bt.S
new file mode 100644
index 0000000..ab8629d
--- /dev/null
+++ b/lib/alloca86_64-bt.S
@@ -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
+/* ---------------------------------------------- */
diff --git a/lib/bcheck.c b/lib/bcheck.c
index 7dcb36e..829e33d 100644
--- a/lib/bcheck.c
+++ b/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;
}
diff --git a/tcc.h b/tcc.h
index d9c24dc..e25a55b 100644
--- a/tcc.h
+++ b/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
diff --git a/tccelf.c b/tccelf.c
index ac91456..98815e5 100644
--- a/tccelf.c
+++ b/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 */
diff --git a/tccgen.c b/tccgen.c
index 3b87d0a..9fab0c8 100644
--- a/tccgen.c
+++ b/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) {
diff --git a/tests/boundtest.c b/tests/boundtest.c
index eb95a96..15bffb4 100644
--- a/tests/boundtest.c
+++ b/tests/boundtest.c
@@ -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,9 +193,44 @@ 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,
test4,
@@ -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();
diff --git a/x86_64-gen.c b/x86_64-gen.c
index d5ed4f6..0083f8b 100644
--- a/x86_64-gen.c
+++ b/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 */