diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 000564672df..0c48e20f013 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -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)) diff --git a/bfd/reloc.c b/bfd/reloc.c index a187afe9b56..d9386a7fdc7 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -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 AUTISPPC 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 diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index f69b0b0c0e2..9115e20a186 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -5123,6 +5123,12 @@ encode_addsub_imm_shift_amount (uint32_t cnt) return cnt << 22; } +/* encode the imm16 field of RETASPPC 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. AUTISPPC or RETASPPC */ + 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) { diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.l b/gas/testsuite/gas/aarch64/pauth_lr-bad.l index d0a629f216f..184e3f8398f 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr-bad.l +++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.l @@ -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 diff --git a/gas/testsuite/gas/aarch64/pauth_lr-bad.s b/gas/testsuite/gas/aarch64/pauth_lr-bad.s index 98840d4c257..32f5c4b65cf 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr-bad.s +++ b/gas/testsuite/gas/aarch64/pauth_lr-bad.s @@ -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 retasppc 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] diff --git a/gas/testsuite/gas/aarch64/pauth_lr.d b/gas/testsuite/gas/aarch64/pauth_lr.d index ddd65b77fd1..ab5700897dc 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr.d +++ b/gas/testsuite/gas/aarch64/pauth_lr.d @@ -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: + 3c: f380001f autiasppc 3c + 40: f3a0003f autibsppc 3c + 44: 5500005f retaasppc 3c + 48: 5520007f retabsppc 3c + 4c: 5500001f retaasppc 4c + 50: 5500001f retaasppc 50 + 54: 5500003f retaasppc 50 + 58: 5500011f retaasppc 38 + 5c: 550002df retaasppc 4 +#... + 40000: 55091a7f retaasppc 2dcb4 + 40004: 551fffff retaasppc 8 diff --git a/gas/testsuite/gas/aarch64/pauth_lr.s b/gas/testsuite/gas/aarch64/pauth_lr.s index cdedd6e4588..3f57559d3df 100644 --- a/gas/testsuite/gas/aarch64/pauth_lr.s +++ b/gas/testsuite/gas/aarch64/pauth_lr.s @@ -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 diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 81c9b1f1220..4661dc83e17 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -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... */ 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 ad5dfdc27b6..9848e15392a 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -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: diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index ef7b69e4970..58d294b0d33 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -1034,6 +1034,12 @@ QLF4(V_16B, V_16B, V_16B, imm_0_15), \ } +/* e.g. AUTISPPC */ +#define QL_PAUTH_IMM16 \ +{ \ + QLF1(imm_0_15), \ +} + /* e.g. AUTISPPCR 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), \