From: Siddhesh Poyarekar Date: Fri, 11 Sep 2020 03:48:07 +0000 (+0530) Subject: [Morello] LDR immediate X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7855d7bd2f98c0d00f40f9cd54012da6cc0b7521;p=thirdparty%2Fbinutils-gdb.git [Morello] LDR immediate The 17-bit signed offset needs to be 16-byte aligned, but the PCC-relative address resolution rounds down the final address to the 16-byte boundary. Due to this, disassembly of the instruction will show as if it is loading from the middle of an object. bfd/ChangeLog: 2020-10-20 Siddhesh Poyarekar * elfnn-aarch64.c (elfNN_aarch64_howto_table): Add LD_PREL_LO17. (elfNN_aarch64_final_link_relocate, elfNN_aarch64_check_relocs): Likewise. * elfxx-aarch64.c (reencode_ld_lit_ofs_17): New function. (_bfd_aarch64_elf_put_addend, _bfd_aarch64_elf_resolve_relocation): Add LD_PREL_LO17. * libbfd.h (bfd_reloc_code_real_names): Add BFD_RELOC_MORELLO_LD_LO17_PCREL. * reloc.c: Add BFD_RELOC_AARCH64_LD_LO17_PCREL. * bfd-in2.h: Regenerate. gas/ChangeLog: 2020-10-20 Siddhesh Poyarekar * config/tc-aarch64.c (encode_ld_lit_ofs_17): New function. (parse_operands, programmer_friendly_fixup, md_apply_fix): Add ADDR_PCREL17. include/ChangeLog: 2020-10-20 Siddhesh Poyarekar * elf/aarch64.h: New relocation R_MORELLO_LD_PREL_LO17. * opcode/aarch64.h (aarch64_opnd): Add ADDR_PCREL17. (aarch64_op): Add OP_LDR_LIT_2. opcodes/ChangeLog: 2020-10-20 Siddhesh Poyarekar * aarch64-asm-2.c: Regenerate. * aarch64-dis-2.c: Regenerate. * aarch64-opc-2.c: Regenerate. * aarch64-opc.c (fields): Add imm17. (operand_general_constraint_met_p, aarch64_print_operand): Add ADDR_PCREL17. * aarch64-opc.h (aarch64_field_kind): Add FLD_imm17. * aarch64-tbl.h (QL2_A64C_CA_PCREL): New macro. (aarch64_opcode_table): New instruction. (AARCH64_OPERANDS): New operand. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 0a5aa97aed2..3c21dd46f34 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2020-10-20 Siddhesh Poyarekar + + * elfnn-aarch64.c (elfNN_aarch64_howto_table): Add + LD_PREL_LO17. + (elfNN_aarch64_final_link_relocate, + elfNN_aarch64_check_relocs): Likewise. + * elfxx-aarch64.c (reencode_ld_lit_ofs_17): New function. + (_bfd_aarch64_elf_put_addend, + _bfd_aarch64_elf_resolve_relocation): Add LD_PREL_LO17. + * libbfd.h (bfd_reloc_code_real_names): Add + BFD_RELOC_MORELLO_LD_LO17_PCREL. + * reloc.c: Add BFD_RELOC_AARCH64_LD_LO17_PCREL. + * bfd-in2.h: Regenerate. + 2020-10-20 Siddhesh Poyarekar * elf-bfd.h (bfd_elf_section_data): New member diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index c0b563aec02..812bd07f0ac 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5615,6 +5615,11 @@ of a signed value. */ of a signed value. */ BFD_RELOC_AARCH64_MOVW_PREL_G3, +/* AArch64 A64C Load Literal instruction, holding a 17 bit pc-relative +word offset. The lowest four bits must be zero and are not stored in +the instruction, giving a 21 bit signed byte offset. */ + BFD_RELOC_MORELLO_LD_LO17_PCREL, + /* AArch64 Load Literal instruction, holding a 19 bit pc-relative word offset. The lowest two bits must be zero and are not stored in the instruction, giving a 21 bit signed byte offset. */ diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 70d19a27468..52b80334079 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -157,6 +157,9 @@ #define BFD_RELOC_AARCH64_TLSDESC_LD64_LO12_NC BFD_RELOC_AARCH64_TLSDESC_LD64_LO12 #endif +#define MORELLO_R(NAME) R_MORELLO_ ## NAME +#define MORELLO_R_STR(NAME) "R_MORELLO_" #NAME + #if ARCH_SIZE == 32 #define AARCH64_R(NAME) R_AARCH64_P32_ ## NAME #define AARCH64_R_STR(NAME) "R_AARCH64_P32_" #NAME @@ -825,6 +828,21 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = /* Relocations to generate 19, 21 and 33 bit PC-relative load/store addresses: PG(x) is (x & ~0xfff). */ + /* LD-lit: ((S+A-P) >> 4) & 0x1ffff */ + HOWTO64 (MORELLO_R (LD_PREL_LO17), /* type */ + 4, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 17, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + MORELLO_R_STR (LD_PREL_LO17), /* name */ + false, /* partial_inplace */ + 0x1ffff, /* src_mask */ + 0x1ffff, /* dst_mask */ + true), /* pcrel_offset */ + /* LD-lit: ((S+A-P) >> 2) & 0x7ffff */ HOWTO (AARCH64_R (LD_PREL_LO19), /* type */ 2, /* rightshift */ @@ -5939,6 +5957,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, case BFD_RELOC_AARCH64_ADR_HI21_PCREL: case BFD_RELOC_AARCH64_ADR_LO21_PCREL: case BFD_RELOC_AARCH64_LD_LO19_PCREL: + case BFD_RELOC_MORELLO_LD_LO17_PCREL: case BFD_RELOC_AARCH64_MOVW_PREL_G0: case BFD_RELOC_AARCH64_MOVW_PREL_G0_NC: case BFD_RELOC_AARCH64_MOVW_PREL_G1: @@ -7844,6 +7863,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, case BFD_RELOC_AARCH64_LDST64_LO12: case BFD_RELOC_AARCH64_LDST8_LO12: case BFD_RELOC_AARCH64_LD_LO19_PCREL: + case BFD_RELOC_MORELLO_LD_LO17_PCREL: if (h == NULL || bfd_link_pic (info)) break; /* Fall through. */ diff --git a/bfd/elfxx-aarch64.c b/bfd/elfxx-aarch64.c index 63be6dc0e6e..3e57a97683d 100644 --- a/bfd/elfxx-aarch64.c +++ b/bfd/elfxx-aarch64.c @@ -84,6 +84,13 @@ reencode_cond_branch_ofs_19 (uint32_t insn, uint32_t ofs) return (insn & ~(MASK (19) << 5)) | ((ofs & MASK (19)) << 5); } +/* Decode the 17-bit offset of A64C load literal. */ +static inline uint32_t +reencode_ld_lit_ofs_17 (uint32_t insn, uint32_t ofs) +{ + return (insn & ~(MASK (17) << 5)) | ((ofs & MASK (17)) << 5); +} + /* Decode the 19-bit offset of load literal. */ static inline uint32_t reencode_ld_lit_ofs_19 (uint32_t insn, uint32_t ofs) @@ -222,6 +229,12 @@ _bfd_aarch64_elf_put_addend (bfd *abfd, contents = reencode_tst_branch_ofs_14 (contents, addend); break; + case BFD_RELOC_MORELLO_LD_LO17_PCREL: + if (old_addend & ((1 << howto->rightshift) - 1)) + addend++; + contents = reencode_ld_lit_ofs_17 (contents, addend); + break; + case BFD_RELOC_AARCH64_GOT_LD_PREL19: case BFD_RELOC_AARCH64_LD_LO19_PCREL: case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19: @@ -407,6 +420,7 @@ _bfd_aarch64_elf_resolve_relocation (bfd *input_bfd, case BFD_RELOC_AARCH64_TLSDESC_CALL: break; + case BFD_RELOC_MORELLO_LD_LO17_PCREL: case BFD_RELOC_AARCH64_16_PCREL: case BFD_RELOC_AARCH64_32_PCREL: case BFD_RELOC_AARCH64_64_PCREL: diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 6e62e556962..a6adcad23b1 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -3035,6 +3035,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_AARCH64_MOVW_PREL_G2", "BFD_RELOC_AARCH64_MOVW_PREL_G2_NC", "BFD_RELOC_AARCH64_MOVW_PREL_G3", + "BFD_RELOC_MORELLO_LD_LO17_PCREL", "BFD_RELOC_AARCH64_LD_LO19_PCREL", "BFD_RELOC_AARCH64_ADR_LO21_PCREL", "BFD_RELOC_AARCH64_ADR_HI21_PCREL", diff --git a/bfd/reloc.c b/bfd/reloc.c index 164060361a9..f2a9f0d436e 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -7115,6 +7115,12 @@ ENUM ENUMDOC AArch64 MOVK instruction with most significant bits 47 to 63 of a signed value. +ENUM + BFD_RELOC_MORELLO_LD_LO17_PCREL +ENUMDOC + AArch64 A64C Load Literal instruction, holding a 17 bit pc-relative + word offset. The lowest four bits must be zero and are not stored in + the instruction, giving a 21 bit signed byte offset. ENUM BFD_RELOC_AARCH64_LD_LO19_PCREL ENUMDOC diff --git a/gas/ChangeLog b/gas/ChangeLog index 59409d2f62e..345914f0cb2 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2020-10-20 Siddhesh Poyarekar + + * config/tc-aarch64.c (encode_ld_lit_ofs_17): New function. + (parse_operands, programmer_friendly_fixup, md_apply_fix): Add + ADDR_PCREL17. + 2020-10-20 Siddhesh Poyarekar * config/tc-aarch64.c (parse_operands, fix_insn): Add diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 373c8c1eea0..cb7034a41b1 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -5022,6 +5022,13 @@ encode_cond_branch_ofs_19 (uint32_t ofs) return (ofs & ((1 << 19) - 1)) << 5; } +/* encode the 17-bit offset of ld literal */ +static inline uint32_t +encode_ld_lit_ofs_17 (uint32_t ofs) +{ + return (ofs & ((1 << 17) - 1)) << 5; +} + /* encode the 19-bit offset of ld literal */ static inline uint32_t encode_ld_lit_ofs_19 (uint32_t ofs) @@ -7147,6 +7154,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) break; case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_PCREL17: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: @@ -7202,8 +7210,11 @@ parse_operands (char *str, const aarch64_opcode *opcode) : BFD_RELOC_AARCH64_JUMP26; break; case loadlit: - gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19); - inst.reloc.type = BFD_RELOC_AARCH64_LD_LO19_PCREL; + gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19 + || operands[i] == AARCH64_OPND_ADDR_PCREL17); + inst.reloc.type = (operands[i] == AARCH64_OPND_ADDR_PCREL19 + ? BFD_RELOC_AARCH64_LD_LO19_PCREL + : BFD_RELOC_MORELLO_LD_LO17_PCREL); break; case pcreladdr: gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL21); @@ -7994,7 +8005,8 @@ programmer_friendly_fixup (aarch64_instruction *instr) nearby literal pool and generate a hidden label which references it. ISREG has been set to 0 in the case of =value. */ if (instr->gen_lit_pool - && (op == OP_LDR_LIT || op == OP_LDRV_LIT || op == OP_LDRSW_LIT)) + && (op == OP_LDR_LIT || op == OP_LDRV_LIT || op == OP_LDRSW_LIT + || op == OP_LDR_LIT_2)) { int size = aarch64_get_qualifier_esize (operands[0].qualifier); if (op == OP_LDRSW_LIT) @@ -9195,6 +9207,25 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg) fix_insn (fixP, flags, value); break; + case BFD_RELOC_MORELLO_LD_LO17_PCREL: + if (fixP->fx_done || !seg->use_rela_p) + { + /* The LDR-immediate that uses LO17 aligns the address down to + 16-byte boundary to get the final address of the capability. + Since the fixed up immediate also needs to be 16-byte aligned, + align it up to the 16-byte boundary so that the downward alignment + of the load literal instruction gets us the correct address. */ + value = (value + 0xf) & ~(offsetT) 0xf; + + if (signed_overflow (value, 21)) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("pcc-relative load offset out of range")); + insn = get_aarch64_insn (buf); + insn |= encode_ld_lit_ofs_17 (value >> 4); + put_aarch64_insn (buf, insn); + } + break; + case BFD_RELOC_AARCH64_LD_LO19_PCREL: if (fixP->fx_done || !seg->use_rela_p) { diff --git a/include/ChangeLog b/include/ChangeLog index 0195f044bc9..4604eaece79 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,9 @@ +2020-10-20 Siddhesh Poyarekar + + * elf/aarch64.h: New relocation R_MORELLO_LD_PREL_LO17. + * opcode/aarch64.h (aarch64_opnd): Add ADDR_PCREL17. + (aarch64_op): Add OP_LDR_LIT_2. + 2020-10-20 Siddhesh Poyarekar * opcode/aarch64.h (aarch64_opnd): Add A64C_ADDR_SIMM7. diff --git a/include/elf/aarch64.h b/include/elf/aarch64.h index ec04bb6a17b..b29a1c8161d 100644 --- a/include/elf/aarch64.h +++ b/include/elf/aarch64.h @@ -445,6 +445,11 @@ RELOC_NUMBER (R_AARCH64_TLS_TPREL, 1030) RELOC_NUMBER (R_AARCH64_TLSDESC, 1031) RELOC_NUMBER (R_AARCH64_IRELATIVE, 1032) +/* Morello Relocations. */ + +/* A64C LD-lit: ((S+A-P) >> 4) & 0x1ffff */ +RELOC_NUMBER (R_MORELLO_LD_PREL_LO17, 57348) + END_RELOC_NUMBERS (R_AARCH64_end) enum aarch64_st_branch_type diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index e563c111414..716e0e3b34e 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -530,6 +530,7 @@ enum aarch64_opnd BLR/BR. */ AARCH64_OPND_CAPADDR_SIMPLE, /* Simple base address with no offset. */ AARCH64_OPND_A64C_ADDR_SIMM7, /* Address with 7-bit immediate offset. */ + AARCH64_OPND_ADDR_PCREL17, /* 17-bit PC-relative address for e.g. LDR. */ }; /* Qualifier constrains an operand. It either specifies a variant of an @@ -761,6 +762,7 @@ enum aarch64_op OP_PRFUM, OP_LDR_LIT, + OP_LDR_LIT_2, OP_LDRV_LIT, OP_LDRSW_LIT, OP_PRFM_LIT, diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 7b9cd529a55..64979cf399f 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,16 @@ +2020-10-20 Siddhesh Poyarekar + + * aarch64-asm-2.c: Regenerate. + * aarch64-dis-2.c: Regenerate. + * aarch64-opc-2.c: Regenerate. + * aarch64-opc.c (fields): Add imm17. + (operand_general_constraint_met_p, aarch64_print_operand): Add + ADDR_PCREL17. + * aarch64-opc.h (aarch64_field_kind): Add FLD_imm17. + * aarch64-tbl.h (QL2_A64C_CA_PCREL): New macro. + (aarch64_opcode_table): New instruction. + (AARCH64_OPERANDS): New operand. + 2020-10-20 Siddhesh Poyarekar * aarch64-asm-2.c: Regenerate. diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index dcf094620ef..44f69cdbd6b 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -359,6 +359,7 @@ const aarch64_field fields[] = { 13, 2 }, /* form: form specifier in seal. */ { 13, 7 }, /* capaddr_simm7: Signed immediate for BLR/BR. */ { 30, 1 }, /* a64c_index2: in ld/st pair inst deciding the pre/post-index. */ + { 5, 17 }, /* imm17: in ld/st pair inst deciding the pre/post-index. */ }; enum aarch64_operand_class @@ -1913,31 +1914,43 @@ operand_general_constraint_met_p (aarch64_feature_set features, break; case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_PCREL17: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: - imm = opnd->imm.value; - if (operand_need_shift_by_two (get_operand_from_code (type))) { - /* The offset value in a PC-relative branch instruction is alway - 4-byte aligned and is encoded without the lowest 2 bits. */ - if (!value_aligned_p (imm, 4)) + int shift_amt = 0; + const aarch64_operand *op = get_operand_from_code (type); + if (operand_need_shift_by_two (op)) + shift_amt = 2; + else if (operand_need_shift_by_four (op)) + shift_amt = 4; + + imm = opnd->imm.value; + + if (shift_amt > 0) + { + /* The offset value in a PC-relative (or PCC-relative) branch + instruction is always encoded without the lowest alignment + bits, i.e. 2 bits for PC and 4 bits for PCC. */ + if (!value_aligned_p (imm, 1 << shift_amt)) + { + set_unaligned_error (mismatch_detail, idx, 1 << shift_amt); + return 0; + } + /* Right shift by 2 so that we can carry out the following check + canonically. */ + imm >>= shift_amt; + } + size = get_operand_fields_width (get_operand_from_code (type)); + if (!value_fit_signed_field_p (imm, size)) { - set_unaligned_error (mismatch_detail, idx, 4); + set_other_error (mismatch_detail, idx, + _("immediate out of range")); return 0; } - /* Right shift by 2 so that we can carry out the following check - canonically. */ - imm >>= 2; - } - size = get_operand_fields_width (get_operand_from_code (type)); - if (!value_fit_signed_field_p (imm, size)) - { - set_other_error (mismatch_detail, idx, - _("immediate out of range")); - return 0; + break; } - break; case AARCH64_OPND_SME_ADDR_RI_U4xVL: if (!value_in_range_p (opnd->addr.offset.imm, 0, 15)) @@ -3873,10 +3886,17 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, break; case AARCH64_OPND_ADDR_PCREL14: + case AARCH64_OPND_ADDR_PCREL17: case AARCH64_OPND_ADDR_PCREL19: case AARCH64_OPND_ADDR_PCREL21: case AARCH64_OPND_ADDR_PCREL26: addr = pc + AARCH64_PCREL_OFFSET + opnd->imm.value; + + /* For A64C PCREL17, the final address is rounded down to align to + capability boundary. */ + if (opnd->type == AARCH64_OPND_ADDR_PCREL17) + addr = addr & ~(uint64_t) 0xf; + if (pcrel_p) *pcrel_p = 1; if (address) diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h index a774d38f820..78bd4d801f3 100644 --- a/opcodes/aarch64-opc.h +++ b/opcodes/aarch64-opc.h @@ -182,6 +182,7 @@ enum aarch64_field_kind FLD_form, FLD_capaddr_simm7, FLD_a64c_index2, + FLD_imm17, }; /* Field description. */ diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index f70d9a5efac..dbfbf440410 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -2438,6 +2438,11 @@ QLF2(X, S_D), \ } +# define QL2_A64C_CA_PCREL \ +{ \ + QLF2(CA,NIL), \ +} + #define QL3_A64C_CA_CA_NIL \ { \ QLF3(CA, CA, NIL), \ @@ -4206,6 +4211,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = A64C_INSN ("ldp", 0x22c00000, 0xbfc00000, ldstpair_indexed, 0, OP3 (Cat, Cat2, A64C_ADDR_SIMM7), QL3_A64C_CA_CA_ADDR, 0), A64C_INSN ("stp", 0x22800000, 0xbfc00000, ldstpair_indexed, 0, OP3 (Cat, Cat2, A64C_ADDR_SIMM7), QL3_A64C_CA_CA_ADDR, 0), + A64C_INSN ("ldr", 0x82000000, 0xffc00000, loadlit, OP_LDR_LIT_2, OP2 (Cat, ADDR_PCREL17), QL2_A64C_CA_PCREL, 0), + A64C_INSN ("ldct", 0xc2c4b000, 0xfffffc00, a64c, 0, OP2 (Rt, ADDR_SIMPLE), QL2_A64C_X_ADDR, 0), A64C_INSN ("stct", 0xc2c49000, 0xfffffc00, a64c, 0, OP2 (Rt, ADDR_SIMPLE), QL2_A64C_X_ADDR, 0), @@ -6181,4 +6188,6 @@ const struct aarch64_opcode aarch64_opcode_table[] = "a capability address with base register (no offset)") \ Y(ADDRESS, addr_simm, "A64C_ADDR_SIMM7", 0, \ F(FLD_imm7,FLD_a64c_index2), \ - "an address with 7-bit signed immediate offset") + "an address with 7-bit signed immediate offset") \ + Y(ADDRESS, imm, "ADDR_PCREL17", OPD_F_SEXT | OPD_F_SHIFT_BY_4, \ + F(FLD_imm17), "17-bit PC-relative address")