@@ -431,7 +431,7 @@ elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_TLSDESC_ENTRY_SIZE] =
/* Indexed by the bfd interal reloc enumerators.
Therefore, the table needs to be synced with BFD_RELOC_AARCH64_*
- in reloc.c. */
+ in bfd/reloc.c, and with a RELOC_NUMBER in include/elf/aarch64.h */
static reloc_howto_type elfNN_aarch64_howto_table[] =
{
@@ -822,6 +822,8 @@ static reloc_howto_type elfNN_aarch64_howto_table[] =
0xffff, /* dst_mask */
true), /* pcrel_offset */
+ EMPTY_HOWTO (0), // BFD_RELOC_AARCH64_AUTI_LO16_PCREL
+
/* Relocations to generate 19, 21 and 33 bit PC-relative load/store
addresses: PG(x) is (x & ~0xfff). */
@@ -8262,7 +8264,7 @@ elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
return 0;
size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
-
+
if (!(sym->flags & BSF_SYNTHETIC))
switch (ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info))
{
@@ -8280,7 +8282,7 @@ elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
default:
return 0;
}
-
+
if ((sym->flags & BSF_LOCAL)
&& bfd_is_aarch64_special_symbol_name (sym->name,
BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))
@@ -6776,6 +6776,7 @@ ENUMDOC
This is a 64 bit reloc that stores the 32 bit offset value in two
words (with an imm instruction). The relocation is relative offset
from start of TEXT.
+
ENUM
BFD_RELOC_KVX_RELOC_START
ENUMDOC
@@ -6961,6 +6962,7 @@ ENUMDOC
a few more enumerators after this one; those are mainly used by the
KVX assembler for the internal fixup or to select one of the above
enumerators.
+
ENUM
BFD_RELOC_AARCH64_RELOC_START
ENUMDOC
@@ -6968,6 +6970,11 @@ ENUMDOC
relocation enumerators. N.B. the order of the enumerators is
important as several tables in the AArch64 bfd backend are indexed
by these enumerators; make sure they are all synced.
+ - bfd/elfnn-aarch64.c:elfNN_aarch64_howto_table
+ If the reloc is local and does not require bfd, fill in the gap
+ with EMPTY_HOWTO (0).
+ - include/elf/aarch64.h:RELOC_NUMBER
+ If the reloc does not depend on elf, you can skip this.
ENUM
BFD_RELOC_AARCH64_NULL
ENUMDOC
@@ -7085,6 +7092,12 @@ ENUM
ENUMDOC
AArch64 MOVK instruction with most significant bits 47 to 63 of a
signed value.
+ENUM
+ BFD_RELOC_AARCH64_AUTI_LO16_PCREL
+ENUMDOC
+ AArch64 AUTI<k>SPPC instructions, holding a 16 bit pc-relative word
+ offset. The lowest two bits must be zero and are not stored in the
+ instruction, giving a 18 bit unsigned byte offset.
ENUM
BFD_RELOC_AARCH64_LD_LO19_PCREL
ENUMDOC
@@ -7309,7 +7322,7 @@ ENUM
BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC
ENUMDOC
Similar to BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no
- overflow check.
+ overflow check.
ENUM
BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12
ENUMDOC
@@ -7525,6 +7538,7 @@ ENUM
ENUMDOC
AArch64 pseudo relocation code to be used internally by the AArch64
assembler and not (currently) written to any object files.
+
ENUM
BFD_RELOC_TILEPRO_COPY
ENUMX
@@ -7685,6 +7699,7 @@ ENUMX
BFD_RELOC_TILEPRO_IMM16_X1_TLS_LE_HA
ENUMDOC
Tilera TILEPro Relocations.
+
ENUM
BFD_RELOC_TILEGX_HW0
ENUMX
@@ -5123,6 +5123,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
@@ -7413,6 +7419,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
break;
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:
@@ -7464,6 +7471,11 @@ parse_operands (char *str, const aarch64_opcode *opcode)
(opcode->op == OP_BL) ? BFD_RELOC_AARCH64_CALL26
: BFD_RELOC_AARCH64_JUMP26;
break;
+ case ic_pauth_lr:
+ /* e.g. AUTI<k>SPPC or RETA<k>SPPC */
+ gas_assert (operands[i] == AARCH64_OPND_ADDR_UPCREL16);
+ inst.reloc.type = BFD_RELOC_AARCH64_AUTI_LO16_PCREL;
+ break;
case loadlit:
gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19);
inst.reloc.type = BFD_RELOC_AARCH64_LD_LO19_PCREL;
@@ -9639,6 +9651,41 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
}
break;
+ case BFD_RELOC_AARCH64_AUTI_LO16_PCREL:
+ if (fixP->fx_done)
+ {
+ // FIXME: I don't think this inversion should be done here. There
+ // should be a better generic mechanism to handle unsigned relative
+ // offsets. However, I am not sure yet where to add it, and the
+ // complexity of the change.
+ unsigned long value_ = (unsigned long) -value;
+ if (value > 0)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("negative pc-relative address offset not allowed"\
+ " in this context: %ld"), -value);
+ else if (unsigned_overflow(value_, 18))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("pc-relative address offset out of range: %#lx"), value_);
+ if (value_ & 3)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("pc-relative address offset not word aligned"));
+ insn = get_aarch64_insn (buf);
+ insn |= encode_pauthauti_imm16 (value_ >> 2);
+ put_aarch64_insn (buf, insn);
+ }
+ else
+ {
+ // The symbold is probably external or undeclared. This is unsupported
+ // for this relocation type which is only used for computing the
+ // PC-relative offset, but does no relocation.
+ gas_assert (fixP->fx_addsy && !S_IS_DEFINED (fixP->fx_addsy));
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("undefined symbol %s used as an immediate value"),
+ S_GET_NAME (fixP->fx_addsy));
+ goto apply_fix_return;
+ }
+ break;
+
case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
if (fixP->fx_done || !seg->use_rela_p)
{
@@ -8,4 +8,12 @@
.*: Info: did you mean this\?
.*: Info: retaasppcr x0
.*: Error: unexpected register type at operand 1 -- `retaasppcr sp'
-.*: Error: unexpected register type at operand 1 -- `retaasppcr xzr'
\ No newline at end of file
+.*: 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
@@ -10,3 +10,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 // it should be impossible to jump before .text [NOK. FIXME: . notation seems to be taken into account as expected]
+ 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 // current PC + offset is above the limit that can be encoded. [NOK. FIXME: . notation seems to be taken into account as expected]
@@ -21,4 +21,17 @@ Disassembly of section \.text:
.*: dac1941e autibsppcr x0
.*: d65f0be0 retaasppcr x0
.*: d65f0bfe retaasppcr x30
-.*: d65f0fe0 retabsppcr x0
\ No newline at end of file
+.*: d65f0fe0 retabsppcr x0
+[^\s]+\s<lr_signing>:
+ 3c: f380001f autiasppc 3c <lr_signing>
+ 40: f3a0003f autibsppc 3c <lr_signing>
+ 44: 5500005f retaasppc 3c <lr_signing>
+ 48: 5520007f retabsppc 3c <lr_signing>
+ 4c: 5500001f retaasppc 4c <lr_signing\+0x10>
+ 50: 5500001f retaasppc 50 <lr_signing\+0x14>
+ 54: 5500003f retaasppc 50 <lr_signing\+0x14>
+ 58: 5500011f retaasppc 38 <lr_signing-0x4>
+ 5c: 550002df retaasppc 4 <lr_signing-0x38>
+#...
+ 40000: 55091a7f retaasppc 2dcb4 <lr_signing\+0x2dc78>
+ 40004: 551fffff retaasppc 8 <lr_signing-0x34>
@@ -28,3 +28,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
@@ -639,6 +639,7 @@ enum aarch64_opnd
AARCH64_OPND_ADDR_ADRP, /* Memory address for ADRP */
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. */
@@ -2383,6 +2383,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
break;
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:
@@ -4730,19 +4731,26 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
break;
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 (pcrel_p)
- *pcrel_p = 1;
- if (address)
- *address = addr;
- /* This is not necessary during the disassembling, as print_address_func
- in the disassemble_info will take care of the printing. But some
- other callers may be still interested in getting the string in *STR,
- so here we do snprintf regardless. */
- snprintf (buf, size, "%s", style_addr (styler, "#0x%" PRIx64, addr));
+ {
+ const aarch64_operand *operand = get_operand_from_code (opnd->type);
+ if (operand_need_unsigned_offset (operand))
+ 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)
+ *address = addr;
+ /* This is not necessary during the disassembling, as print_address_func
+ in the disassemble_info will take care of the printing. But some
+ other callers may be still interested in getting the string in *STR,
+ so here we do snprintf regardless. */
+ snprintf (buf, size, "%s", style_addr (styler, "#0x%" PRIx64, addr));
+ }
break;
case AARCH64_OPND_ADDR_SIMPLE:
@@ -1034,6 +1034,12 @@
QLF4(V_16B, V_16B, V_16B, imm_0_15), \
}
+/* e.g. AUTI<k>SPPC <label_imm16:00> */
+#define QL_PAUTH_IMM16 \
+{ \
+ QLF1(imm_0_15), \
+}
+
/* e.g. AUTI<k>SPPCR Xn */
#define QL_PAUTH_REG \
{ \
@@ -3896,6 +3902,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
PAUTH_INSN ("eretab", 0xd69f0fff, 0xffffffff, branch_reg, OP0 (), {}, 0),
PAUTH_LR_INSN ("retaasppcr", 0xd65f0be0, 0xffffffe0, ic_pauth_lr, OP1 (Rd), QL_PAUTH_REG, 0),
PAUTH_LR_INSN ("retabsppcr", 0xd65f0fe0, 0xffffffe0, ic_pauth_lr, OP1 (Rd), QL_PAUTH_REG, 0),
+ PAUTH_LR_INSN ("retaasppc", 0x5500001f, 0xffe0001f, ic_pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, 0),
+ PAUTH_LR_INSN ("retabsppc", 0x5520001f, 0xffe0001f, ic_pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, 0),
/* 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),
@@ -3959,6 +3967,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, ic_pauth_lr, OP1 (Rn), QL_PAUTH_REG, 0),
PAUTH_LR_INSN ("autibsppcr", 0xdac1941e, 0xfffffc1f, ic_pauth_lr, OP1 (Rn), QL_PAUTH_REG, 0),
+ PAUTH_LR_INSN ("autiasppc", 0xf380001f, 0xffe0001f, ic_pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, 0),
+ PAUTH_LR_INSN ("autibsppc", 0xf3a0001f, 0xffe0001f, ic_pauth_lr, OP1 (ADDR_UPCREL16), QL_PAUTH_IMM16, 0),
PAUTH_LR_INSN ("autia171615", 0xdac1bbfe, 0xffffffff, ic_system, OP0 (), {}, 0),
PAUTH_LR_INSN ("autib171615", 0xdac1bffe, 0xffffffff, ic_system, OP0 (), {}, 0),
PAUTH_INSN ("paciza", 0xdac123e0, 0xffffffe0, dp_1src, OP1 (Rd), QL_I1X, 0),
@@ -7003,6 +7013,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
"21-bit PC-relative address of a 4KB page") \
Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \
F(FLD_imm14), "14-bit PC-relative address") \
+ Y(ADDRESS, imm, "ADDR_UPCREL16", OPD_F_SHIFT_BY_2 | OPD_F_UNSIGNED, \
+ F(FLD_imm16_5), "unsigned 16-bit PC-relative offset (imm16:'00')")\
Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2, \
F(FLD_imm19), "19-bit PC-relative address") \
Y(ADDRESS, imm, "ADDR_PCREL21", OPD_F_SEXT, F(FLD_immhi,FLD_immlo), \