mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
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
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:
parent
6ca228339c
commit
b6a16e3be4
43
arm-gen.c
43
arm-gen.c
@ -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)
|
||||
|
||||
42
arm64-gen.c
42
arm64-gen.c
@ -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.
|
||||
|
||||
17
c67-gen.c
17
c67-gen.c
@ -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);
|
||||
|
||||
32
i386-gen.c
32
i386-gen.c
@ -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
|
||||
|
||||
|
||||
15
il-gen.c
15
il-gen.c
@ -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");
|
||||
}
|
||||
|
||||
@ -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
4
tcc.h
@ -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);
|
||||
|
||||
28
tccgen.c
28
tccgen.c
@ -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);
|
||||
|
||||
2
tccrun.c
2
tccrun.c
@ -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;
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
72
x86_64-gen.c
72
x86_64-gen.c
@ -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 */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user