mirror of
https://github.com/mirror/tinycc.git
synced 2024-12-26 03:50:07 +08:00
Add bound checking to arm, arm64 and riscv64
Checked on: - i386/x86_64 (linux/windows) - arm/arm64 (rapberry pi) - riscv64 (simulator) Not tested for arm softfloat because raspberry pi does not support it. Modifications: Makefile: add arm-asm.c to arm64_FILES add riscv64-asm.c (new file) to riscv64_FILES lib/Makefile: add fetch_and_add_arm.o(new file) to ARM_O add fetch_and_add_arm64.o(new file) to ARM64_O add fetch_and_add_riscv64.o(new file) to RISCV64_O add $(BCHECK_O) to OBJ-arm/OBJ-arm64/OBJ-riscv64 tcc.h: Enable CONFIG_TCC_BCHECK for arm32/arm64/riscv64 Add arm-asm.c, riscv64-asm.c tcctok.h: for arm use memmove4 instead of memcpy4 for arm use memmove8 instead of memcpy8 tccgen.c: put_extern_sym2: for arm check memcpy/memmove/memset/memmove4/memmove8 only use alloca for i386/x86_64 for arm use memmove4 instead of memcpy4 for arm use memmove8 instead of memcpy8 fix builtin_frame_address/builtin_return_address for arm/riscv64 tccrun.c: Add riscv64 support fix rt_getcontext/rt_get_caller_pc for arm tccelf.c: tcc_load_dll: Print filename for bad architecture libtcc.c: add arm-asm.c/riscv64-asm.c tcc-doc.texi: Add arm, arm64, riscv64 support for bound checking lib/bcheck.c: add __bound___aeabi_memcpy/__bound___aeabi_memmove __bound___aeabi_memmove4/__bound___aeabi_memmove8 __bound___aeabi_memset for arm call fetch_and_add_arm/fetch_and_add_arm64/fetch_and_add_riscv64 __bound_init: Fix type for start/end/ad __bound_malloc/__bound_memalign/__bound_realloc/__bound_calloc: Use size + 1 arm-gen.c: add bound checking code like i386/x86_64 assign_regs: only malloc if nb_args != 0 gen_opi/gen_opf: Fix reload problems arm-link.c: relocate_plt: Fix address calculating arm64-gen.c: add bound checking code like i386/x86_64 load/store: remove VT_BOUNDED from sv->r arm64_hfa_aux/arm64_hfa_aux: Fix array code gfunc_prolog: only malloc if n != 0 arm64-link.c: code_reloc/gotplt_entry_type/relocate: add R_AARCH64_LDST64_ABS_LO12_NC relocate: Use addXXle instead of writeXXle riscv64-gen.c: add bound checking code like i386/x86_64 add NB_ASM_REGS/CONFIG_TCC_ASM riscv64-link.c: relocate: Use addXXle instead of writeXXle i386-gen.c/x86_64-gen.c gen_bounds_epilog: Fix code (unrelated) tests/Makefile: add $(BTESTS) for arm/arm64/riscv64 tests/tests2/Makefile: Use 85 only on i386/x86_64 because of asm code Use 113 only on i386/x86_64 because of DLL code Add 112/114/115/116 for arm/arm64/riscv64 Fix FILTER (failed on riscv64) tests/boundtest.c: Only use alloca for i386/x86_64
This commit is contained in:
parent
9eef33993a
commit
0b8ee7364a
4
Makefile
4
Makefile
@ -176,9 +176,9 @@ arm-fpa-ld_FILES = $(arm_FILES)
|
||||
arm-vfp_FILES = $(arm_FILES)
|
||||
arm-eabi_FILES = $(arm_FILES)
|
||||
arm-eabihf_FILES = $(arm_FILES)
|
||||
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
|
||||
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm-asm.c
|
||||
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
|
||||
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c
|
||||
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c riscv64-asm.c
|
||||
|
||||
# libtcc sources
|
||||
LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
|
||||
|
218
arm-gen.c
218
arm-gen.c
@ -158,6 +158,12 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
||||
static int func_sub_sp_offset, last_itod_magic;
|
||||
static int leaffunc;
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
static int func_bound_add_epilog;
|
||||
#endif
|
||||
|
||||
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
|
||||
static CType float_type, double_type, func_float_type, func_double_type;
|
||||
ST_FUNC void arm_init(struct TCCState *s)
|
||||
@ -193,11 +199,17 @@ ST_FUNC void arm_init(struct TCCState *s)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR)
|
||||
|
||||
static int two2mask(int a,int b) {
|
||||
if (!CHECK_R(a) || !CHECK_R(b))
|
||||
tcc_error("compiler error! registers %i,%i is not valid",a,b);
|
||||
return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
|
||||
}
|
||||
|
||||
static int regmask(int r) {
|
||||
if (!CHECK_R(r))
|
||||
tcc_error("compiler error! register %i is not valid",r);
|
||||
return reg_classes[r]&~(RC_INT|RC_FLOAT);
|
||||
}
|
||||
|
||||
@ -751,6 +763,14 @@ static void gcall_or_jmp(int is_jmp)
|
||||
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
|
||||
o(vtop->c.i);
|
||||
}
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check &&
|
||||
(vtop->sym->v == TOK_setjmp ||
|
||||
vtop->sym->v == TOK__setjmp ||
|
||||
vtop->sym->v == TOK_sigsetjmp ||
|
||||
vtop->sym->v == TOK___sigsetjmp))
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
}else{
|
||||
if(!is_jmp)
|
||||
o(0xE28FE004); // add lr,pc,#4
|
||||
@ -759,6 +779,9 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
} else {
|
||||
/* otherwise, indirect call */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
vtop->r &= ~VT_MUSTBOUND;
|
||||
#endif
|
||||
r = gv(RC_INT);
|
||||
if(!is_jmp)
|
||||
o(0xE1A0E00F); // mov lr,pc
|
||||
@ -766,6 +789,121 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
|
||||
static void gen_bounds_call(int v)
|
||||
{
|
||||
Sym *sym = external_global_sym(v, &func_old_type);
|
||||
|
||||
greloc(cur_text_section, sym, ind, R_ARM_PC24);
|
||||
o(0xebfffffe);
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in REG_IRET */
|
||||
vtop->r = REG_IRET | VT_BOUNDED;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
Elf32_Rel *rel;
|
||||
Sym *sym;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
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:
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
|
||||
}
|
||||
|
||||
static void gen_bounds_prolog(void)
|
||||
{
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_add_epilog = 0;
|
||||
o(0xe1a00000); /* ld r0,lbounds_section->data_offset */
|
||||
o(0xe1a00000);
|
||||
o(0xe1a00000);
|
||||
o(0xe1a00000); /* call __bound_local_new */
|
||||
}
|
||||
|
||||
static void gen_bounds_epilog(void)
|
||||
{
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
int offset_modified = func_bound_offset != lbounds_section->data_offset;
|
||||
|
||||
if (!offset_modified && !func_bound_add_epilog)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
o(0xe59f0000); /* ldr r0, [pc] */
|
||||
o(0xea000000); /* b $+4 */
|
||||
greloc(cur_text_section, sym_data, ind, R_ARM_ABS32);
|
||||
o(0x00000000); /* lbounds_section->data_offset */
|
||||
gen_bounds_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
}
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0xe92d0003); /* push {r0,r1} */
|
||||
o(0xed2d0b02); /* vpush {d0} */
|
||||
o(0xe59f0000); /* ldr r0, [pc] */
|
||||
o(0xea000000); /* b $+4 */
|
||||
greloc(cur_text_section, sym_data, ind, R_ARM_ABS32);
|
||||
o(0x00000000); /* lbounds_section->data_offset */
|
||||
gen_bounds_call(TOK___bound_local_delete);
|
||||
o(0xecbd0b02); /* vpop {d0} */
|
||||
o(0xe8bd0003); /* pop {r0,r1} */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int unalias_ldbl(int btype)
|
||||
{
|
||||
#if LDOUBLE_SIZE == 8
|
||||
@ -956,7 +1094,7 @@ static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
|
||||
|
||||
ncrn = nsaa = 0;
|
||||
*todo = 0;
|
||||
plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans));
|
||||
plan->pplans = nb_args ? tcc_malloc(nb_args * sizeof(*plan->pplans)) : NULL;
|
||||
memset(plan->clsplans, 0, sizeof(plan->clsplans));
|
||||
for(i = nb_args; i-- ;) {
|
||||
int j, start_vfpreg = 0;
|
||||
@ -1215,10 +1353,16 @@ void gfunc_call(int nb_args)
|
||||
int def_float_abi = float_abi;
|
||||
int todo;
|
||||
struct plan plan;
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
int variadic;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
if (float_abi == ARM_HARD_FLOAT) {
|
||||
variadic = (vtop[-nb_args].type.ref->f.func_type == FUNC_ELLIPSIS);
|
||||
if (variadic || floats_in_core_regs(&vtop[-nb_args]))
|
||||
@ -1367,6 +1511,10 @@ from_stack:
|
||||
last_itod_magic=0;
|
||||
leaffunc = 1;
|
||||
loc = 0;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_prolog();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* generate function epilog */
|
||||
@ -1374,6 +1522,11 @@ void gfunc_epilog(void)
|
||||
{
|
||||
uint32_t x;
|
||||
int diff;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_epilog();
|
||||
#endif
|
||||
/* 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)
|
||||
@ -1582,10 +1735,10 @@ void gen_opi(int op)
|
||||
vswap();
|
||||
c=intr(gv(RC_INT));
|
||||
vswap();
|
||||
opc=0xE0000000|(opc<<20)|(c<<16);
|
||||
opc=0xE0000000|(opc<<20);
|
||||
if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
|
||||
uint32_t x;
|
||||
x=stuff_const(opc|0x2000000,vtop->c.i);
|
||||
x=stuff_const(opc|0x2000000|(c<<16),vtop->c.i);
|
||||
if(x) {
|
||||
r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
|
||||
o(x|(r<<12));
|
||||
@ -1593,8 +1746,13 @@ void gen_opi(int op)
|
||||
}
|
||||
}
|
||||
fr=intr(gv(RC_INT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
c=intr(gv(RC_INT));
|
||||
vswap();
|
||||
}
|
||||
r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
|
||||
o(opc|(r<<12)|fr);
|
||||
o(opc|(c<<16)|(r<<12)|fr);
|
||||
done:
|
||||
vtop--;
|
||||
if (op >= TOK_ULT && op <= TOK_GT)
|
||||
@ -1608,15 +1766,19 @@ done:
|
||||
vswap();
|
||||
r=intr(gv(RC_INT));
|
||||
vswap();
|
||||
opc|=r;
|
||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
|
||||
fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
|
||||
c = vtop->c.i & 0x1f;
|
||||
o(opc|(c<<7)|(fr<<12));
|
||||
o(opc|r|(c<<7)|(fr<<12));
|
||||
} else {
|
||||
fr=intr(gv(RC_INT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=intr(gv(RC_INT));
|
||||
vswap();
|
||||
}
|
||||
c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
|
||||
o(opc|(c<<12)|(fr<<8)|0x10);
|
||||
o(opc|r|(c<<12)|(fr<<8)|0x10);
|
||||
}
|
||||
vtop--;
|
||||
break;
|
||||
@ -1701,9 +1863,9 @@ void gen_opf(int op)
|
||||
vtop--;
|
||||
o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
|
||||
} else {
|
||||
x|=vfpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
o(x|(vfpr(gv(RC_FLOAT))<<12));
|
||||
gv2(RC_FLOAT,RC_FLOAT);
|
||||
x|=vfpr(vtop[0].r);
|
||||
o(x|(vfpr(vtop[-1].r) << 12));
|
||||
vtop--;
|
||||
}
|
||||
o(0xEEF1FA10); /* fmstat */
|
||||
@ -1726,6 +1888,12 @@ void gen_opf(int op)
|
||||
r2=gv(RC_FLOAT);
|
||||
x|=vfpr(r2)<<16;
|
||||
r|=regmask(r2);
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=gv(RC_FLOAT);
|
||||
vswap();
|
||||
x=(x&~0xf)|vfpr(r);
|
||||
}
|
||||
}
|
||||
vtop->r=get_reg_ex(RC_FLOAT,r);
|
||||
if(!fneg)
|
||||
@ -1808,6 +1976,11 @@ void gen_opf(int op)
|
||||
r2=c2&0xf;
|
||||
} else {
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
@ -1829,6 +2002,11 @@ void gen_opf(int op)
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
@ -1841,8 +2019,14 @@ void gen_opf(int op)
|
||||
vswap();
|
||||
if(c2 && c2<=0xf)
|
||||
r2=c2;
|
||||
else
|
||||
else {
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
}
|
||||
}
|
||||
x|=0x100000; // muf
|
||||
break;
|
||||
case '/':
|
||||
@ -1863,6 +2047,11 @@ void gen_opf(int op)
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1915,6 +2104,11 @@ void gen_opf(int op)
|
||||
r2=c2&0xf;
|
||||
} else {
|
||||
r2=fpr(gv(RC_FLOAT));
|
||||
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) {
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
}
|
||||
}
|
||||
--vtop;
|
||||
vset_VT_CMP(op);
|
||||
|
@ -155,7 +155,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
while (p < p_end) {
|
||||
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
|
||||
p += 4;
|
||||
add32le(p + 12, x + s1->plt->data - p);
|
||||
add32le(p + 12, x + (s1->plt->data - p));
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
|
171
arm64-gen.c
171
arm64-gen.c
@ -81,6 +81,12 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
||||
RC_FLOAT | RC_F(7)
|
||||
};
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
static int func_bound_add_epilog;
|
||||
#endif
|
||||
|
||||
#define IS_FREG(x) ((x) >= TREG_F(0))
|
||||
|
||||
static uint32_t intr(int r)
|
||||
@ -454,7 +460,7 @@ static void arm64_load_cmp(int r, SValue *sv);
|
||||
ST_FUNC void load(int r, SValue *sv)
|
||||
{
|
||||
int svtt = sv->type.t;
|
||||
int svr = sv->r;
|
||||
int svr = sv->r & ~VT_BOUNDED;
|
||||
int svrv = svr & VT_VALMASK;
|
||||
uint64_t svcul = (uint32_t)sv->c.i;
|
||||
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
|
||||
@ -554,7 +560,7 @@ ST_FUNC void load(int r, SValue *sv)
|
||||
ST_FUNC void store(int r, SValue *sv)
|
||||
{
|
||||
int svtt = sv->type.t;
|
||||
int svr = sv->r;
|
||||
int svr = sv->r & ~VT_BOUNDED;
|
||||
int svrv = svr & VT_VALMASK;
|
||||
uint64_t svcul = (uint32_t)sv->c.i;
|
||||
svcul = svcul >> 31 & 1 ? svcul - ((uint64_t)1 << 32) : svcul;
|
||||
@ -594,11 +600,147 @@ static void arm64_gen_bl_or_b(int b)
|
||||
assert(!b);
|
||||
greloca(cur_text_section, vtop->sym, ind, R_AARCH64_CALL26, 0);
|
||||
o(0x94000000); // bl .
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check &&
|
||||
(vtop->sym->v == TOK_setjmp ||
|
||||
vtop->sym->v == TOK__setjmp ||
|
||||
vtop->sym->v == TOK_sigsetjmp ||
|
||||
vtop->sym->v == TOK___sigsetjmp))
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else {
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
vtop->r &= ~VT_MUSTBOUND;
|
||||
#endif
|
||||
o(0xd61f0000 | (uint32_t)!b << 21 | intr(gv(RC_R30)) << 5); // br/blr
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
|
||||
static void gen_bounds_call(int v)
|
||||
{
|
||||
Sym *sym = external_global_sym(v, &func_old_type);
|
||||
|
||||
greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0);
|
||||
o(0x94000000); // bl
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in REG_IRET */
|
||||
vtop->r = REG_IRET | VT_BOUNDED;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (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;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
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:
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
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.i);
|
||||
rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
|
||||
}
|
||||
|
||||
static void gen_bounds_prolog(void)
|
||||
{
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_add_epilog = 0;
|
||||
o(0xd503201f); /* nop -> mov x0,#0,lsl #0, lbound section pointer */
|
||||
o(0xd503201f);
|
||||
o(0xd503201f);
|
||||
o(0xd503201f);
|
||||
o(0xd503201f); /* nop -> call __bound_local_new */
|
||||
}
|
||||
|
||||
static void gen_bounds_epilog(void)
|
||||
{
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
int offset_modified = func_bound_offset != lbounds_section->data_offset;
|
||||
|
||||
if (!offset_modified && !func_bound_add_epilog)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G0_NC, 0);
|
||||
o(0xd2800000); /* mov x0,#0,lsl #0, lbound section pointer */
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G1_NC, 0);
|
||||
o(0xf2a00000); /* movk x0,#0,lsl #16 */
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G2_NC, 0);
|
||||
o(0xf2c00000); /* movk x0,#0,lsl #32 */
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G3, 0);
|
||||
o(0xf2e00000); /* movk x0,#0,lsl #48 */
|
||||
gen_bounds_call(TOK___bound_local_new);
|
||||
ind = saved_ind;
|
||||
}
|
||||
|
||||
/* generate bound check local freeing */
|
||||
o(0xf81f0fe0); /* str x0, [sp, #-16]! */
|
||||
o(0x3c9f0fe0); /* str q0, [sp, #-16]! */
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G0_NC, 0);
|
||||
o(0xd2800000); // mov x0,#0,lsl #0
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G1_NC, 0);
|
||||
o(0xf2a00000); // movk x0,#0,lsl #16
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G2_NC, 0);
|
||||
o(0xf2c00000); // movk x0,#0,lsl #32
|
||||
greloca(cur_text_section, sym_data, ind, R_AARCH64_MOVW_UABS_G3, 0);
|
||||
o(0xf2e00000); // movk x0,#0,lsl #48
|
||||
gen_bounds_call(TOK___bound_local_delete);
|
||||
o(0x3cc107e0); /* ldr q0, [sp], #16 */
|
||||
o(0xf84107e0); /* ldr x0, [sp], #16 */
|
||||
}
|
||||
#endif
|
||||
|
||||
static int arm64_hfa_aux(CType *type, int *fsize, int num)
|
||||
{
|
||||
if (is_float(type->t)) {
|
||||
@ -642,7 +784,7 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
|
||||
return num;
|
||||
}
|
||||
}
|
||||
else if (type->t & VT_ARRAY) {
|
||||
else if ((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR)) {
|
||||
int num1;
|
||||
if (!type->ref->c)
|
||||
return num;
|
||||
@ -659,7 +801,8 @@ static int arm64_hfa_aux(CType *type, int *fsize, int num)
|
||||
|
||||
static int arm64_hfa(CType *type, int *fsize)
|
||||
{
|
||||
if ((type->t & VT_BTYPE) == VT_STRUCT || (type->t & VT_ARRAY)) {
|
||||
if ((type->t & VT_BTYPE) == VT_STRUCT ||
|
||||
((type->t & VT_ARRAY) && ((type->t & VT_BTYPE) != VT_PTR))) {
|
||||
int sz = 0;
|
||||
int n = arm64_hfa_aux(type, &sz, 0);
|
||||
if (0 < n && n <= 4) {
|
||||
@ -839,6 +982,11 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
unsigned long stack;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
return_type = &vtop[-nb_args].type.ref->type;
|
||||
if ((return_type->t & VT_BTYPE) == VT_STRUCT)
|
||||
--nb_args;
|
||||
@ -1014,8 +1162,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
|
||||
for (sym = func_type->ref; sym; sym = sym->next)
|
||||
++n;
|
||||
t = tcc_malloc(n * sizeof(*t));
|
||||
a = tcc_malloc(n * sizeof(*a));
|
||||
t = n ? tcc_malloc(n * sizeof(*t)) : NULL;
|
||||
a = n ? tcc_malloc(n * sizeof(*a)) : NULL;
|
||||
|
||||
for (sym = func_type->ref; sym; sym = sym->next)
|
||||
t[i++] = &sym->type;
|
||||
@ -1076,6 +1224,10 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
o(0xd503201f); // nop
|
||||
o(0xd503201f); // nop
|
||||
loc = 0;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_prolog();
|
||||
#endif
|
||||
}
|
||||
|
||||
ST_FUNC void gen_va_start(void)
|
||||
@ -1246,6 +1398,11 @@ ST_FUNC void gfunc_return(CType *func_type)
|
||||
|
||||
ST_FUNC void gfunc_epilog(void)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_epilog();
|
||||
#endif
|
||||
|
||||
if (loc) {
|
||||
// Insert instructions to subtract size of stack frame from SP.
|
||||
unsigned char *ptr = cur_text_section->data + arm64_func_sub_sp_offset;
|
||||
|
10
arm64-link.c
10
arm64-link.c
@ -37,6 +37,7 @@ int code_reloc (int reloc_type)
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_COPY:
|
||||
return 0;
|
||||
@ -62,6 +63,7 @@ int gotplt_entry_type (int reloc_type)
|
||||
case R_AARCH64_MOVW_UABS_G3:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_JUMP_SLOT:
|
||||
case R_AARCH64_COPY:
|
||||
@ -157,10 +159,10 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
||||
|
||||
switch(type) {
|
||||
case R_AARCH64_ABS64:
|
||||
write64le(ptr, val);
|
||||
add64le(ptr, val);
|
||||
return;
|
||||
case R_AARCH64_ABS32:
|
||||
write32le(ptr, val);
|
||||
add32le(ptr, val);
|
||||
return;
|
||||
case R_AARCH64_PREL32:
|
||||
write32le(ptr, val - addr);
|
||||
@ -193,6 +195,10 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
||||
(val & 0xfff) << 10));
|
||||
return;
|
||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
||||
(val & 0xff8) << 7));
|
||||
return;
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_CALL26:
|
||||
#ifdef DEBUG_RELOC
|
||||
|
@ -1089,8 +1089,9 @@ static void gen_bounds_epilog(void)
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
int offset_modified = func_bound_offset != lbounds_section->data_offset;
|
||||
|
||||
if (func_bound_offset == lbounds_section->data_offset && !func_bound_add_epilog)
|
||||
if (!offset_modified && !func_bound_add_epilog)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
@ -1101,7 +1102,7 @@ static void gen_bounds_epilog(void)
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (func_bound_offset != lbounds_section->data_offset) {
|
||||
if (offset_modified) {
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
greloc(cur_text_section, sym_data, ind + 1, R_386_32);
|
||||
|
12
lib/Makefile
12
lib/Makefile
@ -43,9 +43,9 @@ endif
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o $(BT_O)
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o $(BT_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o $(BT_O)
|
||||
ARM64_O = lib-arm64.o $(BT_O)
|
||||
RISCV64_O = lib-arm64.o $(BT_O)
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o fetch_and_add_arm.o $(BT_O)
|
||||
ARM64_O = lib-arm64.o fetch_and_add_arm64.o $(BT_O)
|
||||
RISCV64_O = lib-arm64.o fetch_and_add_riscv64.o $(BT_O)
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
|
||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||
@ -53,15 +53,15 @@ OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(B_O) $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
||||
OBJ-arm = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(BCHECK_O) $(DSO_O)
|
||||
OBJ-arm = $(ARM_O) $(BCHECK_O) $(DSO_O)
|
||||
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-fpa-ld = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-vfp = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-eabi = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) $(BCHECK_O) $(DSO_O)
|
||||
|
||||
OBJ-extra = $(filter $(B_O),$(OBJ-$T))
|
||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||
|
97
lib/bcheck.c
97
lib/bcheck.c
@ -163,7 +163,7 @@ typedef struct alloca_list_struct {
|
||||
#if defined(_WIN32)
|
||||
#define BOUND_TID_TYPE DWORD
|
||||
#define BOUND_GET_TID GetCurrentThreadId()
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__riscv)
|
||||
#define BOUND_TID_TYPE pid_t
|
||||
#define BOUND_GET_TID syscall (SYS_gettid)
|
||||
#else
|
||||
@ -223,6 +223,19 @@ DLL_EXPORT char *__bound_strcat(char *dest, const char *src);
|
||||
DLL_EXPORT char *__bound_strchr(const char *string, int ch);
|
||||
DLL_EXPORT char *__bound_strdup(const char *s);
|
||||
|
||||
#if defined(__arm__)
|
||||
DLL_EXPORT void *__bound___aeabi_memcpy(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__bound___aeabi_memmove(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__bound___aeabi_memmove4(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__bound___aeabi_memmove8(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__bound___aeabi_memset(void *dst, int c, size_t size);
|
||||
DLL_EXPORT void *__aeabi_memcpy(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__aeabi_memmove(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__aeabi_memmove4(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__aeabi_memmove8(void *dst, const void *src, size_t size);
|
||||
DLL_EXPORT void *__aeabi_memset(void *dst, int c, size_t size);
|
||||
#endif
|
||||
|
||||
#if MALLOC_REDIR
|
||||
#define BOUND_MALLOC(a) malloc_redir(a)
|
||||
#define BOUND_MEMALIGN(a,b) memalign_redir(a,b)
|
||||
@ -320,6 +333,15 @@ static void fetch_and_add(signed char* variable, signed char value)
|
||||
: // No input-only
|
||||
: "memory"
|
||||
);
|
||||
#elif defined __arm__
|
||||
extern fetch_and_add_arm(signed char* variable, signed char value);
|
||||
fetch_and_add_arm(variable, value);
|
||||
#elif defined __aarch64__
|
||||
extern fetch_and_add_arm64(signed char* variable, signed char value);
|
||||
fetch_and_add_arm64(variable, value);
|
||||
#elif defined __riscv
|
||||
extern fetch_and_add_riscv64(signed char* variable, signed char value);
|
||||
fetch_and_add_riscv64(variable, value);
|
||||
#else
|
||||
*variable += value;
|
||||
#endif
|
||||
@ -814,10 +836,10 @@ void __bound_init(size_t *p)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char found;
|
||||
unsigned long long start;
|
||||
unsigned long long end;
|
||||
unsigned long long ad =
|
||||
(unsigned long long) __builtin_return_address(0);
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
unsigned long ad =
|
||||
(unsigned long) __builtin_return_address(0);
|
||||
char line[1000];
|
||||
|
||||
/* Display exec name. Usefull when a lot of code is compiled with tcc */
|
||||
@ -835,7 +857,7 @@ void __bound_init(size_t *p)
|
||||
fp = fopen ("/proc/self/maps", "r");
|
||||
if (fp) {
|
||||
while (fgets (line, sizeof(line), fp)) {
|
||||
if (sscanf (line, "%Lx-%Lx", &start, &end) == 2 &&
|
||||
if (sscanf (line, "%lx-%lx", &start, &end) == 2 &&
|
||||
ad >= start && ad < end) {
|
||||
found = 1;
|
||||
break;
|
||||
@ -1099,7 +1121,7 @@ void *__bound_malloc(size_t size, const void *caller)
|
||||
INCR_COUNT(bound_malloc_count);
|
||||
|
||||
if (ptr) {
|
||||
tree = splay_insert ((size_t) ptr, size, tree);
|
||||
tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
|
||||
if (tree && tree->start == (size_t) ptr)
|
||||
tree->type = TCC_TYPE_MALLOC;
|
||||
}
|
||||
@ -1138,7 +1160,7 @@ void *__bound_memalign(size_t size, size_t align, const void *caller)
|
||||
INCR_COUNT(bound_memalign_count);
|
||||
|
||||
if (ptr) {
|
||||
tree = splay_insert((size_t) ptr, size, tree);
|
||||
tree = splay_insert((size_t) ptr, size ? size : size + 1, tree);
|
||||
if (tree && tree->start == (size_t) ptr)
|
||||
tree->type = TCC_TYPE_MEMALIGN;
|
||||
}
|
||||
@ -1205,7 +1227,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_ptr = BOUND_REALLOC (ptr, size);
|
||||
new_ptr = BOUND_REALLOC (ptr, size + 1);
|
||||
dprintf(stderr, "%s, %s(): %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, new_ptr, (unsigned long)size);
|
||||
|
||||
@ -1216,7 +1238,7 @@ void *__bound_realloc(void *ptr, size_t size, const void *caller)
|
||||
if (ptr)
|
||||
tree = splay_delete ((size_t) ptr, tree);
|
||||
if (new_ptr) {
|
||||
tree = splay_insert ((size_t) new_ptr, size, tree);
|
||||
tree = splay_insert ((size_t) new_ptr, size ? size : size + 1, tree);
|
||||
if (tree && tree->start == (size_t) new_ptr)
|
||||
tree->type = TCC_TYPE_REALLOC;
|
||||
}
|
||||
@ -1259,7 +1281,7 @@ void *__bound_calloc(size_t nmemb, size_t size)
|
||||
if (no_checking == 0) {
|
||||
WAIT_SEM ();
|
||||
INCR_COUNT(bound_calloc_count);
|
||||
tree = splay_insert ((size_t) ptr, size, tree);
|
||||
tree = splay_insert ((size_t) ptr, size ? size : size + 1, tree);
|
||||
if (tree && tree->start == (size_t) ptr)
|
||||
tree->type = TCC_TYPE_CALLOC;
|
||||
POST_SEM ();
|
||||
@ -1387,6 +1409,59 @@ void *__bound_memset(void *s, int c, size_t n)
|
||||
return memset(s, c, n);
|
||||
}
|
||||
|
||||
#if defined(__arm__)
|
||||
void *__bound___aeabi_memcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, dest, src, (unsigned long)n);
|
||||
INCR_COUNT(bound_mempcy_count);
|
||||
__bound_check(dest, n, "memcpy dest");
|
||||
__bound_check(src, n, "memcpy src");
|
||||
if (check_overlap(dest, n, src, n, "memcpy"))
|
||||
return dest;
|
||||
return __aeabi_memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
void *__bound___aeabi_memmove(void *dest, const void *src, size_t n)
|
||||
{
|
||||
dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, dest, src, (unsigned long)n);
|
||||
INCR_COUNT(bound_memmove_count);
|
||||
__bound_check(dest, n, "memmove dest");
|
||||
__bound_check(src, n, "memmove src");
|
||||
return __aeabi_memmove(dest, src, n);
|
||||
}
|
||||
|
||||
void *__bound___aeabi_memmove4(void *dest, const void *src, size_t n)
|
||||
{
|
||||
dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, dest, src, (unsigned long)n);
|
||||
INCR_COUNT(bound_memmove_count);
|
||||
__bound_check(dest, n, "memmove dest");
|
||||
__bound_check(src, n, "memmove src");
|
||||
return __aeabi_memmove4(dest, src, n);
|
||||
}
|
||||
|
||||
void *__bound___aeabi_memmove8(void *dest, const void *src, size_t n)
|
||||
{
|
||||
dprintf(stderr, "%s, %s(): %p, %p, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, dest, src, (unsigned long)n);
|
||||
INCR_COUNT(bound_memmove_count);
|
||||
__bound_check(dest, n, "memmove dest");
|
||||
__bound_check(src, n, "memmove src");
|
||||
return __aeabi_memmove8(dest, src, n);
|
||||
}
|
||||
|
||||
void *__bound___aeabi_memset(void *s, int c, size_t n)
|
||||
{
|
||||
dprintf(stderr, "%s, %s(): %p, %d, 0x%lx\n",
|
||||
__FILE__, __FUNCTION__, s, c, (unsigned long)n);
|
||||
INCR_COUNT(bound_memset_count);
|
||||
__bound_check(s, n, "memset");
|
||||
return __aeabi_memset(s, c, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
int __bound_strlen(const char *s)
|
||||
{
|
||||
const char *p = s;
|
||||
|
16
lib/fetch_and_add_arm.S
Normal file
16
lib/fetch_and_add_arm.S
Normal file
@ -0,0 +1,16 @@
|
||||
.text
|
||||
.align 2
|
||||
.global fetch_and_add_arm
|
||||
.type fetch_and_add_arm, %function
|
||||
fetch_and_add_arm:
|
||||
.int 0xee070fba # mcr 15, 0, r0, cr7, cr10, {5}
|
||||
.int 0xe1903f9f # ldrex r3, [r0]
|
||||
.int 0xe2833001 # add r3, r3, #1
|
||||
.int 0xe1802f93 # strex r2, r3, [r0]
|
||||
.int 0xe3520000 # cmp r2, #0
|
||||
.int 0x1afffffa # bne 4 <fetch_and_add_arm+0x4>
|
||||
.int 0xee070fba # mcr 15, 0, r0, cr7, cr10, {5}
|
||||
.int 0xe1a00003 # mov r0, r3
|
||||
.int 0xe12fff1e # bx lr
|
||||
|
||||
.size fetch_and_add_arm, .-fetch_and_add_arm
|
14
lib/fetch_and_add_arm64.S
Normal file
14
lib/fetch_and_add_arm64.S
Normal file
@ -0,0 +1,14 @@
|
||||
.text
|
||||
.align 2
|
||||
.global fetch_and_add_arm64
|
||||
.type fetch_and_add_arm64, %function
|
||||
fetch_and_add_arm64:
|
||||
.int 0x885f7c01 # ldxr w1, [x0]
|
||||
.int 0x11000421 # add w1, w1, #0x1
|
||||
.int 0x8802fc01 # stlxr w2, w1, [x0]
|
||||
.int 0x35ffffa2 # cbnz w2, 0 <fetch_and_add_arm64>
|
||||
.int 0xd5033bbf # dmb ish
|
||||
.int 0x2a0103e0 # mov w0, w1
|
||||
.int 0xd65f03c0 # ret
|
||||
|
||||
.size fetch_and_add_arm64, .-fetch_and_add_arm64
|
12
lib/fetch_and_add_riscv64.S
Normal file
12
lib/fetch_and_add_riscv64.S
Normal file
@ -0,0 +1,12 @@
|
||||
.text
|
||||
.align 2
|
||||
.global fetch_and_add_riscv64
|
||||
.type fetch_and_add_riscv64, %function
|
||||
fetch_and_add_riscv64:
|
||||
.short 0x4705 # li a4,1
|
||||
.int 0x0f50000f # fence iorw,ow
|
||||
.int 0x04e527af # amoadd.w.aq a5,a4,(a0)
|
||||
.int 0x0017851b # addiw a0,a5,1
|
||||
.short 0x8082 # ret
|
||||
|
||||
.size fetch_and_add_riscv64, .-fetch_and_add_riscv64
|
2
libtcc.c
2
libtcc.c
@ -34,6 +34,7 @@
|
||||
#elif defined(TCC_TARGET_ARM64)
|
||||
#include "arm64-gen.c"
|
||||
#include "arm64-link.c"
|
||||
#include "arm-asm.c"
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
#include "c67-gen.c"
|
||||
#include "c67-link.c"
|
||||
@ -45,6 +46,7 @@
|
||||
#elif defined(TCC_TARGET_RISCV64)
|
||||
#include "riscv64-gen.c"
|
||||
#include "riscv64-link.c"
|
||||
#include "riscv64-asm.c"
|
||||
#else
|
||||
#error unknown target
|
||||
#endif
|
||||
|
94
riscv64-asm.c
Normal file
94
riscv64-asm.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*************************************************************/
|
||||
/*
|
||||
* RISCV64 dummy assembler for TCC
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef TARGET_DEFS_ONLY
|
||||
|
||||
#define CONFIG_TCC_ASM
|
||||
#define NB_ASM_REGS 32
|
||||
|
||||
ST_FUNC void g(int c);
|
||||
ST_FUNC void gen_le16(int c);
|
||||
ST_FUNC void gen_le32(int c);
|
||||
|
||||
/*************************************************************/
|
||||
#else
|
||||
/*************************************************************/
|
||||
#define USING_GLOBALS
|
||||
#include "tcc.h"
|
||||
|
||||
static void asm_error(void)
|
||||
{
|
||||
tcc_error("RISCV64 asm not implemented.");
|
||||
}
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
ST_FUNC void g(int c)
|
||||
{
|
||||
int ind1;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
ind1 = ind + 1;
|
||||
if (ind1 > cur_text_section->data_allocated)
|
||||
section_realloc(cur_text_section, ind1);
|
||||
cur_text_section->data[ind] = c;
|
||||
ind = ind1;
|
||||
}
|
||||
|
||||
ST_FUNC void gen_le16 (int i)
|
||||
{
|
||||
g(i);
|
||||
g(i>>8);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_le32 (int i)
|
||||
{
|
||||
gen_le16(i);
|
||||
gen_le16(i>>16);
|
||||
}
|
||||
|
||||
ST_FUNC void gen_expr32(ExprValue *pe)
|
||||
{
|
||||
gen_le32(pe->v);
|
||||
}
|
||||
|
||||
ST_FUNC void asm_opcode(TCCState *s1, int opcode)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
/* generate prolog and epilog code for asm statement */
|
||||
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
int nb_outputs, int is_output,
|
||||
uint8_t *clobber_regs,
|
||||
int out_reg)
|
||||
{
|
||||
}
|
||||
|
||||
ST_FUNC void asm_compute_constraints(ASMOperand *operands,
|
||||
int nb_operands, int nb_outputs,
|
||||
const uint8_t *clobber_regs,
|
||||
int *pout_reg)
|
||||
{
|
||||
}
|
||||
|
||||
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
|
||||
{
|
||||
asm_error();
|
||||
}
|
||||
|
||||
ST_FUNC int asm_parse_regvar (int t)
|
||||
{
|
||||
asm_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
#endif /* ndef TARGET_DEFS_ONLY */
|
155
riscv64-gen.c
155
riscv64-gen.c
@ -2,6 +2,8 @@
|
||||
|
||||
// Number of registers available to allocator:
|
||||
#define NB_REGS 19 // x10-x17 aka a0-a7, f10-f17 aka fa0-fa7, xxx, ra, sp
|
||||
#define NB_ASM_REGS 32
|
||||
#define CONFIG_TCC_ASM
|
||||
|
||||
#define TREG_R(x) (x) // x = 0..7
|
||||
#define TREG_F(x) (x + 8) // x = 0..7
|
||||
@ -61,6 +63,12 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
||||
1 << TREG_SP
|
||||
};
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
static addr_t func_bound_offset;
|
||||
static unsigned long func_bound_ind;
|
||||
static int func_bound_add_epilog;
|
||||
#endif
|
||||
|
||||
static int ireg(int r)
|
||||
{
|
||||
if (r == TREG_RA)
|
||||
@ -377,6 +385,14 @@ static void gcall_or_jmp(int docall)
|
||||
R_RISCV_CALL_PLT, (int)vtop->c.i);
|
||||
o(0x17 | (tr << 7)); // auipc TR, 0 %call(func)
|
||||
EI(0x67, 0, tr, tr, 0);// jalr TR, r(TR)
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check &&
|
||||
(vtop->sym->v == TOK_setjmp ||
|
||||
vtop->sym->v == TOK__setjmp ||
|
||||
vtop->sym->v == TOK_sigsetjmp ||
|
||||
vtop->sym->v == TOK___sigsetjmp))
|
||||
func_bound_add_epilog = 1;
|
||||
#endif
|
||||
} else if (vtop->r < VT_CONST) {
|
||||
int r = ireg(vtop->r);
|
||||
EI(0x67, 0, tr, r, 0); // jalr TR, 0(R)
|
||||
@ -388,6 +404,130 @@ static void gcall_or_jmp(int docall)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TCC_BCHECK)
|
||||
|
||||
static void gen_bounds_call(int v)
|
||||
{
|
||||
Sym *sym = external_global_sym(v, &func_old_type);
|
||||
|
||||
greloca(cur_text_section, sym, ind, R_RISCV_CALL_PLT, 0);
|
||||
o(0x17 | (1 << 7)); // auipc TR, 0 %call(func)
|
||||
EI(0x67, 0, 1, 1, 0); // jalr TR, r(TR)
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in REG_IRET */
|
||||
vtop->r = REG_IRET | VT_BOUNDED;
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (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;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
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:
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
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.i);
|
||||
rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
|
||||
}
|
||||
|
||||
static void gen_bounds_prolog(void)
|
||||
{
|
||||
/* leave some room for bound checking code */
|
||||
func_bound_offset = lbounds_section->data_offset;
|
||||
func_bound_ind = ind;
|
||||
func_bound_add_epilog = 0;
|
||||
o(0x00000013); /* ld a0,#lbound section pointer */
|
||||
o(0x00000013);
|
||||
o(0x00000013); /* nop -> call __bound_local_new */
|
||||
o(0x00000013);
|
||||
}
|
||||
|
||||
static void gen_bounds_epilog(void)
|
||||
{
|
||||
static Sym label;
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
int offset_modified = func_bound_offset != lbounds_section->data_offset;
|
||||
|
||||
if (!offset_modified && !func_bound_add_epilog)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
|
||||
*bounds_ptr = 0;
|
||||
|
||||
sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
|
||||
if (!label.v) {
|
||||
label.v = tok_alloc(".LB0 ", 4)->tok;
|
||||
label.type.t = VT_VOID | VT_STATIC;
|
||||
}
|
||||
/* generate bound local allocation */
|
||||
if (offset_modified) {
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
label.c = 0; /* force new local ELF symbol */
|
||||
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_new);
|
||||
ind = saved_ind;
|
||||
}
|
||||
|
||||
/* 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) */
|
||||
label.c = 0; /* force new local ELF symbol */
|
||||
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 */
|
||||
}
|
||||
#endif
|
||||
static void reg_pass_rec(CType *type, int *rc, int *fieldofs, int ofs)
|
||||
{
|
||||
if ((type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
@ -440,6 +580,12 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
int stack_adj = 0, tempspace = 0, ofs, splitofs = 0;
|
||||
SValue *sv;
|
||||
Sym *sa;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
areg[0] = 0; /* int arg regs */
|
||||
areg[1] = 8; /* float arg regs */
|
||||
sa = vtop[-nb_args].type.ref->next;
|
||||
@ -691,6 +837,10 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
ES(0x23, 3, 8, 10 + areg[0], -8 + num_va_regs * 8); // sd aX, loc(s0)
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_prolog();
|
||||
#endif
|
||||
}
|
||||
|
||||
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret,
|
||||
@ -732,6 +882,11 @@ ST_FUNC void gfunc_epilog(void)
|
||||
{
|
||||
int v, saved_ind, d, large_ofs_ind;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_epilog();
|
||||
#endif
|
||||
|
||||
loc = (loc - num_va_regs * 8);
|
||||
d = v = (-loc + 15) & -16;
|
||||
|
||||
|
@ -284,11 +284,11 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
return;
|
||||
|
||||
case R_RISCV_32:
|
||||
write32le(ptr, val);
|
||||
add32le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_JUMP_SLOT:
|
||||
case R_RISCV_64:
|
||||
write64le(ptr, val);
|
||||
add64le(ptr, val);
|
||||
return;
|
||||
case R_RISCV_ADD64:
|
||||
write64le(ptr, read64le(ptr) + val);
|
||||
|
@ -370,7 +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) for the moment.
|
||||
Note: @option{-b} is only available on i386 (linux and windows), x86_64 (linux and windows), arm, arm64 and riscv64 for the moment.
|
||||
|
||||
@item -bt[N]
|
||||
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
|
||||
|
6
tcc.h
6
tcc.h
@ -184,7 +184,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
|
||||
#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT
|
||||
# define CONFIG_TCC_BACKTRACE
|
||||
# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) \
|
||||
# if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || \
|
||||
defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64) || \
|
||||
defined TCC_TARGET_RISCV64 \
|
||||
&& !defined TCC_UCLIBC && !defined TCC_MUSL
|
||||
# define CONFIG_TCC_BCHECK /* enable bound checking code */
|
||||
# endif
|
||||
@ -354,6 +356,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#elif defined TCC_TARGET_ARM64
|
||||
# include "arm64-gen.c"
|
||||
# include "arm64-link.c"
|
||||
# include "arm-asm.c"
|
||||
#elif defined TCC_TARGET_C67
|
||||
# define TCC_TARGET_COFF
|
||||
# include "coff.h"
|
||||
@ -362,6 +365,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#elif defined(TCC_TARGET_RISCV64)
|
||||
# include "riscv64-gen.c"
|
||||
# include "riscv64-link.c"
|
||||
# include "riscv64-asm.c"
|
||||
#else
|
||||
#error unknown target
|
||||
#endif
|
||||
|
2
tccelf.c
2
tccelf.c
@ -3123,7 +3123,7 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
||||
/* test CPU specific stuff */
|
||||
if (ehdr.e_ident[5] != ELFDATA2LSB ||
|
||||
ehdr.e_machine != EM_TCC_TARGET) {
|
||||
tcc_error_noabort("bad architecture");
|
||||
tcc_error_noabort("bad architecture: %s", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
31
tccgen.c
31
tccgen.c
@ -886,6 +886,12 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
||||
/* XXX: avoid doing that for statics ? */
|
||||
/* if bound checking is activated, we change some function
|
||||
names by adding the "__bound" prefix */
|
||||
#if defined(TCC_TARGET_ARM) && defined(TCC_ARM_EABI)
|
||||
if (strcmp (name, "memcpy") == 0 ||
|
||||
strcmp (name, "memmove") == 0 ||
|
||||
strcmp (name, "memset") == 0)
|
||||
goto add_bound;
|
||||
#endif
|
||||
switch(sym->v) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
/* XXX: we rely only on malloc hooks */
|
||||
@ -897,6 +903,10 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
||||
#endif
|
||||
case TOK_memcpy:
|
||||
case TOK_memmove:
|
||||
#if defined(TCC_TARGET_ARM) && defined(TCC_ARM_EABI)
|
||||
case TOK_memmove4:
|
||||
case TOK_memmove8:
|
||||
#endif
|
||||
case TOK_memset:
|
||||
case TOK_memcmp:
|
||||
case TOK_strlen:
|
||||
@ -907,12 +917,17 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
||||
case TOK_strcat:
|
||||
case TOK_strchr:
|
||||
case TOK_strdup:
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
case TOK_alloca:
|
||||
#endif
|
||||
case TOK_mmap:
|
||||
case TOK_munmap:
|
||||
case TOK_longjmp:
|
||||
#ifndef TCC_TARGET_PE
|
||||
case TOK_siglongjmp:
|
||||
#endif
|
||||
#if defined(TCC_TARGET_ARM) && defined(TCC_ARM_EABI)
|
||||
add_bound:
|
||||
#endif
|
||||
strcpy(buf, "__bound_");
|
||||
strcat(buf, name);
|
||||
@ -3820,9 +3835,9 @@ ST_FUNC void vstore(void)
|
||||
/* address of memcpy() */
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(!(align & 7))
|
||||
vpush_global_sym(&func_old_type, TOK_memcpy8);
|
||||
vpush_global_sym(&func_old_type, TOK_memmove8);
|
||||
else if(!(align & 3))
|
||||
vpush_global_sym(&func_old_type, TOK_memcpy4);
|
||||
vpush_global_sym(&func_old_type, TOK_memmove4);
|
||||
else
|
||||
#endif
|
||||
/* Use memmove, rather than memcpy, as dest and src may be same: */
|
||||
@ -5636,13 +5651,25 @@ ST_FUNC void unary(void)
|
||||
mk_pointer(&type);
|
||||
vset(&type, VT_LOCAL, 0); /* local frame */
|
||||
while (level--) {
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
vpushi(2*PTR_SIZE);
|
||||
gen_op('-');
|
||||
#endif
|
||||
mk_pointer(&vtop->type);
|
||||
indir(); /* -> parent frame */
|
||||
}
|
||||
if (tok1 == TOK_builtin_return_address) {
|
||||
// assume return address is just above frame pointer on stack
|
||||
#ifdef TCC_TARGET_ARM
|
||||
vpushi(2*PTR_SIZE);
|
||||
gen_op('+');
|
||||
#elif defined TCC_TARGET_RISCV64
|
||||
vpushi(PTR_SIZE);
|
||||
gen_op('-');
|
||||
#else
|
||||
vpushi(PTR_SIZE);
|
||||
gen_op('+');
|
||||
#endif
|
||||
mk_pointer(&vtop->type);
|
||||
indir();
|
||||
}
|
||||
|
39
tccrun.c
39
tccrun.c
@ -648,10 +648,12 @@ static void rt_getcontext(ucontext_t *uc, rt_context *rc)
|
||||
#elif defined(__arm__)
|
||||
rc->ip = uc->uc_mcontext.arm_pc;
|
||||
rc->fp = uc->uc_mcontext.arm_fp;
|
||||
rc->sp = uc->uc_mcontext.arm_sp;
|
||||
#elif defined(__aarch64__)
|
||||
rc->ip = uc->uc_mcontext.pc;
|
||||
rc->fp = uc->uc_mcontext.regs[29];
|
||||
#elif defined(__riscv)
|
||||
rc->ip = uc->uc_mcontext.__gregs[REG_PC];
|
||||
rc->fp = uc->uc_mcontext.__gregs[REG_S0];
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -805,22 +807,9 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
addr_t fp = rc->fp;
|
||||
addr_t sp = rc->sp;
|
||||
if (sp < 0x1000)
|
||||
sp = 0x1000;
|
||||
/* XXX: specific to tinycc stack frames */
|
||||
if (fp < sp + 12 || fp & 3)
|
||||
return -1;
|
||||
while (--level) {
|
||||
sp = ((addr_t *)fp)[-2];
|
||||
if (sp < fp || sp - fp > 16 || sp & 3)
|
||||
return -1;
|
||||
fp = ((addr_t *)fp)[-3];
|
||||
if (fp <= sp || fp - sp < 12 || fp & 3)
|
||||
return -1;
|
||||
}
|
||||
/* XXX: check address validity with program info */
|
||||
*paddr = ((addr_t *)fp)[-1];
|
||||
while (--level)
|
||||
fp = ((addr_t *)fp)[0];
|
||||
*paddr = ((addr_t *)fp)[2];
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
@ -829,7 +818,7 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
#elif defined(__aarch64__)
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
{
|
||||
if (level == 0) {
|
||||
if (level == 0) {
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
addr_t *fp = (addr_t*)rc->fp;
|
||||
@ -840,6 +829,20 @@ static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(__riscv)
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
{
|
||||
if (level == 0) {
|
||||
*paddr = rc->ip;
|
||||
} else {
|
||||
addr_t *fp = (addr_t*)rc->fp;
|
||||
while (--level)
|
||||
fp = (addr_t *)fp[-2];
|
||||
*paddr = fp[-1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#warning add arch specific rt_get_caller_pc()
|
||||
static int rt_get_caller_pc(addr_t *paddr, rt_context *rc, int level)
|
||||
|
4
tcctok.h
4
tcctok.h
@ -205,9 +205,9 @@
|
||||
#if defined TCC_TARGET_ARM
|
||||
# ifdef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
||||
DEF(TOK_memcpy4, "__aeabi_memcpy4")
|
||||
DEF(TOK_memcpy8, "__aeabi_memcpy8")
|
||||
DEF(TOK_memmove, "__aeabi_memmove")
|
||||
DEF(TOK_memmove4, "__aeabi_memmove4")
|
||||
DEF(TOK_memmove8, "__aeabi_memmove8")
|
||||
DEF(TOK_memset, "__aeabi_memset")
|
||||
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
|
||||
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
|
||||
|
@ -35,6 +35,15 @@ endif
|
||||
ifeq ($(ARCH),x86_64)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
ifeq ($(ARCH),arm)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
ifeq ($(ARCH),arm64)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
ifeq ($(ARCH),riscv64)
|
||||
TESTS += $(BTESTS)
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_OSX # -run only
|
||||
TESTS := hello-run libtest tests2-dir pp-dir
|
||||
|
@ -169,21 +169,34 @@ int test13(void)
|
||||
return strlen(tab);
|
||||
}
|
||||
|
||||
#if defined __i386__ || defined __x86_64__
|
||||
#define allocf(x)
|
||||
#else
|
||||
#define alloca(x) malloc(x)
|
||||
#define allocf(x) free(x)
|
||||
#endif
|
||||
|
||||
int test14(void)
|
||||
{
|
||||
char *p = alloca(TAB_SIZE);
|
||||
size_t ret;
|
||||
memset(p, 'a', TAB_SIZE);
|
||||
p[TAB_SIZE-1] = 0;
|
||||
return strlen(p);
|
||||
ret = strlen(p);
|
||||
allocf(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* error */
|
||||
int test15(void)
|
||||
{
|
||||
char *p = alloca(TAB_SIZE-1);
|
||||
size_t ret;
|
||||
memset(p, 'a', TAB_SIZE);
|
||||
p[TAB_SIZE-1] = 0;
|
||||
return strlen(p);
|
||||
ret = strlen(p);
|
||||
allocf(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ok */
|
||||
@ -194,6 +207,7 @@ int test16()
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
allocf(p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)+1),demo) );
|
||||
@ -209,6 +223,7 @@ int test17()
|
||||
|
||||
p = alloca(16);
|
||||
strcpy(p,"12345678901234");
|
||||
allocf(p);
|
||||
|
||||
/* Test alloca embedded in a larger expression */
|
||||
printf("alloca : %s : %s\n", p, strcpy(alloca(strlen(demo)),demo) );
|
||||
|
@ -23,8 +23,11 @@ ifeq (,$(filter i386,$(ARCH)))
|
||||
SKIP += 98_al_ax_extend.test 99_fastcall.test
|
||||
endif
|
||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
SKIP += 85_asm-outside-function.test
|
||||
SKIP += 112_backtrace.test 113_btdll.test
|
||||
SKIP += 85_asm-outside-function.test # x86 asm
|
||||
SKIP += 113_btdll.test # dll support needed
|
||||
endif
|
||||
ifeq (,$(filter i386 x86_64 arm arm64 riscv64,$(ARCH)))
|
||||
SKIP += 112_backtrace.test
|
||||
SKIP += 114_bound_signal.test
|
||||
SKIP += 115_bound_setjmp.test
|
||||
SKIP += 116_bound_setjmp2.test
|
||||
@ -82,7 +85,7 @@ GEN-ALWAYS =
|
||||
|
||||
112_backtrace.test: FLAGS += -dt -b
|
||||
112_backtrace.test 113_btdll.test: FILTER += \
|
||||
-e 's;[0-9A-Fa-fx]\{8,\};........;g' \
|
||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||
-e 's;0x[0-9A-Fa-f]\+;0x?;g'
|
||||
|
||||
# this test creates two DLLs and an EXE
|
||||
|
@ -744,8 +744,9 @@ static void gen_bounds_epilog(void)
|
||||
addr_t saved_ind;
|
||||
addr_t *bounds_ptr;
|
||||
Sym *sym_data;
|
||||
int offset_modified = func_bound_offset != lbounds_section->data_offset;
|
||||
|
||||
if (func_bound_offset == lbounds_section->data_offset && !func_bound_add_epilog)
|
||||
if (!offset_modified && !func_bound_add_epilog)
|
||||
return;
|
||||
|
||||
/* add end of table info */
|
||||
@ -756,7 +757,7 @@ static void gen_bounds_epilog(void)
|
||||
func_bound_offset, lbounds_section->data_offset);
|
||||
|
||||
/* generate bound local allocation */
|
||||
if (func_bound_offset != lbounds_section->data_offset) {
|
||||
if (offset_modified) {
|
||||
saved_ind = ind;
|
||||
ind = func_bound_ind;
|
||||
greloca(cur_text_section, sym_data, ind + 2, R_X86_64_64, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user