refactor: replace remaining ARM64 opcode literals with symbolic constants

This commit is contained in:
Benjamin Oldenburg 2026-03-21 01:15:15 +07:00
parent 7d2f376843
commit 62345bb113
4 changed files with 67 additions and 59 deletions

View File

@ -707,10 +707,10 @@ static void gen_mrs(int rt, int sysreg)
switch (sysreg) {
case 0: /* FPCR */
instr = 0xD53B4400U;
instr = ARM64_MRS_FPCR;
break;
case 1: /* FPSR */
instr = 0xD53B4420U;
instr = ARM64_MRS_FPSR;
break;
default:
tcc_error("unsupported system register");
@ -725,10 +725,10 @@ static void gen_msr(int rt, int sysreg)
switch (sysreg) {
case 0: /* FPCR */
instr = 0xD51B4400U;
instr = ARM64_MSR_FPCR;
break;
case 1: /* FPSR */
instr = 0xD51B4420U;
instr = ARM64_MSR_FPSR;
break;
default:
tcc_error("unsupported system register");
@ -784,7 +784,7 @@ static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm,
tcc_error("shift immediate out of range");
return;
}
instr = is_64bit ? 0x93C00000U : 0x13800000U;
instr = is_64bit ? ARM64_EXTR64 : ARM64_EXTR;
instr |= ARM64_RM(rm_or_imm); /* Rm = shift amount */
instr |= ARM64_RN(rn); /* Rn = source */
instr |= ARM64_RD(rd); /* Rd = dest */

View File

@ -483,30 +483,32 @@ static void arm64_sym(int r, Sym *sym, unsigned long addend)
#ifdef TCC_TARGET_PE
/* PE links symbol addresses directly; there is no ELF-style GOT here. */
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_PREL_PG_HI21, 0);
o(0x90000000 | r); // adrp xr, #sym
o(ARM64_ADRP | r); // adrp xr, #sym
greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, 0);
o(0x91000000 | r | (r << 5)); // add xr, xr, #sym
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r); // add xr, xr, #sym
#else
greloca(cur_text_section, sym, ind, R_AARCH64_ADR_GOT_PAGE, 0);
o(0x90000000 | r); // adrp xr, #sym
o(ARM64_ADRP | r); // adrp xr, #sym
greloca(cur_text_section, sym, ind, R_AARCH64_LD64_GOT_LO12_NC, 0);
o(0xf9400000 | r | (r << 5)); // ld xr,[xr, #sym]
o(ARM64_LDR_X | ARM64_RN(r) | r); // ld xr,[xr, #sym]
#endif
if (addend) {
// add xr, xr, #addend
if (addend & 0xffful)
o(0x91000000 | r | r << 5 | (addend & 0xfff) << 10);
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RN(r) | r |
(addend & 0xfff) << 10);
if (addend > 0xffful) {
// add xr, xr, #addend, lsl #12
if (addend & 0xfff000ul)
o(0x91400000 | r | r << 5 | ((addend >> 12) & 0xfff) << 10);
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) |
ARM64_RN(r) | r | ((addend >> 12) & 0xfff) << 10);
if (addend > 0xfffffful) {
/* very unlikely */
int t = r ? 0 : 1;
o(0xf81f0fe0 | t); /* str xt, [sp, #-16]! */
o(ARM64_STR_X_PRE | 0x001F0FE0U | t); /* str xt, [sp, #-16]! */
arm64_movimm(t, addend & ~0xfffffful); // use xt for addent
o(0x8B000000 | (t << 16) | (r << 5) | r); /* add xr, xr, xt */
o(0xf84107e0 | t); /* ldr xt, [sp], #16 */
o(ARM64_ADD_REG | ARM64_SF(1) | ARM64_RM(t) | ARM64_RN(r) | r); /* add xr, xr, xt */
o(ARM64_LDR_X_POST | 0x000107E0U | t); /* ldr xt, [sp], #16 */
}
}
}
@ -586,12 +588,12 @@ ST_FUNC void load(int r, SValue *sv)
if (svr < VT_CONST) {
if (IS_FREG(r) && IS_FREG(svr))
if (svtt == VT_LDOUBLE)
o(0x4ea01c00 | fltr(r) | fltr(svr) << 5);
o(ARM64_MOV_V16B | fltr(r) | fltr(svr) << 5);
// mov v(r).16b,v(svr).16b
else
o(0x1e604000 | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr)
o(ARM64_FMOV_SCALAR | fltr(r) | fltr(svr) << 5); // fmov d(r),d(svr)
else if (!IS_FREG(r) && !IS_FREG(svr))
o(0xaa0003e0 | intr(r) | intr(svr) << 16); // mov x(r),x(svr)
o(ARM64_MOV_REG | ARM64_SF(1) | intr(r) | intr(svr) << 16); // mov x(r),x(svr)
else
assert(0);
return;
@ -610,7 +612,7 @@ ST_FUNC void load(int r, SValue *sv)
if (svr == VT_JMP || svr == VT_JMPI) {
int t = (svr == VT_JMPI);
arm64_movimm(intr(r), t);
o(0x14000002); // b .+8
o(ARM64_B | 2); // b .+8
gsym(svcul);
arm64_movimm(intr(r), t ^ 1);
return;
@ -697,13 +699,13 @@ static void arm64_gen_bl_or_b(int b)
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && (vtop->r & VT_SYM)) {
greloca(cur_text_section, vtop->sym, ind,
b ? R_AARCH64_JUMP26 : R_AARCH64_CALL26, 0);
o(0x14000000 | (uint32_t)!b << 31); // b/bl .
o(b ? ARM64_B : ARM64_BL); // b/bl .
}
else {
#ifdef CONFIG_TCC_BCHECK
vtop->r &= ~VT_MUSTBOUND;
#endif
o(0xd61f0000 | (uint32_t)!b << 21 | intr(gv(RC_R30)) << 5); // br/blr
o((b ? ARM64_BR : ARM64_BLR) | intr(gv(RC_R30)) << 5); // br/blr
}
}
@ -714,7 +716,7 @@ static void gen_bounds_call(int v)
Sym *sym = external_helper_sym(v);
greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl
o(ARM64_BL); // bl
}
static void gen_bounds_prolog(void)
@ -723,10 +725,10 @@ static void gen_bounds_prolog(void)
func_bound_offset = lbounds_section->data_offset;
func_bound_ind = ind;
func_bound_add_epilog = 0;
o(0xd503201f); /* nop -> mov x0, lbound section pointer */
o(0xd503201f);
o(0xd503201f);
o(0xd503201f); /* nop -> call __bound_local_new */
o(ARM64_NOP); /* nop -> mov x0, lbound section pointer */
o(ARM64_NOP);
o(ARM64_NOP);
o(ARM64_NOP); /* nop -> call __bound_local_new */
}
static void gen_bounds_epilog(void)
@ -1043,7 +1045,7 @@ static void arm64_sub_sp(uint64_t diff)
arm64_movimm(15, diff >> 4);
greloca(cur_text_section, sym, ind, R_AARCH64_CALL26, 0);
o(0x94000000); // bl __chkstk
o(ARM64_BL); // bl __chkstk
o(0xcb2f73ff); // sub sp,sp,x15,lsl #4
return;
}
@ -1165,9 +1167,9 @@ ST_FUNC void gfunc_call(int nb_args)
if ((variadic || old_style) && i > var_nb_arg && is_float(vtop->type.t)) {
gv(RC_FLOAT);
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
o(0x9e660000 | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov xN,dM
o(ARM64_FMOV_XD | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov xN,dM
else
o(0x1e260000 | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov wN,sM
o(ARM64_FMOV_WS | intr(a[i] / 2) | fltr(vtop->r) << 5); // fmov wN,sM
}
else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
int align, size = type_size(&vtop->type, &align);
@ -1394,7 +1396,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
arm64_func_sub_sp_offset = ind;
/* In gfunc_epilog these will be replaced with stack setup code. */
for (i = 0; i < ARM64_FUNC_STACK_SETUP_SLOTS; ++i)
o(0xd503201f); // nop
o(ARM64_NOP); // nop
loc = 0;
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check)
@ -1481,7 +1483,7 @@ ST_FUNC void gen_va_arg(CType *t)
vtop[0].r = r1 | VT_LVAL;
r1 = intr(r1);
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // ap
o(ARM64_LDR_X | ARM64_RN(r0) | r1); // ldr x(r1),[x(r0)] // ap
if (slot) {
if (slot == 16) {
o(0x910363be); // add x30,x29,#216
@ -1498,7 +1500,7 @@ ST_FUNC void gen_va_arg(CType *t)
}
if (indirect)
o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)]
o(ARM64_LDR_X | ARM64_RN(r1) | r1); // ldr x(r1),[x(r1)]
return;
#endif
@ -1525,7 +1527,7 @@ ST_FUNC void gen_va_arg(CType *t)
o(0x310003c0 | r1 | n << 10); // adds w(r1),w30,#(n)
o(0x540000ad); // b.le .+20
#endif
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
o(ARM64_LDR_X | ARM64_RN(r0) | r1); // ldr x(r1),[x(r0)] // __stack
if (align == 16) {
o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
@ -1533,13 +1535,13 @@ ST_FUNC void gen_va_arg(CType *t)
o(0x9100001e | r1 << 5 | n << 10); // add x30,x(r1),#(n)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
#if !defined(TCC_TARGET_MACHO)
o(0x14000004); // b .+16
o(ARM64_B | 4); // b .+16
o(0xb9001800 | r1 | r0 << 5); // str w(r1),[x(r0),#24] // __gr_offs
o(0xf9400400 | r1 | r0 << 5); // ldr x(r1),[x(r0),#8] // __gr_top
o(0x8b3ec000 | r1 | r1 << 5); // add x(r1),x(r1),w30,sxtw
#endif
if (size > 16)
o(0xf9400000 | r1 | r1 << 5); // ldr x(r1),[x(r1)]
o(ARM64_LDR_X | ARM64_RN(r1) | r1); // ldr x(r1),[x(r1)]
}
else {
uint32_t ssz = (size + 7) & -(uint32_t)8;
@ -1550,7 +1552,7 @@ ST_FUNC void gen_va_arg(CType *t)
o(0x310003c0 | r1 | rsz << 10); // adds w(r1),w30,#(rsz)
b1 = ind; o(0x5400000d); // b.le lab1
#endif
o(0xf9400000 | r1 | r0 << 5); // ldr x(r1),[x(r0)] // __stack
o(ARM64_LDR_X | ARM64_RN(r0) | r1); // ldr x(r1),[x(r0)] // __stack
if (fsize == 16) {
o(0x91003c00 | r1 | r1 << 5); // add x(r1),x(r1),#15
o(0x927cec00 | r1 | r1 << 5); // and x(r1),x(r1),#-16
@ -1558,7 +1560,7 @@ ST_FUNC void gen_va_arg(CType *t)
o(0x9100001e | r1 << 5 | ssz << 10); // add x30,x(r1),#(ssz)
o(0xf900001e | r0 << 5); // str x30,[x(r0)] // __stack
#if !defined(TCC_TARGET_MACHO)
b2 = ind; o(0x14000000); // b lab2
b2 = ind; o(ARM64_B); // b lab2
// lab1:
write32le(cur_text_section->data + b1, 0x5400000d | (ind - b1) << 3);
o(0xb9001c00 | r1 | r0 << 5); // str w(r1),[x(r0),#28] // __vr_offs
@ -1580,7 +1582,7 @@ ST_FUNC void gen_va_arg(CType *t)
(uint32_t)(hfa != 3) << 21); // st(hfa) {v28.(s|d),...}[0],[x(r1)]
}
// lab2:
write32le(cur_text_section->data + b2, 0x14000000 | (ind - b2) >> 2);
write32le(cur_text_section->data + b2, ARM64_B | ((ind - b2) >> 2));
#endif
}
}
@ -1655,7 +1657,7 @@ ST_FUNC void gfunc_epilog(void)
ind = arm64_func_sub_sp_offset;
arm64_sub_sp(diff);
for (i = ind; i < patch_end; i += 4)
write32le(cur_text_section->data + i, 0xd503201f); // nop
write32le(cur_text_section->data + i, ARM64_NOP); // nop
ind = saved_ind;
}
o(0x910003bf); // mov sp,x29
@ -1675,7 +1677,7 @@ ST_FUNC void gen_fill_nops(int bytes)
if ((bytes & 3))
tcc_error("alignment of code section not multiple of 4");
while (bytes > 0) {
o(0xd503201f); // nop
o(ARM64_NOP); // nop
bytes -= 4;
}
}
@ -1694,7 +1696,7 @@ ST_FUNC int gjmp(int t)
ST_FUNC void gjmp_addr(int a)
{
assert(a - ind + 0x8000000 < 0x10000000);
o(0x14000000 | ((a - ind) >> 2 & 0x3ffffff));
o(ARM64_B | (((a - ind) >> 2) & 0x3ffffff));
}
ST_FUNC int gjmp_append(int n, int t)
@ -2257,7 +2259,7 @@ ST_FUNC void gen_increment_tcov (SValue *sv)
vtop->r = r1 = get_reg(RC_INT);
r2 = get_reg(RC_INT);
arm64_sym(r1, sv->sym, 0);
o(0xf9400000 | (intr(r1)<<5) | intr(r2)); // ldr r2, [r1]
o(ARM64_LDR_X | ARM64_RN(intr(r1)) | intr(r2)); // ldr r2, [r1]
o(0x91000400 | (intr(r2)<<5) | intr(r2)); // add r2, r2, #1
o(0xf9000000 | (intr(r1)<<5) | intr(r2)); // str r2, [r1]
vpop();
@ -2294,21 +2296,21 @@ ST_FUNC void gen_clear_cache(void)
o(0x1ac02000 | isz | p << 5 | isz << 16); // lsl w(isz),w(p),w(isz)
o(0x51000400 | p | dsz << 5); // sub w(p),w(dsz),#1
o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p)
b1 = ind; o(0x14000000); // b
b1 = ind; o(ARM64_B); // b
lab1 = ind;
o(0xd50b7b20 | p); // dc cvau,x(p)
o(0x8b000000 | p | p << 5 | dsz << 16); // add x(p),x(p),x(dsz)
write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2);
write32le(cur_text_section->data + b1, ARM64_B | ((ind - b1) >> 2));
o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end)
o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1
o(0xd5033b9f); // dsb ish
o(0x51000400 | p | isz << 5); // sub w(p),w(isz),#1
o(0x8a240004 | p | beg << 5 | p << 16); // bic x(p),x(beg),x(p)
b1 = ind; o(0x14000000); // b
b1 = ind; o(ARM64_B); // b
lab1 = ind;
o(0xd50b7520 | p); // ic ivau,x(p)
o(0x8b000000 | p | p << 5 | isz << 16); // add x(p),x(p),x(isz)
write32le(cur_text_section->data + b1, 0x14000000 | (ind - b1) >> 2);
write32le(cur_text_section->data + b1, ARM64_B | ((ind - b1) >> 2));
o(0xeb00001f | p << 5 | end << 16); // cmp x(p),x(end)
o(0x54ffffa3 | ((lab1 - ind) << 3 & 0xffffe0)); // b.cc lab1
o(0xd5033b9f); // dsb ish

