Save registers around attribute cleanup
Some checks failed
build and test / test-x86_64-linux (push) Has been cancelled
build and test / test-x86_64-osx (push) Has been cancelled
build and test / test-aarch64-osx (push) Has been cancelled
build and test / test-x86-win32 (push) Has been cancelled
build and test / test-armv7-linux (push) Has been cancelled
build and test / test-aarch64-linux (push) Has been cancelled
build and test / test-riscv64-linux (push) Has been cancelled

This makes attribute cleanup code work the same as gcc and also
makes bound checking a very little bit faster.

tcc.h:
  Add save_return_reg(CType *) and restore_return_reg(CType *)
  Change gfunc_epilog() to gfunc_epilog(Sym *)

arm-gen.c:
arm64-gen.c:
c67-gen.c:
i386-gen.c:
il-gen.c:
riscv64-gen.c:
x86_64-gen.c:
  Move save and restore register around bound_local_delete call
  to save_return_reg and restore_return_reg.
  Pass func_type from gfunc_epilog to gen_bounds_epilog.

tccgen.c:
  Call save_return_reg/restore_return_reg in try_call_scope_cleanup
  when RETURN is found.

tccrun.c:
  Fix warning when bound checking not used.

tests/tests2/101_cleanup.c
tests/tests2/101_cleanup.expect
  Extra checks attribute cleanup save/restore registers.

tests/tests2/Makefile:
  Fix when bound checking not used.
This commit is contained in:
herman ten brugge 2025-05-22 16:58:12 +02:00
parent 6ca228339c
commit b6a16e3be4
13 changed files with 346 additions and 59 deletions

View File

@ -837,6 +837,32 @@ static void gcall_or_jmp(int is_jmp)
}
}
ST_FUNC void save_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (ireg)
o(0xe92d0003); /* push {r0,r1} */
if (freg)
o(0xed2d0b04); /* vpush {d0,d1} */
}
ST_FUNC void restore_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (freg)
o(0xecbd0b04); /* vpop {d0,d1} */
if (ireg)
o(0xe8bd0003); /* pop {r0,r1} */
}
#if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v)
@ -860,12 +886,13 @@ static void gen_bounds_prolog(void)
o(0xe1a00000); /* call __bound_local_new */
}
static void gen_bounds_epilog(void)
static void gen_bounds_epilog(Sym *func_sym)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset;
CType *func_type = &func_sym->type.ref->type;
if (!offset_modified && !func_bound_add_epilog)
return;
@ -891,16 +918,16 @@ static void gen_bounds_epilog(void)
}
/* generate bound check local freeing */
o(0xe92d0003); /* push {r0,r1} */
o(0xed2d0b04); /* vpush {d0,d1} */
if (func_type->t != VT_VOID)
save_return_reg(func_type);
o(0xe59f0000); /* ldr r0, [pc] */
o(0xea000000); /* b $+4 */
greloc(cur_text_section, sym_data, ind, R_ARM_REL32);
o(-12); /* lbounds_section->data_offset */
o(0xe080000f); /* add r0,r0,pc */
gen_bounds_call(TOK___bound_local_delete);
o(0xecbd0b04); /* vpop {d0,d1} */
o(0xe8bd0003); /* pop {r0,r1} */
if (func_type->t != VT_VOID)
restore_return_reg(func_type);
}
#endif
@ -1508,15 +1535,17 @@ from_stack:
}
/* generate function epilog */
void gfunc_epilog(void)
void gfunc_epilog(Sym *func_sym)
{
uint32_t x;
int diff;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
/* Copy float return value to core register if base standard is used and
float computation is made with VFP */
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)

View File

