#include "objalloc.h"
#include "elf/aarch64.h"
#include "elfxx-aarch64.h"
+#include "cpu-aarch64.h"
#define ARCH_SIZE NN
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 */
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
+ 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;
{
abfd = stub_entry->target_section->owner;
_bfd_error_handler
- (_("%pB: error: erratum 843419 immediate 0x%lx "
+ (_("%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);
/* 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,
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:
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;
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;
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
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);
}
+ 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;
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;
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:
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:
+ 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;
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;
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
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;
(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;
{
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;
}
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)
+static bfd_size_type
+elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
{
- const char *filename = NULL;
- asymbol *func = NULL;
- bfd_vma low_func = 0;
- asymbol **p;
-
- for (p = symbols; *p != NULL; p++)
- {
- elf_symbol_type *q;
+ 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
}
-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
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,
/* 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;
|| !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 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 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 \
#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