[PATCH 6/7] aarch64: add PAuth_LR instructions with imm16 operand
Muhammad Kamran <[email protected]>
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
From: Matthieu Longo <[email protected]> Add the immediate PC-relative forms of the FEAT_PAuth_LR instructions: * AUTIA<k>SPPC * RETA<k>SPPC These instructions use an unsigned 16-bit offset field, scaled by 4, to identify a PC-relative instruction address. Add ADDR_UPCREL16 for this operand form and handle it as an assembler-internal fixup, since the offset must be fully resolved by gas and no object-file relocation is emitted. Also update operand printing so disassembly computes the target address using the unsigned backwards PC-relative offset semantics, and add gas tests for valid encodings and diagnostics. Co-authored-by: Muhammad Kamran <[email protected]> CI-tag:skip --- gas/config/tc-aarch64.c | 41 ++++++++++++++++++++++++ gas/testsuite/gas/aarch64/pauth_lr-bad.l | 8 +++++ gas/testsuite/gas/aarch64/pauth_lr-bad.s | 15 +++++++++ gas/testsuite/gas/aarch64/pauth_lr.d | 13 ++++++++ gas/testsuite/gas/aarch64/pauth_lr.s | 17 ++++++++++ include/opcode/aarch64.h | 1 + opcodes/aarch64-opc.c | 7 +++- opcodes/aarch64-tbl.h | 12 +++++++ 8 files changed, 113 insertions(+), 1 deletion(-) diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index f5d57b1d094..d7963b66817 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -5241,6 +5241,12 @@ encode_addsub_imm_shift_amount (uint32_t cnt) return cnt << 22; } +/* Encode the imm16 field of RETA<k>SPPC instruction. */ +static inline uint32_t +encode_pauthauti_imm16 (uint32_t imm) +{ + return imm << 5; +} /* encode the imm field of Adr instruction */ static inline uint32_t @@ -7626,6 +7632,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) case AARCH64_OPND_ADDR_PCREL9: case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_UPCREL16: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: @@ -7680,6 +7687,11 @@ parse_operands (char *str, const aarch64_opcode *opcode) (opcode->op == OP_BL) ? BFD_RELOC_AARCH64_CALL26 : BFD_RELOC_AARCH64_JUMP26; break; + case pauth_lr: + /* e.g. AUTI<k>SPPC or RETA<k>SPPC */ + gas_assert (operands[i] == AARCH64_OPND_ADDR_UPCREL16); + aarch64_set_gas_internal_fixup (&inst.reloc, info, 0); + break; case loadlit: gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19); inst.reloc.type = BFD_RELOC_AARCH64_LD_LO19_PCREL; @@ -9725,6 +9737,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value) { int idx; uint32_t insn; + offsetT offset; char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; enum aarch64_opnd opnd = fixP->tc_fix_data.opnd; aarch64_inst *new_inst = fixP->tc_fix_data.inst; @@ -9877,6 +9890,34 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value) _("immediate offset out of range")); break; + case AARCH64_OPND_ADDR_UPCREL16: + /* immediate offset from a label. */ + if (value > 0) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("negative pc-relative address offset not allowed"\ + " in this context: %ld"), -value); + break; + } + offset = -value; + if (unsigned_overflow (offset, 18)) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("pc-relative address offset out of range: %#lx"), + offset); + break; + } + if (offset & 3) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("pc-relative address offset not word aligned")); + break; + } + insn = get_aarch64_insn (buf); + insn |= encode_pauthauti_imm16 (offset >> 2); + put_aarch64_insn (buf, insn); + break; + default: gas_assert (0); as_fatal (_("unhandled operand code %d"), opnd); diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.l b/gas/testsuite/gas/aarch64/pauth_lr-bad.l index befd2c566d1..3afad8e4327 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr-bad.l +++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.l @@ -8,3 +8,11 @@ .*: Info: retaasppcr x0 .*: Error: unexpected register type at operand 1 -- `retaasppcr sp' .*: Error: unexpected register type at operand 1 -- `retaasppcr xzr' +.*: Error: immediate value must be a multiple of 4 at operand 1 -- `retaasppc 0xff' +.*: Error: immediate value must be a multiple of 4 at operand 1 -- `retaasppc 0x3fffd' +.*: Error: immediate value out of range 0 to 65535 at operand 1 -- `retaasppc 0x4fffc' +.*: Error: immediate value out of range 0 to 65535 at operand 1 -- `retaasppc -0x4' +.*: Error: negative pc-relative address offset not allowed in this context: -12 +.*: Error: undefined symbol external_symbol used as an immediate value +.*: Error: pc-relative address offset out of range: 0x40000 +.*: Error: negative pc-relative address offset not allowed in this context: -12 diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.s b/gas/testsuite/gas/aarch64/pauth_lr-bad.s index 4b4539a9354..25661e4a1d2 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr-bad.s +++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.s @@ -9,3 +9,18 @@ lr_signing: retaasppcr w0 // 32-bit registers not allowed retaasppcr sp // SP not allowed retaasppcr xzr // zero register not allowed + + // Invalid values + retaasppc 0xff // not multiple of 4 + retaasppc 0x3fffd // max value overflowed but might not be detected due to bit shift + retaasppc 0x4fffc // aligned overflow: not possible to represent the value on 16 bits + + retaasppc -0x4 // unsupported negative offset + retaasppc .+0xc // future PC target is invalid: encoded offset would be negative + retaasppc external_symbol + + .balign 0x40000 // NOP filling + + retaasppc lr_signing // the distance between the label and the reta<k>sppc instruction + // is above the limit that can be encoded (=0x3fffc). + retaasppc .+0xc // future PC target is invalid: encoded offset would be negative diff --git a/gas/testsuite/gas/aarch64/pauth_lr.d b/gas/testsuite/gas/aarch64/pauth_lr.d index 93ccfd7ee26..cd224169ea4 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr.d +++ b/gas/testsuite/gas/aarch64/pauth_lr.d @@ -23,3 +23,16 @@ Disassembly of section \.text: .*: d65f0be0 retaasppcr x0 .*: d65f0bfe retaasppcr x30 .*: d65f0fe0 retabsppcr x0 +[^\s]+\s<lr_signing>: + 40: f380001f autiasppc 40 <lr_signing> + 44: f3a0003f autibsppc 40 <lr_signing> + 48: 5500005f retaasppc 40 <lr_signing> + 4c: 5520007f retabsppc 40 <lr_signing> + 50: 5500001f retaasppc 50 <lr_signing\+0x10> + 54: 5500001f retaasppc 54 <lr_signing\+0x14> + 58: 5500003f retaasppc 54 <lr_signing\+0x14> + 5c: 5500011f retaasppc 3c <lr_signing-0x4> + 60: 550002df retaasppc 8 <lr_signing-0x38> +#... + 40000: 55091a7f retaasppc 2dcb4 <lr_signing\+0x2dc74> + 40004: 551fffff retaasppc 8 <lr_signing-0x38> diff --git a/gas/testsuite/gas/aarch64/pauth_lr.s b/gas/testsuite/gas/aarch64/pauth_lr.s index 49585e50e6a..495446b52fb 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr.s +++ b/gas/testsuite/gas/aarch64/pauth_lr.s @@ -29,3 +29,20 @@ retaasppcr x0 retaasppcr x30 retabsppcr x0 + +lr_signing: + autiasppc lr_signing + autibsppc lr_signing + retaasppc lr_signing + retabsppc lr_signing + + retaasppc 0x0 // min: reference to itself + retaasppc .+0x0 // min: current PC + 0 + retaasppc 0x4 // first valid value after min: point to previous instruction + retaasppc 0x20 + retaasppc .-0x58 // point to pacm + + .balign 0x40000 // NOP filling + + retaasppc 0x1234c // a random value in the valid range + retaasppc 0x3fffc // max diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 0248d86f3e4..f61af00aae7 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -732,6 +732,7 @@ enum aarch64_opnd AARCH64_OPND_ADDR_ADRP, /* Memory address for ADRP */ AARCH64_OPND_ADDR_PCREL9, /* 9-bit PC-relative address for e.g. CB<cc>. */ AARCH64_OPND_ADDR_PCREL14, /* 14-bit PC-relative address for e.g. TBZ. */ + AARCH64_OPND_ADDR_UPCREL16, /* unsigned 16-bit PC-relative offset (imm16:'00') for e.g. RETA<k>... */ AARCH64_OPND_ADDR_PCREL19, /* 19-bit PC-relative address for e.g. LDR. */ AARCH64_OPND_ADDR_PCREL21, /* 21-bit PC-relative address for e.g. ADR. */ AARCH64_OPND_ADDR_PCREL26, /* 26-bit PC-relative address for e.g. BL. */ diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 41f38053275..8c6bfb98e6b 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -2132,6 +2132,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, case AARCH64_OPND_ADDR_PCREL9: case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_UPCREL16: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: @@ -4532,10 +4533,14 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, case AARCH64_OPND_ADDR_PCREL9: case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_UPCREL16: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: - addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value; + if (opnd->type == AARCH64_OPND_ADDR_UPCREL16) + addr = pc + AARCH64_PCREL_OFFSET - opnd->imm.value; + else + addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value; if (pcrel_p) *pcrel_p = 1; if (address) diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index 78c4c4e60f7..d6e709f5817 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -1103,6 +1103,12 @@ QLF4(V_16B, V_16B, V_16B, imm_0_15), \ } +/* e.g. AUTI<k>SPPC <label_imm16:00> */ +#define QL_PAUTH_IMM16 \ +{ \ + QLF1(NIL), \ +} + /* e.g. AUTI<k>SPPCR Xn */ #define QL_PAUTH_REG \ { \ @@ -4436,6 +4442,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = PAUTH_INSN ("eretab", 0xd69f0fff, 0xffffffff, branch_reg, OP0 (), QL_0, F_BRANCH_RET), PAUTH_LR_INSN ("retaasppcr", 0xd65f0be0, 0xffffffe0, pauth_lr, OP1 (Rd), QL_PAUTH_REG, F_BRANCH_RET), PAUTH_LR_INSN ("retabsppcr", 0xd65f0fe0, 0xffffffe0, pauth_lr, OP1 (Rd), QL_PAUTH_REG, F_BRANCH_RET), + PAUTH_LR_INSN ("retaasppc", 0x5500001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_BRANCH_RET), + PAUTH_LR_INSN ("retabsppc", 0x5520001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_BRANCH_RET), /* Compare & branch (immediate). */ CORE_INSN ("cbz", 0x34000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF), CORE_INSN ("cbnz", 0x35000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF), @@ -4543,6 +4551,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = PAUTH_INSN ("autdb", 0xdac11c00, 0xfffffc00, dp_1src, OP2 (Rd, Rn_SP), QL_I2SAMEX, 0), PAUTH_LR_INSN ("autiasppcr", 0xdac1901e, 0xfffffc1f, pauth_lr, OP1 (Rn), QL_PAUTH_REG, F_SUBCLASS_OTHER), PAUTH_LR_INSN ("autibsppcr", 0xdac1941e, 0xfffffc1f, pauth_lr, OP1 (Rn), QL_PAUTH_REG, F_SUBCLASS_OTHER), + PAUTH_LR_INSN ("autiasppc", 0xf380001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_SUBCLASS_OTHER), + PAUTH_LR_INSN ("autibsppc", 0xf3a0001f, 0xffe0001f, pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, F_SUBCLASS_OTHER), PAUTH_LR_INSN ("autia171615", 0xdac1bbfe, 0xffffffff, pauth_lr, OP0 (), {}, F_SUBCLASS_OTHER), PAUTH_LR_INSN ("autib171615", 0xdac1bffe, 0xffffffff, pauth_lr, OP0 (), {}, F_SUBCLASS_OTHER), PAUTH_INSN ("paciza", 0xdac123e0, 0xffffffe0, dp_1src, OP1 (Rd), QL_I1X, 0), @@ -8184,6 +8194,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = F(FLD(5, 9)), "9-bit PC-relative address") \ Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \ F(FLD(5, 14)), "14-bit PC-relative address") \ + Y(ADDRESS, imm, "ADDR_UPCREL16", OPD_F_SHIFT_BY_2 | OPD_F_UNSIGNED, \ + F(FLD(5, 16)), "unsigned 16-bit PC-relative offset (imm16:'00')") \ Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \ F(FLD(5, 19)), "19-bit PC-relative address") \ Y(ADDRESS, imm, "ADDR_PCREL21", OPD_F_SEXT, F(FLD(5, 19), FLD(29, 2)), \ -- 2.43.0