@ -674,6 +674,32 @@ static void arm64_gen_bl_or_b(int b)
}
}
ST_FUNC void save_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (ireg)
o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */
if (freg)
o(0xadbf07e0); /* stp q0, q1, [sp, #-32]! */
}
ST_FUNC void restore_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (freg)
o(0xacc107e0); /* ldp q0, q1, [sp], #32 */
if (ireg)
o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */
}
#if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v)
@ -696,12 +722,13 @@ static void gen_bounds_prolog(void)
o(0xd503201f); /* nop -> call __bound_local_new */
}
static void gen_bounds_epilog(void)
static void gen_bounds_epilog(Sym *func_sym)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset;
CType *func_type = &func_sym->type.ref->type;
if (!offset_modified && !func_bound_add_epilog)
return;
@ -726,15 +753,15 @@ static void gen_bounds_epilog(void)
}
/* generate bound check local freeing */
o(0xa9bf07e0); /* stp x0, x1, [sp, #-16]! */
o(0x3c9f0fe0); /* str q0, [sp, #-16]! */
if (func_type->t != VT_VOID)
save_return_reg(func_type);
greloca(cur_text_section, sym_data, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | 0); // adrp x0, #sym_data
greloca(cur_text_section, sym_data, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | 0 | (0 << 5)); // ld x0,[x0, #sym_data]
gen_bounds_call(TOK___bound_local_delete);
o(0x3cc107e0); /* ldr q0, [sp], #16 */
o(0xa8c107e0); /* ldp x0, x1, [sp], #16 */
if (func_type->t != VT_VOID)
restore_return_reg(func_type);
}
#endif
@ -1459,12 +1486,13 @@ ST_FUNC void gfunc_return(CType *func_type)
vtop--;
}
ST_FUNC void gfunc_epilog(void)
ST_FUNC void gfunc_epilog(Sym *func_sym)
{
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
if (loc) {
// Insert instructions to subtract size of stack frame from SP.

View File

@ -2019,9 +2019,22 @@ void gfunc_prolog(Sym *func_sym)
C67_PUSH(C67_B3);
}
/* generate function epilog */
void gfunc_epilog(void)
ST_FUNC void save_return_reg(CType *func_type)
{
func_type = NULL;
// TODO
}
ST_FUNC void restore_return_reg(CType *func_type)
{
func_type = NULL;
// TODO
}
/* generate function epilog */
void gfunc_epilog(Sym *func_sym)
{
func_sym = NULL;
{
int local = (-loc + 7) & -8; // stack must stay aligned to 8 bytes for LDDW instr
C67_POP(C67_B3);

View File

@ -104,7 +104,7 @@ static addr_t func_bound_offset;
static unsigned long func_bound_ind;
ST_DATA int func_bound_add_epilog;
static void gen_bounds_prolog(void);
static void gen_bounds_epilog(void);
static void gen_bounds_epilog(Sym *func_sym);
#endif
/* XXX: make it faster ? */
@ -595,14 +595,15 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
}
/* generate function epilog */
ST_FUNC void gfunc_epilog(void)
ST_FUNC void gfunc_epilog(Sym *func_sym)
{
addr_t v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
/* align local size to word & save local variables */
v = (-loc + 3) & -4;
@ -1040,6 +1041,22 @@ ST_FUNC void ggoto(void)
vtop--;
}
ST_FUNC void save_return_reg(CType *func_type)
{
int ireg = !is_float(func_type->t & VT_BTYPE);
if (ireg)
o(0x5250); /* push %rax; %push %rdx */
}
ST_FUNC void restore_return_reg(CType *func_type)
{
int ireg = !is_float(func_type->t & VT_BTYPE);
if (ireg)
o(0x585a); /* pop %rdx; pop %rax */
}
/* bound check support functions */
#ifdef CONFIG_TCC_BCHECK
@ -1053,12 +1070,13 @@ static void gen_bounds_prolog(void)
oad(0xb8, 0); /* call to function */
}
static void gen_bounds_epilog(void)
static void gen_bounds_epilog(Sym *func_sym)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset;
CType *func_type = &func_sym->type.ref->type;
if (!offset_modified && !func_bound_add_epilog)
return;
@ -1081,11 +1099,13 @@ static void gen_bounds_epilog(void)
}
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
if (func_type->t != VT_VOID)
save_return_reg(func_type);
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
oad(0xb8, 0); /* mov %eax, xxx */
gen_static_call(TOK___bound_local_delete);
o(0x585a); /* restore returned value, if any */
if (func_type->t != VT_VOID)
restore_return_reg(func_type);
}
#endif

