X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfnn-aarch64.c;h=64215f718500c24eb5df15921d57f086eec23097;hb=9a6896021df5997a1ea5d52b86b833920005e652;hp=868144489ba23ccfc4cfc92c1005c59fe4d8d5cb;hpb=c691de6a16a87adc686ce5cd6c9be54ee0b1a8c1;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c index 868144489b..64215f7185 100644 --- a/bfd/elfnn-aarch64.c +++ b/bfd/elfnn-aarch64.c @@ -1,5 +1,5 @@ /* AArch64-specific support for NN-bit ELF. - Copyright (C) 2009-2018 Free Software Foundation, Inc. + Copyright (C) 2009-2020 Free Software Foundation, Inc. Contributed by ARM Ltd. This file is part of BFD, the Binary File Descriptor library. @@ -139,12 +139,12 @@ #include "bfd.h" #include "libiberty.h" #include "libbfd.h" -#include "bfd_stdint.h" #include "elf-bfd.h" #include "bfdlink.h" #include "objalloc.h" #include "elf/aarch64.h" #include "elfxx-aarch64.h" +#include "cpu-aarch64.h" #define ARCH_SIZE NN @@ -268,6 +268,12 @@ #define PLT_ENTRY_SIZE (32) #define PLT_SMALL_ENTRY_SIZE (16) #define PLT_TLSDESC_ENTRY_SIZE (32) +/* PLT sizes with BTI insn. */ +#define PLT_BTI_SMALL_ENTRY_SIZE (24) +/* PLT sizes with PAC insn. */ +#define PLT_PAC_SMALL_ENTRY_SIZE (24) +/* PLT sizes with BTI and PAC insn. */ +#define PLT_BTI_PAC_SMALL_ENTRY_SIZE (24) /* Encoding of the nop instruction. */ #define INSN_NOP 0xd503201f @@ -298,9 +304,26 @@ static const bfd_byte elfNN_aarch64_small_plt0_entry[PLT_ENTRY_SIZE] = 0x1f, 0x20, 0x03, 0xd5, /* nop */ }; +static const bfd_byte elfNN_aarch64_small_plt0_bti_entry[PLT_ENTRY_SIZE] = +{ + 0x5f, 0x24, 0x03, 0xd5, /* bti c. */ + 0xf0, 0x7b, 0xbf, 0xa9, /* stp x16, x30, [sp, #-16]! */ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, (GOT+16) */ +#if ARCH_SIZE == 64 + 0x11, 0x0A, 0x40, 0xf9, /* ldr x17, [x16, #PLT_GOT+0x10] */ + 0x10, 0x42, 0x00, 0x91, /* add x16, x16,#PLT_GOT+0x10 */ +#else + 0x11, 0x0A, 0x40, 0xb9, /* ldr w17, [x16, #PLT_GOT+0x8] */ + 0x10, 0x22, 0x00, 0x11, /* add w16, w16,#PLT_GOT+0x8 */ +#endif + 0x20, 0x02, 0x1f, 0xd6, /* br x17 */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + /* Per function entry in a procedure linkage table looks like this if the distance between the PLTGOT and the PLT is < 4GB use - these PLT entries. */ + these PLT entries. Use BTI versions of the PLTs when enabled. */ static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] = { 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ @@ -314,6 +337,54 @@ static const bfd_byte elfNN_aarch64_small_plt_entry[PLT_SMALL_ENTRY_SIZE] = 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ }; +static const bfd_byte +elfNN_aarch64_small_plt_bti_entry[PLT_BTI_SMALL_ENTRY_SIZE] = +{ + 0x5f, 0x24, 0x03, 0xd5, /* bti c. */ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ +#if ARCH_SIZE == 64 + 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */ + 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */ +#else + 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */ + 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */ +#endif + 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + +static const bfd_byte +elfNN_aarch64_small_plt_pac_entry[PLT_PAC_SMALL_ENTRY_SIZE] = +{ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ +#if ARCH_SIZE == 64 + 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */ + 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */ +#else + 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */ + 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */ +#endif + 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */ + 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + +static const bfd_byte +elfNN_aarch64_small_plt_bti_pac_entry[PLT_BTI_PAC_SMALL_ENTRY_SIZE] = +{ + 0x5f, 0x24, 0x03, 0xd5, /* bti c. */ + 0x10, 0x00, 0x00, 0x90, /* adrp x16, PLTGOT + n * 8 */ +#if ARCH_SIZE == 64 + 0x11, 0x02, 0x40, 0xf9, /* ldr x17, [x16, PLTGOT + n * 8] */ + 0x10, 0x02, 0x00, 0x91, /* add x16, x16, :lo12:PLTGOT + n * 8 */ +#else + 0x11, 0x02, 0x40, 0xb9, /* ldr w17, [x16, PLTGOT + n * 4] */ + 0x10, 0x02, 0x00, 0x11, /* add w16, w16, :lo12:PLTGOT + n * 4 */ +#endif + 0x9f, 0x21, 0x03, 0xd5, /* autia1716 */ + 0x20, 0x02, 0x1f, 0xd6, /* br x17. */ +}; + static const bfd_byte elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] = { @@ -332,6 +403,24 @@ elfNN_aarch64_tlsdesc_small_plt_entry[PLT_TLSDESC_ENTRY_SIZE] = 0x1f, 0x20, 0x03, 0xd5, /* nop */ }; +static const bfd_byte +elfNN_aarch64_tlsdesc_small_plt_bti_entry[PLT_TLSDESC_ENTRY_SIZE] = +{ + 0x5f, 0x24, 0x03, 0xd5, /* bti c. */ + 0xe2, 0x0f, 0xbf, 0xa9, /* stp x2, x3, [sp, #-16]! */ + 0x02, 0x00, 0x00, 0x90, /* adrp x2, 0 */ + 0x03, 0x00, 0x00, 0x90, /* adrp x3, 0 */ +#if ARCH_SIZE == 64 + 0x42, 0x00, 0x40, 0xf9, /* ldr x2, [x2, #0] */ + 0x63, 0x00, 0x00, 0x91, /* add x3, x3, 0 */ +#else + 0x42, 0x00, 0x40, 0xb9, /* ldr w2, [x2, #0] */ + 0x63, 0x00, 0x00, 0x11, /* add w3, w3, 0 */ +#endif + 0x40, 0x00, 0x1f, 0xd6, /* br x2 */ + 0x1f, 0x20, 0x03, 0xd5, /* nop */ +}; + #define elf_info_to_howto elfNN_aarch64_info_to_howto #define elf_info_to_howto_rel elfNN_aarch64_info_to_howto @@ -629,7 +718,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = PC relative address inline. */ /* MOV[NZ]: ((S+A-P) >> 0) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_PREL_G0), /* type */ + HOWTO (AARCH64_R (MOVW_PREL_G0), /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 17, /* bitsize */ @@ -644,7 +733,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = TRUE), /* pcrel_offset */ /* MOVK: ((S+A-P) >> 0) & 0xffff [no overflow check] */ - HOWTO64 (AARCH64_R (MOVW_PREL_G0_NC), /* type */ + HOWTO (AARCH64_R (MOVW_PREL_G0_NC), /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ @@ -659,7 +748,7 @@ static reloc_howto_type elfNN_aarch64_howto_table[] = TRUE), /* pcrel_offset */ /* MOV[NZ]: ((S+A-P) >> 16) & 0xffff */ - HOWTO64 (AARCH64_R (MOVW_PREL_G1), /* type */ + HOWTO (AARCH64_R (MOVW_PREL_G1), /* type */ 16, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 17, /* bitsize */ @@ -2436,6 +2525,16 @@ struct elf_aarch64_obj_tdata /* Zero to warn when linking objects with incompatible wchar_t sizes. */ int no_wchar_size_warning; + + /* All GNU_PROPERTY_AARCH64_FEATURE_1_AND properties. */ + uint32_t gnu_and_prop; + + /* Zero to warn when linking objects with incompatible + GNU_PROPERTY_AARCH64_FEATURE_1_BTI. */ + int no_bti_warn; + + /* PLT type based on security. */ + aarch64_plt_type plt_type; }; #define elf_aarch64_tdata(bfd) \ @@ -2471,9 +2570,6 @@ struct elf_aarch64_link_hash_entry { struct elf_link_hash_entry root; - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - /* Since PLT entries have variable size, we need to record the index into .got.plt instead of recomputing it from the PLT offset. */ @@ -2530,10 +2626,7 @@ struct elf_aarch64_link_hash_table int fix_erratum_835769; /* Fix erratum 843419. */ - int fix_erratum_843419; - - /* Enable ADRP->ADR rewrite for erratum 843419 workaround. */ - int fix_erratum_843419_adr; + erratum_84319_opts fix_erratum_843419; /* Don't apply link-time values for dynamic relocations. */ int no_apply_dynamic_relocs; @@ -2541,9 +2634,15 @@ struct elf_aarch64_link_hash_table /* The number of bytes in the initial entry in the PLT. */ bfd_size_type plt_header_size; - /* The number of bytes in the subsequent PLT etries. */ + /* The bytes of the initial PLT entry. */ + const bfd_byte *plt0_entry; + + /* The number of bytes in the subsequent PLT entries. */ bfd_size_type plt_entry_size; + /* The bytes of the subsequent PLT entry. */ + const bfd_byte *plt_entry; + /* Small local sym cache. */ struct sym_cache sym_cache; @@ -2580,12 +2679,18 @@ struct elf_aarch64_link_hash_table unsigned int top_index; asection **input_list; + /* JUMP_SLOT relocs for variant PCS symbols may be present. */ + int variant_pcs; + /* The offset into splt of the PLT entry for the TLS descriptor resolver. Special values are 0, if not necessary (or not found to be necessary yet), and -1 if needed but not determined yet. */ bfd_vma tlsdesc_plt; + /* The number of bytes in the PLT enty for the TLS descriptor. */ + bfd_size_type tlsdesc_plt_entry_size; + /* The GOT offset for the lazy trampoline. Communicated to the loader via DT_TLSDESC_GOT. The magic value (bfd_vma) -1 indicates an offset is not allocated. */ @@ -2620,7 +2725,6 @@ elfNN_aarch64_link_hash_newfunc (struct bfd_hash_entry *entry, table, string)); if (ret != NULL) { - ret->dyn_relocs = NULL; ret->got_type = GOT_UNKNOWN; ret->plt_got_offset = (bfd_vma) - 1; ret->stub_cache = NULL; @@ -2747,37 +2851,6 @@ elfNN_aarch64_copy_indirect_symbol (struct bfd_link_info *info, edir = (struct elf_aarch64_link_hash_entry *) dir; eind = (struct elf_aarch64_link_hash_entry *) ind; - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL;) - { - struct elf_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - if (ind->root.type == bfd_link_hash_indirect) { /* Copy over PLT info. */ @@ -2791,6 +2864,31 @@ elfNN_aarch64_copy_indirect_symbol (struct bfd_link_info *info, _bfd_elf_link_hash_copy_indirect (info, dir, ind); } +/* Merge non-visibility st_other attributes. */ + +static void +elfNN_aarch64_merge_symbol_attribute (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *isym, + bfd_boolean definition ATTRIBUTE_UNUSED, + bfd_boolean dynamic ATTRIBUTE_UNUSED) +{ + unsigned int isym_sto = isym->st_other & ~ELF_ST_VISIBILITY (-1); + unsigned int h_sto = h->other & ~ELF_ST_VISIBILITY (-1); + + if (isym_sto == h_sto) + return; + + if (isym_sto & ~STO_AARCH64_VARIANT_PCS) + /* Not fatal, this callback cannot fail. */ + _bfd_error_handler (_("unknown attribute for symbol `%s': 0x%02x"), + h->root.root.string, isym_sto); + + /* Note: Ideally we would warn about any attribute mismatch, but + this api does not allow that without substantial changes. */ + if (isym_sto & STO_AARCH64_VARIANT_PCS) + h->other |= STO_AARCH64_VARIANT_PCS; +} + /* Destroy an AArch64 elf linker hash table. */ static void @@ -2814,7 +2912,7 @@ static struct bfd_link_hash_table * elfNN_aarch64_link_hash_table_create (bfd *abfd) { struct elf_aarch64_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_aarch64_link_hash_table); + size_t amt = sizeof (struct elf_aarch64_link_hash_table); ret = bfd_zmalloc (amt); if (ret == NULL) @@ -2829,7 +2927,10 @@ elfNN_aarch64_link_hash_table_create (bfd *abfd) } ret->plt_header_size = PLT_ENTRY_SIZE; + ret->plt0_entry = elfNN_aarch64_small_plt0_entry; ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE; + ret->plt_entry = elfNN_aarch64_small_plt_entry; + ret->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE; ret->obfd = abfd; ret->dt_tlsdesc_got = (bfd_vma) - 1; @@ -2869,7 +2970,8 @@ aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section, + offset); r_type = elfNN_aarch64_bfd_reloc_from_type (input_bfd, r_type); - value = _bfd_aarch64_elf_resolve_relocation (r_type, place, value, 0, FALSE); + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, r_type, place, + value, 0, FALSE); return _bfd_aarch64_elf_put_addend (input_bfd, input_section->contents + offset, r_type, howto, value) == bfd_reloc_ok; @@ -3119,7 +3221,10 @@ _bfd_aarch64_add_stub_entry_after (const char *stub_name, asection *stub_sec; struct elf_aarch64_stub_hash_entry *stub_entry; - stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab); + stub_sec = NULL; + /* Only create the actual stub if we will end up needing it. */ + if (htab->fix_erratum_843419 & ERRAT_ADRP) + stub_sec = _bfd_aarch64_get_stub_for_link_section (link_section, htab); stub_entry = aarch64_stub_hash_lookup (&htab->stub_hash_table, stub_name, TRUE, FALSE); if (stub_entry == NULL) @@ -3138,7 +3243,7 @@ _bfd_aarch64_add_stub_entry_after (const char *stub_name, static bfd_boolean aarch64_build_one_stub (struct bfd_hash_entry *gen_entry, - void *in_arg ATTRIBUTE_UNUSED) + void *in_arg) { struct elf_aarch64_stub_hash_entry *stub_entry; asection *stub_sec; @@ -3151,10 +3256,22 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry, unsigned int template_size; const uint32_t *template; unsigned int i; + struct bfd_link_info *info; /* Massage our args to the form they really have. */ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry; + info = (struct bfd_link_info *) in_arg; + + /* Fail if the target section could not be assigned to an output + section. The user should fix his linker script. */ + if (stub_entry->target_section->output_section == NULL + && info->non_contiguous_regions) + info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. " + "Retry without " + "--enable-non-contiguous-regions.\n"), + stub_entry->target_section); + stub_sec = stub_entry->stub_sec; /* Make a note of the offset within the stubs for this entry. */ @@ -3264,14 +3381,15 @@ aarch64_build_one_stub (struct bfd_hash_entry *gen_entry, we know stub section sizes. */ static bfd_boolean -aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, - void *in_arg ATTRIBUTE_UNUSED) +aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) { struct elf_aarch64_stub_hash_entry *stub_entry; + struct elf_aarch64_link_hash_table *htab; int size; /* Massage our args to the form they really have. */ stub_entry = (struct elf_aarch64_stub_hash_entry *) gen_entry; + htab = (struct elf_aarch64_link_hash_table *) in_arg; switch (stub_entry->stub_type) { @@ -3285,7 +3403,11 @@ aarch64_size_one_stub (struct bfd_hash_entry *gen_entry, size = sizeof (aarch64_erratum_835769_stub); break; case aarch64_stub_erratum_843419_veneer: - size = sizeof (aarch64_erratum_843419_stub); + { + if (htab->fix_erratum_843419 == ERRAT_ADR) + return TRUE; + size = sizeof (aarch64_erratum_843419_stub); + } break; default: abort (); @@ -3311,7 +3433,7 @@ elfNN_aarch64_setup_section_lists (bfd *output_bfd, unsigned int top_id, top_index; asection *section; asection **input_list, **list; - bfd_size_type amt; + size_t amt; struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info); @@ -3389,7 +3511,7 @@ elfNN_aarch64_next_input_section (struct bfd_link_info *info, asection *isec) { asection **list = htab->input_list + isec->output_section->index; - if (*list != bfd_abs_section_ptr) + if (*list != bfd_abs_section_ptr && (isec->flags & SEC_CODE) != 0) { /* Steal the link_sec pointer for our list. */ /* This happens to make the list in reverse order, @@ -3410,67 +3532,96 @@ elfNN_aarch64_next_input_section (struct bfd_link_info *info, asection *isec) static void group_sections (struct elf_aarch64_link_hash_table *htab, bfd_size_type stub_group_size, - bfd_boolean stubs_always_before_branch) + bfd_boolean stubs_always_after_branch) { - asection **list = htab->input_list + htab->top_index; + asection **list = htab->input_list; do { asection *tail = *list; + asection *head; if (tail == bfd_abs_section_ptr) continue; + /* Reverse the list: we must avoid placing stubs at the + beginning of the section because the beginning of the text + section may be required for an interrupt vector in bare metal + code. */ +#define NEXT_SEC PREV_SEC + head = NULL; while (tail != NULL) + { + /* Pop from tail. */ + asection *item = tail; + tail = PREV_SEC (item); + + /* Push on head. */ + NEXT_SEC (item) = head; + head = item; + } + + while (head != NULL) { asection *curr; - asection *prev; - bfd_size_type total; + asection *next; + bfd_vma stub_group_start = head->output_offset; + bfd_vma end_of_next; - curr = tail; - total = tail->size; - while ((prev = PREV_SEC (curr)) != NULL - && ((total += curr->output_offset - prev->output_offset) - < stub_group_size)) - curr = prev; + curr = head; + while (NEXT_SEC (curr) != NULL) + { + next = NEXT_SEC (curr); + end_of_next = next->output_offset + next->size; + if (end_of_next - stub_group_start >= stub_group_size) + /* End of NEXT is too far from start, so stop. */ + break; + /* Add NEXT to the group. */ + curr = next; + } - /* OK, the size from the start of CURR to the end is less + /* OK, the size from the start to the start of CURR is less than stub_group_size and thus can be handled by one stub - section. (Or the tail section is itself larger than + section. (Or the head section is itself larger than stub_group_size, in which case we may be toast.) We should really be keeping track of the total size of stubs added here, as stubs contribute to the final output section size. */ do { - prev = PREV_SEC (tail); + next = NEXT_SEC (head); /* Set up this stub group. */ - htab->stub_group[tail->id].link_sec = curr; + htab->stub_group[head->id].link_sec = curr; } - while (tail != curr && (tail = prev) != NULL); + while (head != curr && (head = next) != NULL); /* But wait, there's more! Input sections up to stub_group_size - bytes before the stub section can be handled by it too. */ - if (!stubs_always_before_branch) + bytes after the stub section can be handled by it too. */ + if (!stubs_always_after_branch) { - total = 0; - while (prev != NULL - && ((total += tail->output_offset - prev->output_offset) - < stub_group_size)) + stub_group_start = curr->output_offset + curr->size; + + while (next != NULL) { - tail = prev; - prev = PREV_SEC (tail); - htab->stub_group[tail->id].link_sec = curr; + end_of_next = next->output_offset + next->size; + if (end_of_next - stub_group_start >= stub_group_size) + /* End of NEXT is too far from stubs, so stop. */ + break; + /* Add NEXT to the stub group. */ + head = next; + next = NEXT_SEC (head); + htab->stub_group[head->id].link_sec = curr; } } - tail = prev; + head = next; } } - while (list-- != htab->input_list); + while (list++ != htab->input_list + htab->top_index); free (htab->input_list); } +#undef PREV_SEC #undef PREV_SEC #define AARCH64_BITS(x, pos, n) (((x) >> (pos)) & ((1 << (n)) - 1)) @@ -3845,7 +3996,7 @@ _bfd_aarch64_erratum_835769_scan (bfd *input_bfd, static bfd_boolean _bfd_aarch64_adrp_p (uint32_t insn) { - return ((insn & 0x9f000000) == 0x90000000); + return ((insn & AARCH64_ADRP_OP_MASK) == AARCH64_ADRP_OP); } @@ -3950,8 +4101,10 @@ _bfd_aarch64_resize_stubs (struct elf_aarch64_link_hash_table *htab) /* Ensure all stub sections have a size which is a multiple of 4096. This is important in order to ensure that the insertion of stub sections does not in itself move existing code around - in such a way that new errata sequences are created. */ - if (htab->fix_erratum_843419) + in such a way that new errata sequences are created. We only do this + when the ADRP workaround is enabled. If only the ADR workaround is + enabled then the stubs workaround won't ever be used. */ + if (htab->fix_erratum_843419 & ERRAT_ADRP) if (section->size) section->size = BFD_ALIGN (section->size, 0x1000); } @@ -4166,15 +4319,21 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, for (input_bfd = info->input_bfds; input_bfd != NULL; input_bfd = input_bfd->link.next) - if (!_bfd_aarch64_erratum_835769_scan (input_bfd, info, - &num_erratum_835769_fixes)) - return FALSE; + { + if (!is_aarch64_elf (input_bfd) + || (input_bfd->flags & BFD_LINKER_CREATED) != 0) + continue; + + if (!_bfd_aarch64_erratum_835769_scan (input_bfd, info, + &num_erratum_835769_fixes)) + return FALSE; + } _bfd_aarch64_resize_stubs (htab); (*htab->layout_sections_again) (); } - if (htab->fix_erratum_843419) + if (htab->fix_erratum_843419 != ERRAT_NONE) { bfd *input_bfd; @@ -4184,6 +4343,10 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, { asection *section; + if (!is_aarch64_elf (input_bfd) + || (input_bfd->flags & BFD_LINKER_CREATED) != 0) + continue; + for (section = input_bfd->sections; section != NULL; section = section->next) @@ -4206,6 +4369,10 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, asection *section; Elf_Internal_Sym *local_syms = NULL; + if (!is_aarch64_elf (input_bfd) + || (input_bfd->flags & BFD_LINKER_CREATED) != 0) + continue; + /* We'll need the symbol table in a second. */ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; if (symtab_hdr->sh_info == 0) @@ -4414,6 +4581,9 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, { /* The proper stub has already been created. */ free (stub_name); + /* Always update this stub's target since it may have + changed after layout. */ + stub_entry->target_value = sym_value + irela->r_addend; continue; } @@ -4465,7 +4635,7 @@ elfNN_aarch64_size_stubs (bfd *output_bfd, return TRUE; -error_ret_free_local: + error_ret_free_local: return FALSE; } @@ -4594,6 +4764,47 @@ bfd_elfNN_aarch64_init_maps (bfd *abfd) } } +static void +setup_plt_values (struct bfd_link_info *link_info, + aarch64_plt_type plt_type) +{ + struct elf_aarch64_link_hash_table *globals; + globals = elf_aarch64_hash_table (link_info); + + if (plt_type == PLT_BTI_PAC) + { + globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry; + + /* Only in ET_EXEC we need PLTn with BTI. */ + if (bfd_link_pde (link_info)) + { + globals->plt_entry_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE; + globals->plt_entry = elfNN_aarch64_small_plt_bti_pac_entry; + } + else + { + globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE; + globals->plt_entry = elfNN_aarch64_small_plt_pac_entry; + } + } + else if (plt_type == PLT_BTI) + { + globals->plt0_entry = elfNN_aarch64_small_plt0_bti_entry; + + /* Only in ET_EXEC we need PLTn with BTI. */ + if (bfd_link_pde (link_info)) + { + globals->plt_entry_size = PLT_BTI_SMALL_ENTRY_SIZE; + globals->plt_entry = elfNN_aarch64_small_plt_bti_entry; + } + } + else if (plt_type == PLT_PAC) + { + globals->plt_entry_size = PLT_PAC_SMALL_ENTRY_SIZE; + globals->plt_entry = elfNN_aarch64_small_plt_pac_entry; + } +} + /* Set option values needed during linking. */ void bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, @@ -4601,21 +4812,38 @@ bfd_elfNN_aarch64_set_options (struct bfd *output_bfd, int no_enum_warn, int no_wchar_warn, int pic_veneer, int fix_erratum_835769, - int fix_erratum_843419, - int no_apply_dynamic_relocs) + erratum_84319_opts fix_erratum_843419, + int no_apply_dynamic_relocs, + aarch64_bti_pac_info bp_info) { struct elf_aarch64_link_hash_table *globals; globals = elf_aarch64_hash_table (link_info); globals->pic_veneer = pic_veneer; globals->fix_erratum_835769 = fix_erratum_835769; + /* If the default options are used, then ERRAT_ADR will be set by default + which will enable the ADRP->ADR workaround for the erratum 843419 + workaround. */ globals->fix_erratum_843419 = fix_erratum_843419; - globals->fix_erratum_843419_adr = TRUE; globals->no_apply_dynamic_relocs = no_apply_dynamic_relocs; BFD_ASSERT (is_aarch64_elf (output_bfd)); elf_aarch64_tdata (output_bfd)->no_enum_size_warning = no_enum_warn; elf_aarch64_tdata (output_bfd)->no_wchar_size_warning = no_wchar_warn; + + switch (bp_info.bti_type) + { + case BTI_WARN: + elf_aarch64_tdata (output_bfd)->no_bti_warn = 0; + elf_aarch64_tdata (output_bfd)->gnu_and_prop + |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI; + break; + + default: + break; + } + elf_aarch64_tdata (output_bfd)->plt_type = bp_info.plt_type; + setup_plt_values (link_info, bp_info.plt_type); } static bfd_vma @@ -5066,15 +5294,24 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry, || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer) return TRUE; - insn = bfd_getl32 (contents + stub_entry->target_value); - bfd_putl32 (insn, - stub_entry->stub_sec->contents + stub_entry->stub_offset); + BFD_ASSERT (((htab->fix_erratum_843419 & ERRAT_ADRP) && stub_entry->stub_sec) + || (htab->fix_erratum_843419 & ERRAT_ADR)); + + /* Only update the stub section if we have one. We should always have one if + we're allowed to use the ADRP errata workaround, otherwise it is not + required. */ + if (stub_entry->stub_sec) + { + insn = bfd_getl32 (contents + stub_entry->target_value); + bfd_putl32 (insn, + stub_entry->stub_sec->contents + stub_entry->stub_offset); + } place = (section->output_section->vma + section->output_offset + stub_entry->adrp_offset); insn = bfd_getl32 (contents + stub_entry->adrp_offset); - if ((insn & AARCH64_ADRP_OP_MASK) != AARCH64_ADRP_OP) + if (!_bfd_aarch64_adrp_p (insn)) abort (); bfd_signed_vma imm = @@ -5082,14 +5319,16 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry, ((bfd_vma) _bfd_aarch64_decode_adrp_imm (insn) << 12, 33) - (place & 0xfff)); - if (htab->fix_erratum_843419_adr + if ((htab->fix_erratum_843419 & ERRAT_ADR) && (imm >= AARCH64_MIN_ADRP_IMM && imm <= AARCH64_MAX_ADRP_IMM)) { insn = (_bfd_aarch64_reencode_adr_imm (AARCH64_ADR_OP, imm) | AARCH64_RT (insn)); bfd_putl32 (insn, contents + stub_entry->adrp_offset); + /* Stub is not needed, don't map it out. */ + stub_entry->stub_type = aarch64_stub_none; } - else + else if (htab->fix_erratum_843419 & ERRAT_ADRP) { bfd_vma veneered_insn_loc; bfd_vma veneer_entry_loc; @@ -5116,6 +5355,21 @@ _bfd_aarch64_erratum_843419_branch_to_stub (struct bfd_hash_entry *gen_entry, branch_insn |= branch_offset; bfd_putl32 (branch_insn, contents + stub_entry->target_value); } + else + { + abfd = stub_entry->target_section->owner; + _bfd_error_handler + (_("%pB: error: erratum 843419 immediate 0x%" BFD_VMA_FMT "x " + "out of range for ADR (input file too large) and " + "--fix-cortex-a53-843419=adr used. Run the linker with " + "--fix-cortex-a53-843419=full instead"), abfd, imm); + bfd_set_error (bfd_error_bad_value); + /* This function is called inside a hashtable traversal and the error + handlers called above turn into non-fatal errors. Which means this + case ld returns an exit code 0 and also produces a broken object file. + To prevent this, issue a hard abort. */ + BFD_FAIL (); + } return TRUE; } @@ -5205,6 +5459,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, bfd_vma orig_value = value; bfd_boolean resolved_to_zero; bfd_boolean abs_symbol_p; + bfd_boolean via_plt_p; globals = elf_aarch64_hash_table (info); @@ -5226,6 +5481,8 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, : bfd_is_und_section (sym_sec)); abs_symbol_p = h != NULL && bfd_is_abs_symbol (&h->root); + via_plt_p = (globals->root.splt != NULL && h != NULL + && h->plt.offset != (bfd_vma) - 1); /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined in a non-shared object. */ @@ -5273,7 +5530,7 @@ elfNN_aarch64_final_link_relocate (reloc_howto_type *howto, switch (bfd_r_type) { default: -bad_ifunc_reloc: + bad_ifunc_reloc: if (h->root.root.string) name = h->root.root.string; else @@ -5353,7 +5610,8 @@ bad_ifunc_reloc: /* FALLTHROUGH */ case BFD_RELOC_AARCH64_CALL26: case BFD_RELOC_AARCH64_JUMP26: - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, signed_addend, weak_undef_p); return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, @@ -5430,7 +5688,8 @@ bad_ifunc_reloc: addend = (globals->root.sgot->output_section->vma + globals->root.sgot->output_offset); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, addend, weak_undef_p); return _bfd_aarch64_elf_put_addend (input_bfd, hit_data, bfd_r_type, howto, value); case BFD_RELOC_AARCH64_ADD_LO12: @@ -5559,12 +5818,23 @@ bad_ifunc_reloc: value += signed_addend; break; + case BFD_RELOC_AARCH64_BRANCH19: + case BFD_RELOC_AARCH64_TSTBR14: + /* A conditional branch to an undefined weak symbol is converted to a + branch to itself. */ + if (weak_undef_p && !via_plt_p) + { + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, + signed_addend, + weak_undef_p); + break; + } + /* Fall through. */ case BFD_RELOC_AARCH64_CALL26: case BFD_RELOC_AARCH64_JUMP26: { asection *splt = globals->root.splt; - bfd_boolean via_plt_p = - splt != NULL && h != NULL && h->plt.offset != (bfd_vma) - 1; /* A call to an undefined weak symbol is converted to a jump to the next instruction unless a PLT entry will be created. @@ -5608,7 +5878,8 @@ bad_ifunc_reloc: signed_addend = 0; } } - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, signed_addend, weak_undef_p); *unresolved_reloc_p = FALSE; break; @@ -5651,7 +5922,6 @@ bad_ifunc_reloc: case BFD_RELOC_AARCH64_32: #endif case BFD_RELOC_AARCH64_ADD_LO12: - case BFD_RELOC_AARCH64_BRANCH19: case BFD_RELOC_AARCH64_LDST128_LO12: case BFD_RELOC_AARCH64_LDST16_LO12: case BFD_RELOC_AARCH64_LDST32_LO12: @@ -5667,8 +5937,8 @@ bad_ifunc_reloc: case BFD_RELOC_AARCH64_MOVW_G2_NC: case BFD_RELOC_AARCH64_MOVW_G2_S: case BFD_RELOC_AARCH64_MOVW_G3: - case BFD_RELOC_AARCH64_TSTBR14: - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, signed_addend, weak_undef_p); break; @@ -5713,7 +5983,8 @@ bad_ifunc_reloc: if (aarch64_relocation_aginst_gp_p (bfd_r_type)) addend = (globals->root.sgot->output_section->vma + globals->root.sgot->output_offset); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, addend, weak_undef_p); } else @@ -5760,7 +6031,8 @@ bad_ifunc_reloc: if (aarch64_relocation_aginst_gp_p (bfd_r_type)) addend = base_got->output_section->vma + base_got->output_offset; - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, addend, weak_undef_p); } @@ -5797,7 +6069,8 @@ bad_ifunc_reloc: + globals->root.sgot->output_section->vma + globals->root.sgot->output_offset); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, 0, weak_undef_p); *unresolved_reloc_p = FALSE; break; @@ -5810,7 +6083,8 @@ bad_ifunc_reloc: return bfd_reloc_notsupported; value = symbol_got_offset (input_bfd, h, r_symndx); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, 0, weak_undef_p); *unresolved_reloc_p = FALSE; break; @@ -5831,10 +6105,26 @@ bad_ifunc_reloc: case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1: case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G1_NC: case BFD_RELOC_AARCH64_TLSLD_MOVW_DTPREL_G2: - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, - signed_addend - dtpoff_base (info), - weak_undef_p); - break; + { + if (!(weak_undef_p || elf_hash_table (info)->tls_sec)) + { + int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: TLS relocation %s against undefined symbol `%s'"), + input_bfd, elfNN_aarch64_howto_table[howto_index].name, + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return bfd_reloc_notsupported; + } + + bfd_vma def_value + = weak_undef_p ? 0 : signed_addend - dtpoff_base (info); + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, + def_value, weak_undef_p); + break; + } case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_HI12: case BFD_RELOC_AARCH64_TLSLE_ADD_TPREL_LO12: @@ -5852,11 +6142,27 @@ bad_ifunc_reloc: case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, - signed_addend - tpoff_base (info), - weak_undef_p); - *unresolved_reloc_p = FALSE; - break; + { + if (!(weak_undef_p || elf_hash_table (info)->tls_sec)) + { + int howto_index = bfd_r_type - BFD_RELOC_AARCH64_RELOC_START; + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: TLS relocation %s against undefined symbol `%s'"), + input_bfd, elfNN_aarch64_howto_table[howto_index].name, + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return bfd_reloc_notsupported; + } + + bfd_vma def_value + = weak_undef_p ? 0 : signed_addend - tpoff_base (info); + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, + def_value, weak_undef_p); + *unresolved_reloc_p = FALSE; + break; + } case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12: case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21: @@ -5871,7 +6177,8 @@ bad_ifunc_reloc: + globals->root.sgotplt->output_offset + globals->sgotplt_jump_table_size); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, 0, weak_undef_p); *unresolved_reloc_p = FALSE; break; @@ -5889,7 +6196,8 @@ bad_ifunc_reloc: value -= (globals->root.sgot->output_section->vma + globals->root.sgot->output_offset); - value = _bfd_aarch64_elf_resolve_relocation (bfd_r_type, place, value, + value = _bfd_aarch64_elf_resolve_relocation (input_bfd, bfd_r_type, + place, value, 0, weak_undef_p); *unresolved_reloc_p = FALSE; break; @@ -5938,6 +6246,64 @@ bad_ifunc_reloc: # define movz_hw_R0 (0x52c00000) #endif +/* Structure to hold payload for _bfd_aarch64_erratum_843419_clear_stub, + it is used to identify the stub information to reset. */ + +struct erratum_843419_branch_to_stub_clear_data +{ + bfd_vma adrp_offset; + asection *output_section; +}; + +/* Clear the erratum information for GEN_ENTRY if the ADRP_OFFSET and + section inside IN_ARG matches. The clearing is done by setting the + stub_type to none. */ + +static bfd_boolean +_bfd_aarch64_erratum_843419_clear_stub (struct bfd_hash_entry *gen_entry, + void *in_arg) +{ + struct elf_aarch64_stub_hash_entry *stub_entry + = (struct elf_aarch64_stub_hash_entry *) gen_entry; + struct erratum_843419_branch_to_stub_clear_data *data + = (struct erratum_843419_branch_to_stub_clear_data *) in_arg; + + if (stub_entry->target_section != data->output_section + || stub_entry->stub_type != aarch64_stub_erratum_843419_veneer + || stub_entry->adrp_offset != data->adrp_offset) + return TRUE; + + /* Change the stub type instead of removing the entry, removing from the hash + table would be slower and we have already reserved the memory for the entry + so there wouldn't be much gain. Changing the stub also keeps around a + record of what was there before. */ + stub_entry->stub_type = aarch64_stub_none; + + /* We're done and there could have been only one matching stub at that + particular offset, so abort further traversal. */ + return FALSE; +} + +/* TLS Relaxations may relax an adrp sequence that matches the erratum 843419 + sequence. In this case the erratum no longer applies and we need to remove + the entry from the pending stub generation. This clears matching adrp insn + at ADRP_OFFSET in INPUT_SECTION in the stub table defined in GLOBALS. */ + +static void +clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals, + bfd_vma adrp_offset, asection *input_section) +{ + if (globals->fix_erratum_843419 & ERRAT_ADRP) + { + struct erratum_843419_branch_to_stub_clear_data data; + data.adrp_offset = adrp_offset; + data.output_section = input_section; + + bfd_hash_traverse (&globals->stub_hash_table, + _bfd_aarch64_erratum_843419_clear_stub, &data); + } +} + /* Handle TLS relaxations. Relaxing is possible for symbols that use R_AARCH64_TLSDESC_ADR_{PAGE, LD64_LO12_NC, ADD_LO12_NC} during a static link. @@ -5948,8 +6314,9 @@ bad_ifunc_reloc: static bfd_reloc_status_type elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals, - bfd *input_bfd, bfd_byte *contents, - Elf_Internal_Rela *rel, struct elf_link_hash_entry *h) + bfd *input_bfd, asection *input_section, + bfd_byte *contents, Elf_Internal_Rela *rel, + struct elf_link_hash_entry *h) { bfd_boolean is_local = h == NULL; unsigned int r_type = ELFNN_R_TYPE (rel->r_info); @@ -5970,6 +6337,9 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals, Where R is x for LP64, and w for ILP32. */ bfd_putl32 (movz_R0, contents + rel->r_offset); + /* We have relaxed the adrp into a mov, we may have to clear any + pending erratum fixes. */ + clear_erratum_843419_entry (globals, rel->r_offset, input_section); return bfd_reloc_continue; } else @@ -6260,6 +6630,9 @@ elfNN_aarch64_tls_relax (struct elf_aarch64_link_hash_table *globals, { insn = bfd_getl32 (contents + rel->r_offset); bfd_putl32 (movz_R0 | (insn & 0x1f), contents + rel->r_offset); + /* We have relaxed the adrp into a mov, we may have to clear any + pending erratum fixes. */ + clear_erratum_843419_entry (globals, rel->r_offset, input_section); } return bfd_reloc_continue; @@ -6450,7 +6823,7 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, name = (bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, sym->st_name)); if (name == NULL || *name == '\0') - name = bfd_section_name (input_bfd, sec); + name = bfd_section_name (sec); } if (r_symndx != 0 @@ -6484,7 +6857,8 @@ elfNN_aarch64_relocate_section (bfd *output_bfd, howto = elfNN_aarch64_howto_from_bfd_reloc (bfd_r_type); BFD_ASSERT (howto != NULL); r_type = howto->type; - r = elfNN_aarch64_tls_relax (globals, input_bfd, contents, rel, h); + r = elfNN_aarch64_tls_relax (globals, input_bfd, input_section, + contents, rel, h); unresolved_reloc = 0; } else @@ -6932,7 +7306,7 @@ elfNN_aarch64_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) for (sec = ibfd->sections; sec != NULL; sec = sec->next) { - if ((bfd_get_section_flags (ibfd, sec) + if ((bfd_section_flags (sec) & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS)) only_data_sections = FALSE; @@ -6976,23 +7350,6 @@ elfNN_aarch64_print_private_bfd_data (bfd *abfd, void *ptr) return TRUE; } -/* Find dynamic relocs for H that apply to read-only sections. */ - -static asection * -readonly_dynrelocs (struct elf_link_hash_entry *h) -{ - struct elf_dyn_relocs *p; - - for (p = elf_aarch64_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - return p->sec; - } - return NULL; -} - /* Return true if we need copy relocation against EH. */ static bfd_boolean @@ -7001,7 +7358,7 @@ need_copy_relocation_p (struct elf_aarch64_link_hash_entry *eh) struct elf_dyn_relocs *p; asection *s; - for (p = eh->dyn_relocs; p != NULL; p = p->next) + for (p = eh->root.dyn_relocs; p != NULL; p = p->next) { /* If there is any pc-relative reference, we need to keep copy relocation to avoid propagating the relocation into runtime that current glibc @@ -7178,13 +7535,13 @@ aarch64_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) (bed->dynamic_sec_flags | SEC_READONLY)); if (s == NULL - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + || !bfd_set_section_alignment (s, bed->s->log_file_align)) return FALSE; htab->srelgot = s; s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); if (s == NULL - || !bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) + || !bfd_set_section_alignment (s, bed->s->log_file_align)) return FALSE; htab->sgot = s; htab->sgot->size += GOT_ENTRY_SIZE; @@ -7206,8 +7563,7 @@ aarch64_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) { s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags); if (s == NULL - || !bfd_set_section_alignment (abfd, s, - bed->s->log_file_align)) + || !bfd_set_section_alignment (s, bed->s->log_file_align)) return FALSE; htab->sgotplt = s; } @@ -7481,9 +7837,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, relocations we need for this symbol. */ if (h != NULL) { - struct elf_aarch64_link_hash_entry *eh; - eh = (struct elf_aarch64_link_hash_entry *) h; - head = &eh->dyn_relocs; + head = &h->dyn_relocs; } else { @@ -7512,7 +7866,7 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, p = *head; if (p == NULL || p->sec != sec) { - bfd_size_type amt = sizeof *p; + size_t amt = sizeof *p; p = ((struct elf_dyn_relocs *) bfd_zalloc (htab->root.dynobj, amt)); if (p == NULL) @@ -7562,9 +7916,6 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC: case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21: case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21: - case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1: - case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G1_NC: - case BFD_RELOC_AARCH64_TLSLE_MOVW_TPREL_G2: { unsigned got_type; unsigned old_got_type; @@ -7629,6 +7980,8 @@ elfNN_aarch64_check_relocs (bfd *abfd, struct bfd_link_info *info, break; } + case BFD_RELOC_AARCH64_BRANCH19: + case BFD_RELOC_AARCH64_TSTBR14: case BFD_RELOC_AARCH64_CALL26: case BFD_RELOC_AARCH64_JUMP26: /* If this is a local symbol then we resolve it @@ -7661,116 +8014,43 @@ elfNN_aarch64_is_target_special_symbol (bfd *abfd ATTRIBUTE_UNUSED, BFD_AARCH64_SPECIAL_SYM_TYPE_ANY); } -/* This is a copy of elf_find_function () from elf.c except that - AArch64 mapping symbols are ignored when looking for function names. */ +/* If the ELF symbol SYM might be a function in SEC, return the + function size and set *CODE_OFF to the function's entry point, + otherwise return zero. */ -static bfd_boolean -aarch64_elf_find_function (bfd *abfd ATTRIBUTE_UNUSED, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr) -{ - const char *filename = NULL; - asymbol *func = NULL; - bfd_vma low_func = 0; - asymbol **p; - - for (p = symbols; *p != NULL; p++) - { - elf_symbol_type *q; +static bfd_size_type +elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec, + bfd_vma *code_off) +{ + bfd_size_type size; - q = (elf_symbol_type *) * p; + if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT + | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0 + || sym->section != sec) + return 0; - switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) - { - default: - break; - case STT_FILE: - filename = bfd_asymbol_name (&q->symbol); - break; + if (!(sym->flags & BSF_SYNTHETIC)) + switch (ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info)) + { case STT_FUNC: case STT_NOTYPE: - /* Skip mapping symbols. */ - if ((q->symbol.flags & BSF_LOCAL) - && (bfd_is_aarch64_special_symbol_name - (q->symbol.name, BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))) - continue; - /* Fall through. */ - if (bfd_get_section (&q->symbol) == section - && q->symbol.value >= low_func && q->symbol.value <= offset) - { - func = (asymbol *) q; - low_func = q->symbol.value; - } break; - } - } - - if (func == NULL) - return FALSE; - - if (filename_ptr) - *filename_ptr = filename; - if (functionname_ptr) - *functionname_ptr = bfd_asymbol_name (func); - - return TRUE; -} - - -/* Find the nearest line to a particular section and offset, for error - reporting. This code is a duplicate of the code in elf.c, except - that it uses aarch64_elf_find_function. */ - -static bfd_boolean -elfNN_aarch64_find_nearest_line (bfd *abfd, - asymbol **symbols, - asection *section, - bfd_vma offset, - const char **filename_ptr, - const char **functionname_ptr, - unsigned int *line_ptr, - unsigned int *discriminator_ptr) -{ - bfd_boolean found = FALSE; - - if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, - filename_ptr, functionname_ptr, - line_ptr, discriminator_ptr, - dwarf_debug_sections, 0, - &elf_tdata (abfd)->dwarf2_find_line_info)) - { - if (!*functionname_ptr) - aarch64_elf_find_function (abfd, symbols, section, offset, - *filename_ptr ? NULL : filename_ptr, - functionname_ptr); - - return TRUE; - } - - /* Skip _bfd_dwarf1_find_nearest_line since no known AArch64 - toolchain uses DWARF1. */ - - if (!_bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, - &found, filename_ptr, - functionname_ptr, line_ptr, - &elf_tdata (abfd)->line_info)) - return FALSE; - - if (found && (*functionname_ptr || *line_ptr)) - return TRUE; - - if (symbols == NULL) - return FALSE; + default: + return 0; + } - if (!aarch64_elf_find_function (abfd, symbols, section, offset, - filename_ptr, functionname_ptr)) - return FALSE; + if ((sym->flags & BSF_LOCAL) + && bfd_is_aarch64_special_symbol_name (sym->name, + BFD_AARCH64_SPECIAL_SYM_TYPE_ANY)) + return 0; - *line_ptr = 0; - return TRUE; + *code_off = sym->value; + size = 0; + if (!(sym->flags & BSF_SYNTHETIC)) + size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; + if (size == 0) + size = 1; + return size; } static bfd_boolean @@ -7787,16 +8067,17 @@ elfNN_aarch64_find_inliner_info (bfd *abfd, } -static void -elfNN_aarch64_post_process_headers (bfd *abfd, - struct bfd_link_info *link_info) +static bfd_boolean +elfNN_aarch64_init_file_header (bfd *abfd, struct bfd_link_info *link_info) { Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */ + if (!_bfd_elf_init_file_header (abfd, link_info)) + return FALSE; + i_ehdrp = elf_elfheader (abfd); i_ehdrp->e_ident[EI_ABIVERSION] = AARCH64_ELF_ABI_VERSION; - - _bfd_elf_post_process_headers (abfd, link_info); + return TRUE; } static enum elf_reloc_type_class @@ -8074,6 +8355,8 @@ aarch64_map_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (!elfNN_aarch64_output_map_sym (osi, AARCH64_MAP_INSN, addr)) return FALSE; break; + case aarch64_stub_none: + break; default: abort (); @@ -8151,7 +8434,7 @@ elfNN_aarch64_new_section_hook (bfd *abfd, asection *sec) if (!sec->used_by_bfd) { _aarch64_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); + size_t amt = sizeof (*sdata); sdata = bfd_zalloc (abfd, amt); if (sdata == NULL) @@ -8279,7 +8562,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Make room for this entry. For now we only create the small model PLT entries. We later need to find a way of relaxing into these from the large model PLT entries. */ - s->size += PLT_SMALL_ENTRY_SIZE; + s->size += htab->plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker script. */ @@ -8302,6 +8585,12 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) updated. */ htab->root.srelplt->reloc_count++; + + /* Mark the DSO in case R__JUMP_SLOT relocs against + variant PCS symbols are present. */ + if (h->other & STO_AARCH64_VARIANT_PCS) + htab->variant_pcs = 1; + } else { @@ -8409,7 +8698,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) h->got.offset = (bfd_vma) - 1; } - if (eh->dyn_relocs == NULL) + if (h->dyn_relocs == NULL) return TRUE; /* In the shared -Bsymbolic case, discard space allocated for @@ -8430,7 +8719,7 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct elf_dyn_relocs **pp; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) + for (pp = &h->dyn_relocs; (p = *pp) != NULL;) { p->count -= p->pc_count; p->pc_count = 0; @@ -8443,11 +8732,11 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Also discard relocs on undefined weak syms with non-default visibility. */ - if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) + if (h->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; /* Make sure undefined weak symbols are output as a dynamic symbol in PIEs. */ @@ -8486,13 +8775,13 @@ elfNN_aarch64_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) goto keep; } - eh->dyn_relocs = NULL; + h->dyn_relocs = NULL; keep:; } /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + for (p = h->dyn_relocs; p != NULL; p = p->next) { asection *sreloc; @@ -8515,7 +8804,6 @@ elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, { struct bfd_link_info *info; struct elf_aarch64_link_hash_table *htab; - struct elf_aarch64_link_hash_entry *eh; /* An example of a bfd_link_hash_indirect symbol is versioned symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect) @@ -8535,14 +8823,12 @@ elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, info = (struct bfd_link_info *) inf; htab = elf_aarch64_hash_table (info); - eh = (struct elf_aarch64_link_hash_entry *) h; - /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, - &eh->dyn_relocs, + &h->dyn_relocs, NULL, htab->plt_entry_size, htab->plt_header_size, @@ -8551,25 +8837,6 @@ elfNN_aarch64_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, return TRUE; } -/* Allocate space in .plt, .got and associated reloc sections for - local dynamic relocs. */ - -static bfd_boolean -elfNN_aarch64_allocate_local_dynrelocs (void **slot, void *inf) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) *slot; - - if (h->type != STT_GNU_IFUNC - || !h->def_regular - || !h->ref_regular - || !h->forced_local - || h->root.type != bfd_link_hash_defined) - abort (); - - return elfNN_aarch64_allocate_dynrelocs (h, inf); -} - /* Allocate space in .plt, .got and associated reloc sections for local ifunc dynamic relocs. */ @@ -8589,33 +8856,6 @@ elfNN_aarch64_allocate_local_ifunc_dynrelocs (void **slot, void *inf) return elfNN_aarch64_allocate_ifunc_dynrelocs (h, inf); } -/* Set DF_TEXTREL if we find any dynamic relocs that apply to - read-only sections. */ - -static bfd_boolean -maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p) -{ - asection *sec; - - if (h->root.type == bfd_link_hash_indirect) - return TRUE; - - sec = readonly_dynrelocs (h); - if (sec != NULL) - { - struct bfd_link_info *info = (struct bfd_link_info *) info_p; - - info->flags |= DF_TEXTREL; - info->callbacks->minfo - (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"), - sec->owner, h->root.root.string, sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - return TRUE; -} - /* This is the most important function of all . Innocuosly named though ! */ @@ -8757,11 +8997,6 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, elf_link_hash_traverse (&htab->root, elfNN_aarch64_allocate_ifunc_dynrelocs, info); - /* Allocate .plt and .got entries, and space for local symbols. */ - htab_traverse (htab->loc_hash_table, - elfNN_aarch64_allocate_local_dynrelocs, - info); - /* Allocate .plt and .got entries, and space for local ifunc symbols. */ htab_traverse (htab->loc_hash_table, elfNN_aarch64_allocate_local_ifunc_dynrelocs, @@ -8779,15 +9014,15 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->tlsdesc_plt) { if (htab->root.splt->size == 0) - htab->root.splt->size += PLT_ENTRY_SIZE; - - htab->tlsdesc_plt = htab->root.splt->size; - htab->root.splt->size += PLT_TLSDESC_ENTRY_SIZE; + htab->root.splt->size += htab->plt_header_size; /* If we're not using lazy TLS relocations, don't generate the - GOT entry required. */ + GOT and PLT entry required. */ if (!(info->flags & DF_BIND_NOW)) { + htab->tlsdesc_plt = htab->root.splt->size; + htab->root.splt->size += htab->tlsdesc_plt_entry_size; + htab->dt_tlsdesc_got = htab->root.sgot->size; htab->root.sgot->size += GOT_ENTRY_SIZE; } @@ -8822,7 +9057,7 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Strip this section if we don't need it; see the comment below. */ } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) + else if (CONST_STRNEQ (bfd_section_name (s), ".rela")) { if (s->size != 0 && s != htab->root.srelplt) relocs = TRUE; @@ -8890,10 +9125,28 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, || !add_dynamic_entry (DT_JMPREL, 0)) return FALSE; + if (htab->variant_pcs + && !add_dynamic_entry (DT_AARCH64_VARIANT_PCS, 0)) + return FALSE; + if (htab->tlsdesc_plt + && !(info->flags & DF_BIND_NOW) && (!add_dynamic_entry (DT_TLSDESC_PLT, 0) || !add_dynamic_entry (DT_TLSDESC_GOT, 0))) return FALSE; + + if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI_PAC) + && (!add_dynamic_entry (DT_AARCH64_BTI_PLT, 0) + || !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0))) + return FALSE; + + else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_BTI) + && !add_dynamic_entry (DT_AARCH64_BTI_PLT, 0)) + return FALSE; + + else if ((elf_aarch64_tdata (output_bfd)->plt_type == PLT_PAC) + && !add_dynamic_entry (DT_AARCH64_PAC_PLT, 0)) + return FALSE; } if (relocs) @@ -8906,7 +9159,8 @@ elfNN_aarch64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->root, maybe_set_textrel, info); + elf_link_hash_traverse (&htab->root, + _bfd_elf_maybe_set_textrel, info); if ((info->flags & DF_TEXTREL) != 0) { @@ -8990,7 +9244,13 @@ elfNN_aarch64_create_small_pltn_entry (struct elf_link_hash_entry *h, gotplt->output_offset + got_offset; /* Copy in the boiler-plate for the PLTn entry. */ - memcpy (plt_entry, elfNN_aarch64_small_plt_entry, PLT_SMALL_ENTRY_SIZE); + memcpy (plt_entry, htab->plt_entry, htab->plt_entry_size); + + /* First instruction in BTI enabled PLT stub is a BTI + instruction so skip it. */ + if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI + && elf_elfheader (output_bfd)->e_type == ET_EXEC) + plt_entry = plt_entry + 4; /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8. ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */ @@ -9208,7 +9468,7 @@ elfNN_aarch64_finish_dynamic_symbol (bfd *output_bfd, } else { -do_glob_dat: + do_glob_dat: BFD_ASSERT ((h->got.offset & 1) == 0); bfd_put_NN (output_bfd, (bfd_vma) 0, htab->root.sgot->contents + h->got.offset); @@ -9295,10 +9555,10 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED, bfd_vma plt_base; - memcpy (htab->root.splt->contents, elfNN_aarch64_small_plt0_entry, - PLT_ENTRY_SIZE); + memcpy (htab->root.splt->contents, htab->plt0_entry, + htab->plt_header_size); elf_section_data (htab->root.splt->output_section)->this_hdr.sh_entsize = - PLT_ENTRY_SIZE; + htab->plt_header_size; plt_got_2nd_ent = (htab->root.sgotplt->output_section->vma + htab->root.sgotplt->output_offset @@ -9307,18 +9567,24 @@ elfNN_aarch64_init_small_plt0_entry (bfd *output_bfd ATTRIBUTE_UNUSED, plt_base = htab->root.splt->output_section->vma + htab->root.splt->output_offset; + /* First instruction in BTI enabled PLT stub is a BTI + instruction so skip it. */ + bfd_byte *plt0_entry = htab->root.splt->contents; + if (elf_aarch64_tdata (output_bfd)->plt_type & PLT_BTI) + plt0_entry = plt0_entry + 4; + /* Fill in the top 21 bits for this: ADRP x16, PLT_GOT + n * 8. ADRP: ((PG(S+A)-PG(P)) >> 12) & 0x1fffff */ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL, - htab->root.splt->contents + 4, + plt0_entry + 4, PG (plt_got_2nd_ent) - PG (plt_base + 4)); elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_LDSTNN_LO12, - htab->root.splt->contents + 8, + plt0_entry + 8, PG_OFFSET (plt_got_2nd_ent)); elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADD_LO12, - htab->root.splt->contents + 12, + plt0_entry + 12, PG_OFFSET (plt_got_2nd_ent)); } @@ -9378,6 +9644,7 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, case DT_TLSDESC_GOT: s = htab->root.sgot; + BFD_ASSERT (htab->dt_tlsdesc_got != (bfd_vma)-1); dyn.d_un.d_ptr = s->output_section->vma + s->output_offset + htab->dt_tlsdesc_got; break; @@ -9397,14 +9664,23 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, this_hdr.sh_entsize = htab->plt_entry_size; - if (htab->tlsdesc_plt) + if (htab->tlsdesc_plt && !(info->flags & DF_BIND_NOW)) { + BFD_ASSERT (htab->dt_tlsdesc_got != (bfd_vma)-1); bfd_put_NN (output_bfd, (bfd_vma) 0, htab->root.sgot->contents + htab->dt_tlsdesc_got); + const bfd_byte *entry = elfNN_aarch64_tlsdesc_small_plt_entry; + htab->tlsdesc_plt_entry_size = PLT_TLSDESC_ENTRY_SIZE; + + aarch64_plt_type type = elf_aarch64_tdata (output_bfd)->plt_type; + if (type == PLT_BTI || type == PLT_BTI_PAC) + { + entry = elfNN_aarch64_tlsdesc_small_plt_bti_entry; + } + memcpy (htab->root.splt->contents + htab->tlsdesc_plt, - elfNN_aarch64_tlsdesc_small_plt_entry, - sizeof (elfNN_aarch64_tlsdesc_small_plt_entry)); + entry, htab->tlsdesc_plt_entry_size); { bfd_vma adrp1_addr = @@ -9426,6 +9702,15 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, bfd_byte *plt_entry = htab->root.splt->contents + htab->tlsdesc_plt; + /* First instruction in BTI enabled PLT stub is a BTI + instruction so skip it. */ + if (type & PLT_BTI) + { + plt_entry = plt_entry + 4; + adrp1_addr = adrp1_addr + 4; + adrp2_addr = adrp2_addr + 4; + } + /* adrp x2, DT_TLSDESC_GOT */ elf_aarch64_update_plt_entry (output_bfd, BFD_RELOC_AARCH64_ADR_HI21_PCREL, @@ -9504,6 +9789,57 @@ elfNN_aarch64_finish_dynamic_sections (bfd *output_bfd, return TRUE; } +/* Check if BTI enabled PLTs are needed. Returns the type needed. */ +static aarch64_plt_type +get_plt_type (bfd *abfd) +{ + aarch64_plt_type ret = PLT_NORMAL; + bfd_byte *contents, *extdyn, *extdynend; + asection *sec = bfd_get_section_by_name (abfd, ".dynamic"); + if (!sec || !bfd_malloc_and_get_section (abfd, sec, &contents)) + return ret; + extdyn = contents; + extdynend = contents + sec->size; + for (; extdyn < extdynend; extdyn += sizeof (ElfNN_External_Dyn)) + { + Elf_Internal_Dyn dyn; + bfd_elfNN_swap_dyn_in (abfd, extdyn, &dyn); + + /* Let's check the processor specific dynamic array tags. */ + bfd_vma tag = dyn.d_tag; + if (tag < DT_LOPROC || tag > DT_HIPROC) + continue; + + switch (tag) + { + case DT_AARCH64_BTI_PLT: + ret |= PLT_BTI; + break; + + case DT_AARCH64_PAC_PLT: + ret |= PLT_PAC; + break; + + default: break; + } + } + free (contents); + return ret; +} + +static long +elfNN_aarch64_get_synthetic_symtab (bfd *abfd, + long symcount, + asymbol **syms, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + elf_aarch64_tdata (abfd)->plt_type = get_plt_type (abfd); + return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms, + dynsymcount, dynsyms, ret); +} + /* Return address for Ith PLT stub in section PLT, for relocation REL or (bfd_vma) -1 if it should not be included. */ @@ -9511,7 +9847,27 @@ static bfd_vma elfNN_aarch64_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel ATTRIBUTE_UNUSED) { - return plt->vma + PLT_ENTRY_SIZE + i * PLT_SMALL_ENTRY_SIZE; + size_t plt0_size = PLT_ENTRY_SIZE; + size_t pltn_size = PLT_SMALL_ENTRY_SIZE; + + if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI_PAC) + { + if (elf_elfheader (plt->owner)->e_type == ET_EXEC) + pltn_size = PLT_BTI_PAC_SMALL_ENTRY_SIZE; + else + pltn_size = PLT_PAC_SMALL_ENTRY_SIZE; + } + else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_BTI) + { + if (elf_elfheader (plt->owner)->e_type == ET_EXEC) + pltn_size = PLT_BTI_SMALL_ENTRY_SIZE; + } + else if (elf_aarch64_tdata (plt->owner)->plt_type == PLT_PAC) + { + pltn_size = PLT_PAC_SMALL_ENTRY_SIZE; + } + + return plt->vma + plt0_size + i * pltn_size; } /* Returns TRUE if NAME is an AArch64 mapping symbol. @@ -9548,6 +9904,61 @@ elfNN_aarch64_backend_symbol_processing (bfd *abfd, asymbol *sym) sym->flags |= BSF_KEEP; } +/* Implement elf_backend_setup_gnu_properties for AArch64. It serves as a + wrapper function for _bfd_aarch64_elf_link_setup_gnu_properties to account + for the effect of GNU properties of the output_bfd. */ +static bfd * +elfNN_aarch64_link_setup_gnu_properties (struct bfd_link_info *info) +{ + uint32_t prop = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop; + bfd *pbfd = _bfd_aarch64_elf_link_setup_gnu_properties (info, &prop); + elf_aarch64_tdata (info->output_bfd)->gnu_and_prop = prop; + elf_aarch64_tdata (info->output_bfd)->plt_type + |= (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) ? PLT_BTI : 0; + setup_plt_values (info, elf_aarch64_tdata (info->output_bfd)->plt_type); + return pbfd; +} + +/* Implement elf_backend_merge_gnu_properties for AArch64. It serves as a + wrapper function for _bfd_aarch64_elf_merge_gnu_properties to account + for the effect of GNU properties of the output_bfd. */ +static bfd_boolean +elfNN_aarch64_merge_gnu_properties (struct bfd_link_info *info, + bfd *abfd, bfd *bbfd, + elf_property *aprop, + elf_property *bprop) +{ + uint32_t prop + = elf_aarch64_tdata (info->output_bfd)->gnu_and_prop; + + /* If output has been marked with BTI using command line argument, give out + warning if necessary. */ + /* Properties are merged per type, hence only check for warnings when merging + GNU_PROPERTY_AARCH64_FEATURE_1_AND. */ + if (((aprop && aprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) + || (bprop && bprop->pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND)) + && (prop & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) + && (!elf_aarch64_tdata (info->output_bfd)->no_bti_warn)) + { + if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) + || !aprop) + { + _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when " + "all inputs do not have BTI in NOTE section."), + abfd); + } + if ((bprop && !(bprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) + || !bprop) + { + _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when " + "all inputs do not have BTI in NOTE section."), + bbfd); + } + } + + return _bfd_aarch64_elf_merge_gnu_properties (info, abfd, aprop, + bprop, prop); +} /* We use this so we can override certain functions (though currently we don't). */ @@ -9619,8 +10030,8 @@ const struct elf_size_info elfNN_aarch64_size_info = #define bfd_elfNN_find_inliner_info \ elfNN_aarch64_find_inliner_info -#define bfd_elfNN_find_nearest_line \ - elfNN_aarch64_find_nearest_line +#define bfd_elfNN_get_synthetic_symtab \ + elfNN_aarch64_get_synthetic_symtab #define bfd_elfNN_mkobject \ elfNN_aarch64_mkobject @@ -9640,6 +10051,9 @@ const struct elf_size_info elfNN_aarch64_size_info = #define elf_backend_copy_indirect_symbol \ elfNN_aarch64_copy_indirect_symbol +#define elf_backend_merge_symbol_attribute \ + elfNN_aarch64_merge_symbol_attribute + /* Create .dynbss, and .rela.bss sections in DYNOBJ, and set up shortcuts to them in our hash. */ #define elf_backend_create_dynamic_sections \ @@ -9660,11 +10074,14 @@ const struct elf_size_info elfNN_aarch64_size_info = #define elf_backend_output_arch_local_syms \ elfNN_aarch64_output_arch_local_syms +#define elf_backend_maybe_function_sym \ + elfNN_aarch64_maybe_function_sym + #define elf_backend_plt_sym_val \ elfNN_aarch64_plt_sym_val -#define elf_backend_post_process_headers \ - elfNN_aarch64_post_process_headers +#define elf_backend_init_file_header \ + elfNN_aarch64_init_file_header #define elf_backend_relocate_section \ elfNN_aarch64_relocate_section @@ -9687,6 +10104,12 @@ const struct elf_size_info elfNN_aarch64_size_info = #define elf_backend_symbol_processing \ elfNN_aarch64_backend_symbol_processing +#define elf_backend_setup_gnu_properties \ + elfNN_aarch64_link_setup_gnu_properties + +#define elf_backend_merge_gnu_properties \ + elfNN_aarch64_merge_gnu_properties + #define elf_backend_can_refcount 1 #define elf_backend_can_gc_sections 1 #define elf_backend_plt_readonly 1