arm64: support mnemonic win32 stack helpers

This commit is contained in:
Benjamin Oldenburg 2026-03-16 05:59:15 +07:00
parent b1763f8629
commit 0decb1b86f
4 changed files with 407 additions and 163 deletions

View File

@ -58,9 +58,17 @@ typedef struct Operand {
int8_t reg2;
uint8_t reg_type;
uint8_t shift;
uint8_t addr_mode;
int reg_tok;
ExprValue e;
} Operand;
enum {
ADDR_OFF,
ADDR_PRE,
ADDR_POST,
};
/* Forward declaration */
static void parse_addr_operand(TCCState *s1, Operand *op);
@ -217,6 +225,8 @@ static void parse_operand(TCCState *s1, Operand *op)
op->reg2 = -1;
op->reg_type = 0;
op->shift = 0;
op->addr_mode = ADDR_OFF;
op->reg_tok = 0;
/* Address operand in brackets [xn, ...] */
if (tok == '[') {
@ -230,6 +240,7 @@ static void parse_operand(TCCState *s1, Operand *op)
op->type = OP_REG;
op->reg = reg;
op->reg_type = get_reg_type(tok);
op->reg_tok = tok;
next();
return;
}
@ -244,7 +255,7 @@ static void parse_operand(TCCState *s1, Operand *op)
}
/* Immediate or address expression */
if (tok == '#' || tok == ':' || tok == '@') {
if (tok == '#' || tok == ':' || tok == '@' || tok == '$') {
next();
}
asm_expr(s1, &op->e);
@ -261,20 +272,34 @@ static void parse_addr_operand(TCCState *s1, Operand *op)
op->reg2 = -1;
op->e.v = 0;
op->e.sym = NULL;
op->addr_mode = ADDR_OFF;
op->reg_tok = 0;
skip('[');
reg = arm64_parse_regvar(tok);
if (reg >= 0 && reg < 32) {
op->reg = reg;
op->reg_tok = tok;
next();
/* Check for offset */
if (tok == ',') {
next();
if (tok == '#' || tok == '@') next();
if (tok == '#' || tok == '@' || tok == '$')
next();
asm_expr(s1, &op->e);
}
}
skip(']');
if (tok == '!') {
op->addr_mode = ADDR_PRE;
next();
} else if (tok == ',') {
op->addr_mode = ADDR_POST;
next();
if (tok == '#' || tok == '@' || tok == '$')
next();
asm_expr(s1, &op->e);
}
}
/* Generate MOVZ instruction */
@ -317,10 +342,22 @@ static void gen_movk(int rd, uint16_t imm, int shift, int is_64bit)
static void gen_add_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
{
uint32_t instr = 0x11000000;
uint32_t imm12;
if (is_64bit) instr |= (1 << 31);
if (setflags) instr |= (1 << 29);
instr |= ((imm >> 12) & 0x3) << 22;
instr |= (imm & 0xFFF) << 10;
if (imm <= 0xFFF) {
imm12 = imm;
} else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
instr |= 1 << 22;
imm12 = imm >> 12;
} else {
tcc_error("add immediate out of range");
return;
}
instr |= imm12 << 10;
instr |= (rn & 0x1F) << 5;
instr |= rd & 0x1F;
emit_instr32(instr);
@ -330,10 +367,22 @@ static void gen_add_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags
static void gen_sub_imm(int rd, int rn, uint32_t imm, int is_64bit, int setflags)
{
uint32_t instr = 0x51000000;
uint32_t imm12;
if (is_64bit) instr |= (1 << 31);
if (setflags) instr |= (1 << 29);
instr |= ((imm >> 12) & 0x3) << 22;
instr |= (imm & 0xFFF) << 10;
if (imm <= 0xFFF) {
imm12 = imm;
} else if (!(imm & 0xFFF) && (imm >> 12) <= 0xFFF) {
instr |= 1 << 22;
imm12 = imm >> 12;
} else {
tcc_error("sub immediate out of range");
return;
}
instr |= imm12 << 10;
instr |= (rn & 0x1F) << 5;
instr |= rd & 0x1F;
emit_instr32(instr);
@ -350,21 +399,44 @@ static void gen_dp_reg(uint32_t opcode, int rd, int rn, int rm, int is_64bit)
emit_instr32(instr);
}
/* Generate LDR/STR (immediate) */
/* Generate LDR/STR (unsigned immediate) */
static void gen_ldst_imm(uint32_t base_opcode, int rt, int rn,
int32_t offset, int is_64bit, int size_log2)
int32_t offset, int size_log2)
{
uint32_t instr = base_opcode;
uint32_t imm12;
if (is_64bit) instr |= (1 << 30);
if (offset < 0 || (offset & ((1 << size_log2) - 1)))
tcc_error("invalid load/store offset");
imm12 = offset >> size_log2;
if (imm12 > 0xFFF)
tcc_error("load/store offset out of range");
instr |= (imm12 & 0xFFF) << 10;
instr |= (rn & 0x1F) << 5;
instr |= rt & 0x1F;
emit_instr32(instr);
}
/* Generate STP/LDP (signed immediate) */
static void gen_ldst_pair(uint32_t base_opcode, int rt, int rt2, int rn,
int32_t offset, int size_log2)
{
int32_t imm7;
uint32_t instr = base_opcode;
if (offset & ((1 << size_log2) - 1))
tcc_error("invalid pair load/store offset");
imm7 = offset >> size_log2;
if (imm7 < -64 || imm7 > 63)
tcc_error("pair load/store offset out of range");
instr |= (imm7 & 0x7F) << 15;
instr |= (rt2 & 0x1F) << 10;
instr |= (rn & 0x1F) << 5;
instr |= rt & 0x1F;
emit_instr32(instr);
}
/* Generate B (branch) */
static void gen_b(int32_t offset)
{
@ -444,6 +516,61 @@ static void gen_mov_reg(int rd, int rm, int is_64bit)
emit_instr32(instr);
}
static int operand_is_sp(const Operand *op)
{
return op->reg_tok == TOK_ASM_sp;
}
static int parse_sysreg_name(int t)
{
const char *name;
if (t < TOK_IDENT)
return -1;
name = get_tok_str(t, NULL);
if (!strcmp(name, "FPCR") || !strcmp(name, "fpcr"))
return 0;
if (!strcmp(name, "FPSR") || !strcmp(name, "fpsr"))
return 1;
return -1;
}
static void gen_mrs(int rt, int sysreg)
{
uint32_t instr;
switch (sysreg) {
case 0:
instr = 0xD53B4400;
break;
case 1:
instr = 0xD53B4420;
break;
default:
tcc_error("unsupported system register");
return;
}
emit_instr32(instr | (rt & 0x1F));
}
static void gen_msr(int rt, int sysreg)
{
uint32_t instr;
switch (sysreg) {
case 0:
instr = 0xD51B4400;
break;
case 1:
instr = 0xD51B4420;
break;
default:
tcc_error("unsupported system register");
return;
}
emit_instr32(instr | (rt & 0x1F));
}
/* Generate NOP */
static void gen_nop(void)
{
@ -454,40 +581,46 @@ static void gen_nop(void)
static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm, int is_64bit)
{
uint32_t instr;
int width = is_64bit ? 64 : 32;
if (is_imm) {
/* Shift by immediate */
switch (shift_type) {
case 0: /* LSL */
instr = is_64bit ? 0xD3600000 : 0x53000000;
/* For LSL, the immediate is encoded as (64 - imm) & 0x3F for 64-bit */
if (is_64bit) {
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
} else {
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
if (rm_or_imm < 0 || rm_or_imm >= width) {
tcc_error("shift immediate out of range");
return;
}
instr = is_64bit ? 0xD3400000 : 0x53000000;
instr |= ((width - rm_or_imm) & (width - 1)) << 16;
instr |= (width - 1 - rm_or_imm) << 10;
break;
case 1: /* LSR */
instr = is_64bit ? 0xD3600000 : 0x53000000;
instr |= (1 << 22);
if (is_64bit) {
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
} else {
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
if (rm_or_imm < 0 || rm_or_imm >= width) {
tcc_error("shift immediate out of range");
return;
}
instr = is_64bit ? 0xD3400000 : 0x53000000;
instr |= rm_or_imm << 16;
instr |= (width - 1) << 10;
break;
case 2: /* ASR */
instr = is_64bit ? 0xD3600000 : 0x53000000;
instr |= (2 << 22);
if (is_64bit) {
instr |= ((64 - rm_or_imm) & 0x3F) << 10;
} else {
instr |= ((32 - rm_or_imm) & 0x1F) << 10;
if (rm_or_imm < 0 || rm_or_imm >= width) {
tcc_error("shift immediate out of range");
return;
}
instr = is_64bit ? 0x93400000 : 0x13000000;
instr |= rm_or_imm << 16;
instr |= (width - 1) << 10;
break;
case 3: /* ROR */
instr = is_64bit ? 0x93C00000 : 0x13C00000;
instr |= (rm_or_imm & 0x1F) << 10;
if (rm_or_imm < 0 || rm_or_imm >= width) {
tcc_error("shift immediate out of range");
return;
}
instr = is_64bit ? 0x93C00000 : 0x13800000;
instr |= (rn & 0x1F) << 16;
instr |= (rm_or_imm & (width - 1)) << 10;
break;
default:
tcc_error("unknown shift type");
@ -499,21 +632,23 @@ static void gen_shift(int rd, int rn, int rm_or_imm, int shift_type, int is_imm,
/* Shift by register */
switch (shift_type) {
case 0: /* LSL */
instr = is_64bit ? 0x1AC02000 : 0x1AC02000;
instr = 0x1AC02000;
break;
case 1: /* LSR */
instr = is_64bit ? 0x1AC02400 : 0x1AC02400;
instr = 0x1AC02400;
break;
case 2: /* ASR */
instr = is_64bit ? 0x1AC02800 : 0x1AC02800;
instr = 0x1AC02800;
break;
case 3: /* ROR */
instr = is_64bit ? 0x1AC02C00 : 0x1AC02C00;
instr = 0x1AC02C00;
break;
default:
tcc_error("unknown shift type");
return;
}
if (is_64bit)
instr |= 1U << 31;
instr |= (rm_or_imm & 0x1F) << 16;
instr |= (rn & 0x1F) << 5;
instr |= rd & 0x1F;
@ -674,11 +809,18 @@ static void asm_mov(TCCState *s1)
if (op2.type & OP_IM) {
/* Handle immediate: mov x0, #123 */
if (operand_is_sp(&op1)) {
tcc_error("cannot move an immediate into sp");
return;
}
gen_mov_imm(rd, op2.e.v, is_64bit);
} else if (op2.type & OP_REG) {
/* Handle register: mov x0, x1 */
rn = op2.reg;
gen_mov_reg(rd, rn, is_64bit);
if (operand_is_sp(&op1) || operand_is_sp(&op2))
gen_add_imm(rd, rn, 0, 1, 0);
else
gen_mov_reg(rd, rn, is_64bit);
} else {
tcc_error("invalid operand for mov");
}
@ -758,7 +900,6 @@ static void asm_ldst(TCCState *s1, int token)
Operand op1, op2;
int rt, rn;
int32_t offset = 0;
int is_64bit = 1;
int size_log2 = 3;
uint32_t base_opcode;
@ -772,49 +913,49 @@ static void asm_ldst(TCCState *s1, int token)
switch (token) {
case TOK_ASM_ldr:
base_opcode = 0xB9400000;
if (op1.reg_type & REG_X) {
is_64bit = 1;
base_opcode = 0xF9400000;
size_log2 = 3;
} else if (op1.reg_type & REG_W) {
is_64bit = 0;
base_opcode = 0xB9400000;
size_log2 = 2;
} else if (op1.reg_type & REG_D) {
base_opcode = 0xFD400000;
size_log2 = 3;
} else {
tcc_error("ldr requires a w or x register");
tcc_error("ldr requires a w, x, or d register");
return;
}
break;
case TOK_ASM_ldrb:
base_opcode = 0x39400000;
is_64bit = 0;
size_log2 = 0;
break;
case TOK_ASM_ldrh:
base_opcode = 0x79400000;
is_64bit = 0;
size_log2 = 1;
break;
case TOK_ASM_str:
base_opcode = 0xB9000000;
if (op1.reg_type & REG_X) {
is_64bit = 1;
base_opcode = 0xF9000000;
size_log2 = 3;
} else if (op1.reg_type & REG_W) {
is_64bit = 0;
base_opcode = 0xB9000000;
size_log2 = 2;
} else if (op1.reg_type & REG_D) {
base_opcode = 0xFD000000;
size_log2 = 3;
} else {
tcc_error("str requires a w or x register");
tcc_error("str requires a w, x, or d register");
return;
}
break;
case TOK_ASM_strb:
base_opcode = 0x39000000;
is_64bit = 0;
size_log2 = 0;
break;
case TOK_ASM_strh:
base_opcode = 0x79000000;
is_64bit = 0;
size_log2 = 1;
break;
default:
@ -822,7 +963,81 @@ static void asm_ldst(TCCState *s1, int token)
return;
}
gen_ldst_imm(base_opcode, rt, rn, offset, is_64bit, size_log2);
if (op2.addr_mode != ADDR_OFF)
tcc_error("only offset addressing is implemented for ldr/str");
gen_ldst_imm(base_opcode, rt, rn, offset, size_log2);
}
static void asm_ldst_pair(TCCState *s1, int token)
{
Operand op1, op2, op3;
uint32_t base_opcode;
int size_log2 = 3;
parse_operand(s1, &op1);
if (tok == ',')
next();
parse_operand(s1, &op2);
if (tok == ',')
next();
parse_operand(s1, &op3);
if (!(op3.type & OP_ADDR))
tcc_error("pair load/store requires an address operand");
if ((op1.reg_type & REG_X) && (op2.reg_type & REG_X)) {
if (token == TOK_ASM_stp) {
base_opcode = op3.addr_mode == ADDR_PRE ? 0xA9800000 :
op3.addr_mode == ADDR_POST ? 0xA8800000 :
0xA9000000;
} else {
base_opcode = op3.addr_mode == ADDR_PRE ? 0xA9C00000 :
op3.addr_mode == ADDR_POST ? 0xA8C00000 :
0xA9400000;
}
} else if ((op1.reg_type & REG_D) && (op2.reg_type & REG_D)) {
if (token == TOK_ASM_stp) {
base_opcode = op3.addr_mode == ADDR_PRE ? 0x6D800000 :
op3.addr_mode == ADDR_POST ? 0x6C800000 :
0x6D000000;
} else {
base_opcode = op3.addr_mode == ADDR_PRE ? 0x6DC00000 :
op3.addr_mode == ADDR_POST ? 0x6CC00000 :
0x6D400000;
}
} else {
tcc_error("stp/ldp requires matching x or d registers");
return;
}
gen_ldst_pair(base_opcode, op1.reg, op2.reg, op3.reg, op3.e.v, size_log2);
}
static void asm_sysreg(TCCState *s1, int token)
{
Operand op;
int sysreg;
if (token == TOK_ASM_mrs) {
parse_operand(s1, &op);
if (tok == ',')
next();
sysreg = parse_sysreg_name(tok);
if (sysreg < 0)
tcc_error("unsupported system register");
next();
gen_mrs(op.reg, sysreg);
return;
}
sysreg = parse_sysreg_name(tok);
if (sysreg < 0)
tcc_error("unsupported system register");
next();
if (tok == ',')
next();
parse_operand(s1, &op);
gen_msr(op.reg, sysreg);
}
/* Handle branch instructions */
@ -850,20 +1065,22 @@ static void asm_branch(TCCState *s1, int token)
/* Check for conditional branch */
cond = -1;
switch (token) {
case TOK_ASM_b_eq: cond = 0; break;
case TOK_ASM_b_ne: cond = 1; break;
case TOK_ASM_b_cs: cond = 2; break;
case TOK_ASM_b_cc: cond = 3; break;
case TOK_ASM_b_mi: cond = 4; break;
case TOK_ASM_b_pl: cond = 5; break;
case TOK_ASM_b_vs: cond = 6; break;
case TOK_ASM_b_vc: cond = 7; break;
case TOK_ASM_b_hi: cond = 8; break;
case TOK_ASM_b_ls: cond = 9; break;
case TOK_ASM_b_ge: cond = 10; break;
case TOK_ASM_b_lt: cond = 11; break;
case TOK_ASM_b_gt: cond = 12; break;
case TOK_ASM_b_le: cond = 13; break;
case TOK_ASM_beq: cond = 0; break;
case TOK_ASM_bne: cond = 1; break;
case TOK_ASM_bcs:
case TOK_ASM_bhs: cond = 2; break;
case TOK_ASM_bcc:
case TOK_ASM_blo: cond = 3; break;
case TOK_ASM_bmi: cond = 4; break;
case TOK_ASM_bpl: cond = 5; break;
case TOK_ASM_bvs: cond = 6; break;
case TOK_ASM_bvc: cond = 7; break;
case TOK_ASM_bhi: cond = 8; break;
case TOK_ASM_bls: cond = 9; break;
case TOK_ASM_bge: cond = 10; break;
case TOK_ASM_blt: cond = 11; break;
case TOK_ASM_bgt: cond = 12; break;
case TOK_ASM_ble: cond = 13; break;
}
if (cond >= 0) {
@ -890,20 +1107,22 @@ static void asm_branch(TCCState *s1, int token)
/* Check for conditional branch */
cond = -1;
switch (token) {
case TOK_ASM_b_eq: cond = 0; break;
case TOK_ASM_b_ne: cond = 1; break;
case TOK_ASM_b_cs: cond = 2; break;
case TOK_ASM_b_cc: cond = 3; break;
case TOK_ASM_b_mi: cond = 4; break;
case TOK_ASM_b_pl: cond = 5; break;
case TOK_ASM_b_vs: cond = 6; break;
case TOK_ASM_b_vc: cond = 7; break;
case TOK_ASM_b_hi: cond = 8; break;
case TOK_ASM_b_ls: cond = 9; break;
case TOK_ASM_b_ge: cond = 10; break;
case TOK_ASM_b_lt: cond = 11; break;
case TOK_ASM_b_gt: cond = 12; break;
case TOK_ASM_b_le: cond = 13; break;
case TOK_ASM_beq: cond = 0; break;
case TOK_ASM_bne: cond = 1; break;
case TOK_ASM_bcs:
case TOK_ASM_bhs: cond = 2; break;
case TOK_ASM_bcc:
case TOK_ASM_blo: cond = 3; break;
case TOK_ASM_bmi: cond = 4; break;
case TOK_ASM_bpl: cond = 5; break;
case TOK_ASM_bvs: cond = 6; break;
case TOK_ASM_bvc: cond = 7; break;
case TOK_ASM_bhi: cond = 8; break;
case TOK_ASM_bls: cond = 9; break;
case TOK_ASM_bge: cond = 10; break;
case TOK_ASM_blt: cond = 11; break;
case TOK_ASM_bgt: cond = 12; break;
case TOK_ASM_ble: cond = 13; break;
}
if (cond >= 0) {
@ -1052,25 +1271,32 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
asm_ldst(s1, opcode);
break;
case TOK_ASM_ldp:
case TOK_ASM_stp:
asm_ldst_pair(s1, opcode);
break;
case TOK_ASM_b:
case TOK_ASM_bl:
case TOK_ASM_br:
case TOK_ASM_blr:
case TOK_ASM_ret:
case TOK_ASM_b_eq:
case TOK_ASM_b_ne:
case TOK_ASM_b_cs:
case TOK_ASM_b_cc:
case TOK_ASM_b_mi:
case TOK_ASM_b_pl:
case TOK_ASM_b_vs:
case TOK_ASM_b_vc:
case TOK_ASM_b_hi:
case TOK_ASM_b_ls:
case TOK_ASM_b_ge:
case TOK_ASM_b_lt:
case TOK_ASM_b_gt:
case TOK_ASM_b_le:
case TOK_ASM_beq:
case TOK_ASM_bne:
case TOK_ASM_bcs:
case TOK_ASM_bhs:
case TOK_ASM_bcc:
case TOK_ASM_blo:
case TOK_ASM_bmi:
case TOK_ASM_bpl:
case TOK_ASM_bvs:
case TOK_ASM_bvc:
case TOK_ASM_bhi:
case TOK_ASM_bls:
case TOK_ASM_bge:
case TOK_ASM_blt:
case TOK_ASM_bgt:
case TOK_ASM_ble:
asm_branch(s1, opcode);
break;
@ -1085,6 +1311,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
asm_move_wide(s1, opcode);
break;
case TOK_ASM_mrs:
case TOK_ASM_msr:
asm_sysreg(s1, opcode);
break;
case TOK_ASM_isb:
case TOK_ASM_dsb:
case TOK_ASM_dmb:

View File

@ -374,6 +374,8 @@
DEF_ASM(adrp)
/* System instructions */
DEF_ASM(mrs)
DEF_ASM(msr)
DEF_ASM(nop)
DEF_ASM(wfi)
DEF_ASM(wfe)

View File

@ -13,18 +13,25 @@
.globl __chkstk
__chkstk:
.long 0x910003f0
.long 0xd37cedf1
.long 0xb4000131
.long 0xf1400620
.long 0x540000a9
.long 0xd1400610
.long 0xf940021f
.long 0xd1400631
.long 0x17fffffb
.long 0xcb110210
.long 0xf940021f
.long 0xd65f03c0
/* Windows ARM64 stack probing helper.
arm64-gen.c passes the requested frame size in x15, scaled in 16-byte
units. Probe one 4 KiB page at a time and leave SP unchanged; the caller
subtracts SP after the probe returns. */
mov x16, sp
lsl x17, x15, 4
cbz x17, L_chkstk_done
L_chkstk_loop:
subs x0, x17, 4096
bls L_chkstk_tail
sub x16, x16, 4096
ldr xzr, [x16]
sub x17, x17, 4096
b L_chkstk_loop
L_chkstk_tail:
sub x16, x16, x17
ldr xzr, [x16]
L_chkstk_done:
ret
.globl _(tinyc_getbp)
_(tinyc_getbp):
@ -33,53 +40,57 @@ _(tinyc_getbp):
.globl _(mingw_getsp)
_(mingw_getsp):
.long 0x910003e0
.long 0xd65f03c0
mov x0, sp
ret
.globl _(__mingw_setjmp)
_(__mingw_setjmp):
.long 0xf900001f
.long 0xa9015013
.long 0xa9025815
.long 0xa9036017
.long 0xa9046819
.long 0xa905701b
.long 0xa906781d
.long 0x910003e2
.long 0xf9003802
.long 0xd53b4402
.long 0xb9007802
.long 0xd53b4422
.long 0xb9007c02
.long 0x6d082408
.long 0x6d092c0a
.long 0x6d0a340c
.long 0x6d0b3c0e
.long 0xd2800000
.long 0xd65f03c0
/* _JUMP_BUFFER layout matches win32/include/setjmp.h for _ARM64_:
0x00 Frame, 0x08 Reserved, 0x10-0x68 X19-X30, 0x70 Sp,
0x78 Fpcr/Fpsr, 0x80-0xB8 D8-D15. */
str xzr, [x0] /* Frame = 0 */
stp x19, x20, [x0, 16]
stp x21, x22, [x0, 32]
stp x23, x24, [x0, 48]
stp x25, x26, [x0, 64]
stp x27, x28, [x0, 80]
stp x29, x30, [x0, 96]
mov x2, sp
str x2, [x0, 112] /* Sp */
mrs x2, FPCR
str w2, [x0, 120] /* Fpcr */
mrs x2, FPSR
str w2, [x0, 124] /* Fpsr */
stp d8, d9, [x0, 128]
stp d10, d11, [x0, 144]
stp d12, d13, [x0, 160]
stp d14, d15, [x0, 176]
mov x0, 0
ret
.globl _(__mingw_longjmp)
_(__mingw_longjmp):
.long 0xa9415013
.long 0xa9425815
.long 0xa9436017
.long 0xa9446819
.long 0xa945701b
.long 0xa946781d
.long 0xf9403802
.long 0x9100005f
.long 0xb9407802
.long 0xd51b4402
.long 0xb9407c02
.long 0xd51b4422
.long 0x6d482408
.long 0x6d492c0a
.long 0x6d4a340c
.long 0x6d4b3c0e
.long 0xaa0103e0
.long 0xb5000040
.long 0xd2800020
.long 0xd65f03c0
ldp x19, x20, [x0, 16]
ldp x21, x22, [x0, 32]
ldp x23, x24, [x0, 48]
ldp x25, x26, [x0, 64]
ldp x27, x28, [x0, 80]
ldp x29, x30, [x0, 96]
ldr x2, [x0, 112] /* Sp */
mov sp, x2
ldr w2, [x0, 120] /* Fpcr */
msr FPCR, x2
ldr w2, [x0, 124] /* Fpsr */
msr FPSR, x2
ldp d8, d9, [x0, 128]
ldp d10, d11, [x0, 144]
ldp d12, d13, [x0, 160]
ldp d14, d15, [x0, 176]
mov x0, x1
cbnz x0, L_longjmp_done
mov x0, 1
L_longjmp_done:
ret
/* ---------------------------------------------- */
#elif !defined(__x86_64__)

View File

@ -3,32 +3,32 @@
.global arm64_call_with_dregs
arm64_call_with_dregs:
stp x29, x30, [sp, #-32]!
stp x19, x20, [sp, #16]
stp x29, x30, [sp, -32]!
stp x19, x20, [sp, 16]
mov x29, sp
mov x19, x1
ldr d8, [x0, #0]
ldr d9, [x0, #8]
ldr d10, [x0, #16]
ldr d11, [x0, #24]
ldr d12, [x0, #32]
ldr d13, [x0, #40]
ldr d14, [x0, #48]
ldr d15, [x0, #56]
ldr d8, [x0, 0]
ldr d9, [x0, 8]
ldr d10, [x0, 16]
ldr d11, [x0, 24]
ldr d12, [x0, 32]
ldr d13, [x0, 40]
ldr d14, [x0, 48]
ldr d15, [x0, 56]
mov x0, x3
blr x2
str d8, [x19, #0]
str d9, [x19, #8]
str d10, [x19, #16]
str d11, [x19, #24]
str d12, [x19, #32]
str d13, [x19, #40]
str d14, [x19, #48]
str d15, [x19, #56]
str d8, [x19, 0]
str d9, [x19, 8]
str d10, [x19, 16]
str d11, [x19, 24]
str d12, [x19, 32]
str d13, [x19, 40]
str d14, [x19, 48]
str d15, [x19, 56]
ldp x19, x20, [sp, #16]
ldp x29, x30, [sp], #32
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
ret