View File

@ -457,9 +457,20 @@ void gfunc_prolog(int t)
}
}
/* generate function epilog */
void gfunc_epilog(void)
void save_return_reg(CType *func_type)
{
func_type = NULL;
}
void restore_return_reg(CType *func_type)
{
func_type = NULL;
}
/* generate function epilog */
void gfunc_epilog(Sym *func_sym)
{
func_sym = NULL;
out_op(IL_OP_RET);
fprintf(il_outfile, "}\n\n");
}

View File

@ -436,6 +436,46 @@ static void gcall_or_jmp(int docall)
}
}
ST_FUNC void save_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE) &&
(func_type->t & VT_BTYPE) != VT_LDOUBLE;
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (ireg && freg) {
o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */
o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */
}
else if (ireg) {
o(0xe02a1141); /* addi sp,sp,-16 sd a0,0(sp) */
o(0x0001e42e); /* sd a1,8(sp) nop */
}
else if (freg)
o(0xa02a1141); /* addi sp,sp,-16 fsd fa0,0(sp) */
}
ST_FUNC void restore_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE) &&
(func_type->t & VT_BTYPE) != VT_LDOUBLE;
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (ireg && freg) {
o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */
o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */
}
else if (ireg) {
o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */
o(0x00010141); /* addi sp,sp,16 nop */
}
else if (freg)
o(0x01412502); /* fld fa0,0(sp) addi sp,sp,16 */
}
#if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v)
@ -459,14 +499,14 @@ static void gen_bounds_prolog(void)
o(0x00000013);
}
static void gen_bounds_epilog(void)
static void gen_bounds_epilog(Sym *func_sym)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
Sym label = {0};
int offset_modified = func_bound_offset != lbounds_section->data_offset;
CType *func_type = &func_sym->type.ref->type;
if (!offset_modified && !func_bound_add_epilog)
return;
@ -494,16 +534,16 @@ static void gen_bounds_epilog(void)
}
/* generate bound check local freeing */
o(0xe02a1101); /* addi sp,sp,-32 sd a0,0(sp) */
o(0xa82ae42e); /* sd a1,8(sp) fsd fa0,16(sp) */
if (func_type->t != VT_VOID)
save_return_reg(func_type);
put_extern_sym(&label, cur_text_section, ind, 0);
greloca(cur_text_section, sym_data, ind, R_RISCV_GOT_HI20, 0);
o(0x17 | (10 << 7)); // auipc a0, 0 %pcrel_hi(sym)+addend
greloca(cur_text_section, &label, ind, R_RISCV_PCREL_LO12_I, 0);
EI(0x03, 3, 10, 10, 0); // ld a0, 0(a0)
gen_bounds_call(TOK___bound_local_delete);
o(0x65a26502); /* ld a0,0(sp) ld a1,8(sp) */
o(0x61052542); /* fld fa0,16(sp) addi sp,sp,32 */
if (func_type->t != VT_VOID)
restore_return_reg(func_type);
}
#endif
@ -893,14 +933,15 @@ ST_FUNC void arch_transfer_ret_regs(int aftercall)
vtop--;
}
ST_FUNC void gfunc_epilog(void)
ST_FUNC void gfunc_epilog(Sym *func_sym)
{
int v, saved_ind, d, large_ofs_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
loc = (loc - num_va_regs * 8);
d = v = (-loc + 15) & -16;

4
tcc.h
View File

@ -1607,7 +1607,9 @@ 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(Sym *func_sym);
ST_FUNC void gfunc_epilog(void);
ST_FUNC void gfunc_epilog(Sym *func_sym);
ST_FUNC void save_return_reg(CType *func_type);
ST_FUNC void restore_return_reg(CType *func_type);
ST_FUNC void gen_fill_nops(int);
ST_FUNC int gjmp(int t);
ST_FUNC void gjmp_addr(int a);

View File

@ -6839,10 +6839,14 @@ static void end_switch(void)
/* ------------------------------------------------------------------------- */
/* __attribute__((cleanup(fn))) */
static void try_call_scope_cleanup(Sym *stop)
static void try_call_scope_cleanup(Sym *stop, CType *func_type)
{
Sym *cls = cur_scope->cl.s;
if (cls == stop)
func_type = NULL;
if (func_type && func_type->t != VT_VOID)
save_return_reg(func_type);
for (; cls != stop; cls = cls->next) {
Sym *fs = cls->cleanup_func;
Sym *vs = cls->prev_tok;
@ -6854,6 +6858,8 @@ static void try_call_scope_cleanup(Sym *stop)
gaddrof();
gfunc_call(1);
}
if (func_type && func_type->t != VT_VOID)
restore_return_reg(func_type);
}
static void try_call_cleanup_goto(Sym *cleanupstate)
@ -6873,7 +6879,7 @@ static void try_call_cleanup_goto(Sym *cleanupstate)
for (; cc != oc; cc = cc->next, oc = oc->next, --ccd)
;
try_call_scope_cleanup(cc);
try_call_scope_cleanup(cc, NULL);
}
/* call 'func' for each __attribute__((cleanup(func))) */
@ -6887,7 +6893,7 @@ static void block_cleanup(struct scope *o)
if (!jmp)
jmp = gjmp(0);
gsym(pcl->jnext);
try_call_scope_cleanup(o->cl.s);
try_call_scope_cleanup(o->cl.s, NULL);
pcl->jnext = gjmp(0);
if (!o->cl.n)
goto remove_pending;
@ -6900,7 +6906,7 @@ static void block_cleanup(struct scope *o)
}
}
gsym(jmp);
try_call_scope_cleanup(o->cl.s);
try_call_scope_cleanup(o->cl.s, NULL);
}
/* ------------------------------------------------------------------------- */
@ -6964,11 +6970,11 @@ static void prev_scope(struct scope *o, int is_expr)
}
/* leave a scope via break/continue(/goto) */
static void leave_scope(struct scope *o)
static void leave_scope(struct scope *o, CType *func_type)
{
if (!o)
return;
try_call_scope_cleanup(o->cl.s);
try_call_scope_cleanup(o->cl.s, func_type);
vla_leave(o);
}
@ -7110,9 +7116,9 @@ again:
tcc_warning("'return' with no value");
b = 0;
}
leave_scope(root_scope);
if (b)
gfunc_return(&func_vt);
leave_scope(root_scope, &func_vt);
skip(';');
/* jump unless last stmt in top-level block */
if (tok != '}' || local_scope != 1)
@ -7126,9 +7132,9 @@ again:
if (!cur_scope->bsym)
tcc_error("cannot break");
if (cur_switch && cur_scope->bsym == cur_switch->bsym)
leave_scope(cur_switch->scope);
leave_scope(cur_switch->scope, NULL);
else
leave_scope(loop_scope);
leave_scope(loop_scope, NULL);
*cur_scope->bsym = gjmp(*cur_scope->bsym);
skip(';');
@ -7136,7 +7142,7 @@ again:
/* compute jump */
if (!cur_scope->csym)
tcc_error("cannot continue");
leave_scope(loop_scope);
leave_scope(loop_scope, NULL);
*cur_scope->csym = gjmp(*cur_scope->csym);
skip(';');
@ -8400,7 +8406,7 @@ static void gen_function(Sym *sym)
/* reset local stack */
pop_local_syms(NULL, 0);
tcc_debug_prolog_epilog(tcc_state, 1);
gfunc_epilog();
gfunc_epilog(sym);
/* end of function */
tcc_debug_funcend(tcc_state, ind - func_ind);

