@@ -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);
@@ -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
@@ -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
@@ -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>
@@ -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
@@ -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. */
@@ -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)
@@ -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)), \