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 */
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 */
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 */
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;
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
_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
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)
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)
{
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 ();
/* 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);
}
(*htab->layout_sections_again) ();
}
- if (htab->fix_erratum_843419)
+ if (htab->fix_erratum_843419 != ERRAT_NONE)
{
bfd *input_bfd;
int no_enum_warn,
int no_wchar_warn, int pic_veneer,
int fix_erratum_835769,
- int fix_erratum_843419,
+ erratum_84319_opts fix_erratum_843419,
int no_apply_dynamic_relocs,
aarch64_bti_pac_info bp_info)
{
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));
|| 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);
((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;
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;
}
clear_erratum_843419_entry (struct elf_aarch64_link_hash_table *globals,
bfd_vma adrp_offset, asection *input_section)
{
- if (globals->fix_erratum_843419)
+ if (globals->fix_erratum_843419 & ERRAT_ADRP)
{
struct erratum_843419_branch_to_stub_clear_data data;
data.adrp_offset = adrp_offset;
BFD_AARCH64_SPECIAL_SYM_TYPE_ANY);
}
-/* This is a copy of elf_find_function () from elf.c except that
+/* This is a version of _bfd_elf_find_function() from dwarf2.c except that
AArch64 mapping symbols are ignored when looking for function names. */
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)
+aarch64_elf_find_function (bfd * abfd,
+ 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;
+ if (symbols == NULL)
+ return FALSE;
+
+ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+ return FALSE;
+
for (p = symbols; *p != NULL; p++)
{
elf_symbol_type *q;
updated. */
htab->root.srelplt->reloc_count++;
+
+ /* Mark the DSO in case R_<CLS>_JUMP_SLOT relocs against
+ variant PCS symbols are present. */
+ if (h->other & STO_AARCH64_VARIANT_PCS)
+ htab->variant_pcs = 1;
+
}
else
{
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. */
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,
|| !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)
if ((aprop && !(aprop->u.number & GNU_PROPERTY_AARCH64_FEATURE_1_BTI))
|| !aprop)
{
- _bfd_error_handler (_("%pB: warning: BTI turned on by --force-bti when "
+ _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 --force-bti when "
+ _bfd_error_handler (_("%pB: warning: BTI turned on by -z force-bti when "
"all inputs do not have BTI in NOTE section."),
bbfd);
}
#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 \