View File

@ -131,17 +131,18 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t off = (got >> 12) - (plt >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error_noabort("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt);
write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
write32le(p + 4, (0x90000010 | // adrp x16,...
write32le(p, ARM64_STP_X_PRE | ARM64_RT(16) | ARM64_RT2(30) |
ARM64_RN(31) | ARM64_IMM7(-2)); // stp x16,x30,[sp,#-16]!
write32le(p + 4, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
write32le(p + 8, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
(got & 0xff8) << 7));
write32le(p + 12, (0x91000210 | // add x16,x16,#...
write32le(p + 12, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
(got & 0xfff) << 10));
write32le(p + 16, 0xd61f0220); // br x17
write32le(p + 20, 0xd503201f); // nop
write32le(p + 24, 0xd503201f); // nop
write32le(p + 28, 0xd503201f); // nop
write32le(p + 16, ARM64_BR | ARM64_RN(17)); // br x17
write32le(p + 20, ARM64_NOP); // nop
write32le(p + 24, ARM64_NOP); // nop
write32le(p + 28, ARM64_NOP); // nop
p += 32;
got = s1->got->sh_addr;
while (p < p_end) {
@ -150,13 +151,13 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t off = (addr >> 12) - (pc >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error_noabort("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", (long)off, (long)addr, (long)pc);
write32le(p, (0x90000010 | // adrp x16,...
write32le(p, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
write32le(p + 4, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
(addr & 0xff8) << 7));
write32le(p + 8, (0x91000210 | // add x16,x16,#...
write32le(p + 8, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
(addr & 0xfff) << 10));
write32le(p + 12, 0xd61f0220); // br x17
write32le(p + 12, ARM64_BR | ARM64_RN(17)); // br x17
p += 16;
}
}
@ -321,7 +322,7 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
write32le(ptr, 0xd503201f); /* nop */
write32le(ptr, ARM64_NOP); /* nop */
return;
}
#endif

View File

@ -692,6 +692,10 @@
#define ARM64_DMB 0xD50330BFU
#define ARM64_MRS 0xD5380000U
#define ARM64_MSR 0xD5180000U
#define ARM64_MRS_FPCR 0xD53B4400U
#define ARM64_MRS_FPSR 0xD53B4420U
#define ARM64_MSR_FPCR 0xD51B4400U
#define ARM64_MSR_FPSR 0xD51B4420U
/* Shifts (register) */
#define ARM64_LSL_REG 0x1AC02000U
@ -809,7 +813,8 @@
#define ARM64_FCMP 0x1E202008U /* FCMP with zero */
#define ARM64_SDIV 0x1AC00C00U /* SDIV (32-bit) */
/* EXTR (Extract) - 64-bit variant */
/* EXTR (Extract) */
#define ARM64_EXTR 0x13800000U /* EXTR Wd, Wn, Wm, #imm (32-bit) */
#define ARM64_EXTR64 0x93C00000U /* EXTR Xd, Xn, Xm, #imm (64-bit) */
/* ARM64_MUL removed - use ARM64_MUL_REG with gen_dp_reg() */