diff --git a/arm64-asm.c b/arm64-asm.c index ef9d5d7b..8074ee81 100644 --- a/arm64-asm.c +++ b/arm64-asm.c @@ -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: diff --git a/arm64-tok.h b/arm64-tok.h index 9100290d..51424385 100644 --- a/arm64-tok.h +++ b/arm64-tok.h @@ -374,6 +374,8 @@ DEF_ASM(adrp) /* System instructions */ + DEF_ASM(mrs) + DEF_ASM(msr) DEF_ASM(nop) DEF_ASM(wfi) DEF_ASM(wfe) diff --git a/win32/lib/chkstk.S b/win32/lib/chkstk.S index 2467138b..43e21634 100644 --- a/win32/lib/chkstk.S +++ b/win32/lib/chkstk.S @@ -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__) diff --git a/win32/test_arm64_libtcc_context.S b/win32/test_arm64_libtcc_context.S index eff145d8..d9f21f14 100644 --- a/win32/test_arm64_libtcc_context.S +++ b/win32/test_arm64_libtcc_context.S @@ -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