View File

@ -495,7 +495,9 @@ static void bt_link(TCCState *s1)
{
#ifdef CONFIG_TCC_BACKTRACE
rt_context *rc;
#ifdef CONFIG_TCC_BCHECK
void *p;
#endif
if (!s1->do_backtrace)
return;

View File

@ -1,9 +1,15 @@
extern int printf(const char*, ...);
static int glob_i = 0;
typedef struct { int a; int b; int c; int d; int e; int f; int g; int h; } tstl;
typedef struct { int a; int b; int c; int d; } tsti;
typedef struct { double a; double b; } tstd;
typedef struct { long double a; } tstld;
void incr_glob_i(int *i)
{
glob_i += *i;
*i = -1;
}
#define INCR_GI { \
@ -71,17 +77,20 @@ void check(int *j)
goto out;
}
}
*j = -1;
return;
}
void check_oh_i(char *oh_i)
{
printf("c: %c\n", *oh_i);
*oh_i = '0';
}
void goto_hell(double *f)
{
printf("oo: %f\n", *f);
*f = -1.0;
}
char *test()
@ -152,6 +161,7 @@ int test3(void) {
void cl(int *ip)
{
printf("%d\n", *ip);
*ip = -1;
}
void loop_cleanups(void)
@ -191,11 +201,72 @@ void loop_cleanups(void)
printf("after break\n");
}
void my_cleanup1(int *p) {
printf("%d\n", *p);
*p = 0x90;
}
int test_cleanup1(void) {
int __attribute__((cleanup(my_cleanup1))) n = 42;
return n;
}
void my_cleanup2(tstl *p) {
printf("%d %d %d %d %d %d %d %d\n", p->a, p->b, p->c, p->d,
p->e, p->f, p->g, p->h);
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
p->e = 0x94; p->f = 0x95; p->g = 0x96; p->h = 0x97;
}
tstl test_cleanup2(void) {
tstl __attribute__((cleanup(my_cleanup2))) n;
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
n.e = 46; n.f = 47; n.g = 48; n.h = 49;
return n;
}
void my_cleanup3(tsti *p) {
printf("%d %d %d %d\n", p->a, p->b, p->c, p->d);
p->a = 0x90; p->b = 0x91; p->c = 0x92; p->d = 0x93;
}
tsti test_cleanup3(void) {
tsti __attribute__((cleanup(my_cleanup3))) n;
n.a = 42; n.b = 43; n.c = 44; n.d = 45;
return n;
}
void my_cleanup4(tstd *p) {
printf("%g %g\n", p->a, p->b);
p->a = 90.0; p->b = 91.0;
}
tstd test_cleanup4(void) {
tstd __attribute__((cleanup(my_cleanup4))) n;
n.a = 42.0; n.b = 43.0;
return n;
}
void my_cleanup5(tstld *p) {
printf("%Lf\n", p->a);
p->a = 90.0;
}
tstld test_cleanup5(void) {
tstld __attribute__((cleanup(my_cleanup5))) n;
n.a = 42.0;
return n;
}
int main()
{
int i __attribute__ ((__cleanup__(check))) = 0, not_i;
int chk = 0;
(void)not_i;
tstl tl;
tsti ti;
tstd td;
tstld tld;
{
__attribute__ ((__cleanup__(check_oh_i))) char oh_i = 'o', o = 'a';
@ -218,10 +289,21 @@ int main()
test2();
test3();
loop_cleanups();
printf("%d\n", test_cleanup1());
tl = test_cleanup2();
printf("%d %d %d %d %d %d %d %d\n", tl.a, tl.b, tl.c, tl.d,
tl.e, tl.f, tl.g, tl.h);
ti = test_cleanup3();
printf("%d %d %d %d\n", ti.a, ti.b, ti.c, ti.d);
td = test_cleanup4();
printf("%g %g\n", td.a, td.b);
tld = test_cleanup5();
printf("%Lf\n", tld.a);
return i;
}
void check2(char **hum)
{
printf("str: %s\n", *hum);
*hum = "fail";
}

View File

@ -48,6 +48,16 @@ str: three
400
after break
1000
42
42
42 43 44 45 46 47 48 49
42 43 44 45 46 47 48 49
42 43 44 45
42 43 44 45
42 43
42 43
42.000000
42.000000
---- 0
---- 1
str: plop

View File

@ -31,6 +31,7 @@ ifeq ($(CONFIG_bcheck),no)
SKIP += 116_bound_setjmp2.test
SKIP += 117_builtins.test
SKIP += 126_bound_global.test
SKIP += 132_bound_test.test
endif
ifeq ($(CONFIG_dll),no)
SKIP += 113_btdll.test # no shared lib support yet

View File

@ -655,6 +655,50 @@ static void gcall_or_jmp(int is_jmp)
}
}
ST_FUNC void save_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (ireg)
o(0x5250); /* push %rax; %push %rdx */
if (freg) {
if ((func_type->t & VT_BTYPE) == VT_LDOUBLE ||
(func_type->t & VT_BTYPE) == VT_STRUCT) {
o(0x10ec8348); /* sub $16,%rsp */
o(0x243cdb); /* fstpt (%rsp) */
}
o(0x20ec8348); /* sub $32,%rsp */
o(0x290f); /* movaps %xmm0,0x10(%rsp) */
o(0x102444);
o(0x240c290f); /* movaps %xmm1,(%rsp) */
}
}
ST_FUNC void restore_return_reg(CType *func_type)
{
int freg = is_float(func_type->t & VT_BTYPE);
int ireg = !freg;
if ((func_type->t & VT_BTYPE) == VT_STRUCT)
ireg = freg = 1;
if (freg) {
o(0x280f); /* movaps 0x10(%rsp),%xmm0 */
o(0x102444);
o(0x240c280f); /* movaps (%rsp),%xmm1 */
o(0x20c48348); /* add $32,%rsp */
if ((func_type->t & VT_BTYPE) == VT_LDOUBLE ||
(func_type->t & VT_BTYPE) == VT_STRUCT) {
o(0x242cdb); /* fldt (%rsp) */
o(0x10c48348); /* add $16,%rsp */
}
}
if (ireg)
o(0x585a); /* pop %rdx; pop %rax */
}
#if defined(CONFIG_TCC_BCHECK)
static void gen_bounds_call(int v)
@ -681,12 +725,13 @@ static void gen_bounds_prolog(void)
oad(0xb8, 0); /* call to function */
}
static void gen_bounds_epilog(void)
static void gen_bounds_epilog(Sym *func_sym)
{
addr_t saved_ind;
addr_t *bounds_ptr;
Sym *sym_data;
int offset_modified = func_bound_offset != lbounds_section->data_offset;
CType *func_type = &func_sym->type.ref->type;
if (!offset_modified && !func_bound_add_epilog)
return;
@ -709,20 +754,14 @@ static void gen_bounds_epilog(void)
}
/* generate bound check local freeing */
o(0x5250); /* save returned value, if any */
o(0x20ec8348); /* sub $32,%rsp */
o(0x290f); /* movaps %xmm0,0x10(%rsp) */
o(0x102444);
o(0x240c290f); /* movaps %xmm1,(%rsp) */
if (func_type->t != VT_VOID)
save_return_reg(func_type);
greloca(cur_text_section, sym_data, ind + 3, R_X86_64_PC32, -4);
o(0x0d8d48 + ((TREG_FASTCALL_1 == TREG_RDI) * 0x300000)); /* lea xxx(%rip), %rcx/rdi */
gen_le32 (0);
gen_bounds_call(TOK___bound_local_delete);
o(0x280f); /* movaps 0x10(%rsp),%xmm0 */
o(0x102444);
o(0x240c280f); /* movaps (%rsp),%xmm1 */
o(0x20c48348); /* add $32,%rsp */
o(0x585a); /* restore returned value, if any */
if (func_type->t != VT_VOID)
restore_return_reg(func_type);
}
#endif
@ -1005,7 +1044,7 @@ void gfunc_prolog(Sym *func_sym)
}
/* generate function epilog */
void gfunc_epilog(void)
void gfunc_epilog(Sym *func_sym)
{
int v, start;
@ -1015,8 +1054,9 @@ void gfunc_epilog(void)
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
o(0xc9); /* leave */
if (func_ret_sub == 0) {
@ -1600,14 +1640,16 @@ void gfunc_prolog(Sym *func_sym)
}
/* generate function epilog */
void gfunc_epilog(void)
void gfunc_epilog(Sym *func_sym)
{
int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
gen_bounds_epilog();
gen_bounds_epilog(func_sym);
#endif
func_sym = NULL;
o(0xc9); /* leave */
if (func_ret_sub == 0) {
o(0xc3); /* ret */