return &ret->root.root;
}
+/* Perform relocation R_TYPE. Returns TRUE upon success, FALSE otherwise. */
+
static bfd_boolean
aarch64_relocate (unsigned int r_type, bfd *input_bfd, asection *input_section,
bfd_vma offset, bfd_vma value)
value = _bfd_aarch64_elf_resolve_relocation (r_type, place, value, 0, FALSE);
return _bfd_aarch64_elf_put_addend (input_bfd,
input_section->contents + offset, r_type,
- howto, value);
+ howto, value) == bfd_reloc_ok;
}
static enum elf_aarch64_stub_type
switch (stub_entry->stub_type)
{
case aarch64_stub_adrp_branch:
- if (aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
- stub_entry->stub_offset, sym_value))
+ if (!aarch64_relocate (AARCH64_R (ADR_PREL_PG_HI21), stub_bfd, stub_sec,
+ stub_entry->stub_offset, sym_value))
/* The stub would not have been relaxed if the offset was out
of range. */
BFD_FAIL ();
- if (aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
- stub_entry->stub_offset + 4, sym_value))
+ if (!aarch64_relocate (AARCH64_R (ADD_ABS_LO12_NC), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value))
BFD_FAIL ();
break;
case aarch64_stub_long_branch:
/* We want the value relative to the address 12 bytes back from the
value itself. */
- if (aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
- stub_entry->stub_offset + 16, sym_value + 12))
+ if (!aarch64_relocate (AARCH64_R (PRELNN), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 16, sym_value + 12))
BFD_FAIL ();
break;
break;
case aarch64_stub_erratum_843419_veneer:
- if (aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
- stub_entry->stub_offset + 4, sym_value + 4))
+ if (!aarch64_relocate (AARCH64_R (JUMP26), stub_bfd, stub_sec,
+ stub_entry->stub_offset + 4, sym_value + 4))
BFD_FAIL ();
break;
uint32_t v = 0;
uint32_t opc_v = 0;
- /* Bail out quickly if INSN doesn't fall into the the load-store
+ /* Bail out quickly if INSN doesn't fall into the load-store
encoding space. */
if (!AARCH64_LDST (insn))
return FALSE;
= elfNN_aarch64_bfd_reloc_from_howto (howto);
unsigned long r_symndx;
bfd_byte *hit_data = contents + rel->r_offset;
- bfd_vma place, off, got_entry_addr;
+ bfd_vma place, off, got_entry_addr = 0;
bfd_signed_vma signed_addend;
struct elf_aarch64_link_hash_table *globals;
bfd_boolean weak_undef_p;
bfd_boolean relative_reloc;
asection *base_got;
bfd_vma orig_value = value;
+ bfd_boolean resolved_to_zero;
globals = elf_aarch64_hash_table (info);
const char *name;
bfd_vma addend = 0;
- if ((input_section->flags & SEC_ALLOC) == 0
- || h->plt.offset == (bfd_vma) -1)
- abort ();
+ if ((input_section->flags & SEC_ALLOC) == 0)
+ {
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING
+ sections because such sections are not SEC_ALLOC and
+ thus ld.so will not process them. */
+ if ((input_section->flags & SEC_DEBUGGING) != 0)
+ return bfd_reloc_ok;
+
+ if (h->root.root.string)
+ name = h->root.root.string;
+ else
+ name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, NULL);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+ input_bfd, input_section, rel->r_offset, howto->name, name);
+ bfd_set_error (bfd_error_bad_value);
+ return bfd_reloc_notsupported;
+ }
+ else if (h->plt.offset == (bfd_vma) -1)
+ goto bad_ifunc_reloc;
/* STT_GNU_IFUNC symbol must go through PLT. */
plt = globals->root.splt ? globals->root.splt : globals->root.iplt;
switch (bfd_r_type)
{
default:
+bad_ifunc_reloc:
if (h->root.root.string)
name = h->root.root.string;
else
"symbol `%s' isn't handled by %s"), input_bfd,
howto->name, name, __FUNCTION__);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
case BFD_RELOC_AARCH64_NN:
if (rel->r_addend != 0)
"symbol `%s' has non-zero addend: %Ld"),
input_bfd, howto->name, name, rel->r_addend);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
}
/* Generate dynamic relocation only when there is a
}
}
+ resolved_to_zero = (h != NULL
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+
switch (bfd_r_type)
{
case BFD_RELOC_AARCH64_NONE:
|| globals->root.is_relocatable_executable)
&& (input_section->flags & SEC_ALLOC)
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
|| h->root.type != bfd_link_hash_undefweak))
/* Or we are creating an executable, we may need to keep relocations
for symbols satisfied by a dynamic library if we manage to avoid
input_bfd, elfNN_aarch64_howto_table[howto_index].name,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ return bfd_reloc_notsupported;
}
/* Fall through. */
r_symndx = ELFNN_R_SYM (rel->r_info);
r_type = ELFNN_R_TYPE (rel->r_info);
- bfd_reloc.howto = elfNN_aarch64_howto_from_type (r_type);
- howto = bfd_reloc.howto;
+ howto = bfd_reloc.howto = elfNN_aarch64_howto_from_type (r_type);
if (howto == NULL)
- {
- /* xgettext:c-format */
- _bfd_error_handler
- (_("%B: unrecognized relocation (0x%x) in section `%A'"),
- input_bfd, r_type, input_section);
- return FALSE;
- }
+ return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
+
bfd_r_type = elfNN_aarch64_bfd_reloc_from_howto (howto);
h = NULL;
return TRUE;
}
-/* Update the got entry reference counts for the section being removed. */
-
-static bfd_boolean
-elfNN_aarch64_gc_sweep_hook (bfd *abfd,
- struct bfd_link_info *info,
- asection *sec,
- const Elf_Internal_Rela * relocs)
-{
- struct elf_aarch64_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- struct elf_aarch64_local_symbol *locals;
- const Elf_Internal_Rela *rel, *relend;
-
- if (bfd_link_relocatable (info))
- return TRUE;
-
- htab = elf_aarch64_hash_table (info);
-
- if (htab == NULL)
- return FALSE;
-
- elf_section_data (sec)->local_dynrel = NULL;
-
- symtab_hdr = &elf_symtab_hdr (abfd);
- sym_hashes = elf_sym_hashes (abfd);
-
- locals = elf_aarch64_locals (abfd);
-
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
- {
- unsigned long r_symndx;
- unsigned int r_type;
- struct elf_link_hash_entry *h = NULL;
-
- r_symndx = ELFNN_R_SYM (rel->r_info);
-
- if (r_symndx >= symtab_hdr->sh_info)
- {
-
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- }
- else
- {
- Elf_Internal_Sym *isym;
-
- /* A local symbol. */
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
- abfd, r_symndx);
-
- /* Check relocation against local STT_GNU_IFUNC symbol. */
- if (isym != NULL
- && ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
- {
- h = elfNN_aarch64_get_local_sym_hash (htab, abfd, rel, FALSE);
- if (h == NULL)
- abort ();
- }
- }
-
- if (h)
- {
- struct elf_aarch64_link_hash_entry *eh;
- struct elf_dyn_relocs **pp;
- struct elf_dyn_relocs *p;
-
- eh = (struct elf_aarch64_link_hash_entry *) h;
-
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
- if (p->sec == sec)
- {
- /* Everything must go for SEC. */
- *pp = p->next;
- break;
- }
- }
-
- r_type = ELFNN_R_TYPE (rel->r_info);
- switch (aarch64_tls_transition (abfd,info, r_type, h ,r_symndx))
- {
- case BFD_RELOC_AARCH64_ADR_GOT_PAGE:
- case BFD_RELOC_AARCH64_GOT_LD_PREL19:
- case BFD_RELOC_AARCH64_LD32_GOTPAGE_LO14:
- case BFD_RELOC_AARCH64_LD32_GOT_LO12_NC:
- case BFD_RELOC_AARCH64_LD64_GOTOFF_LO15:
- case BFD_RELOC_AARCH64_LD64_GOTPAGE_LO15:
- case BFD_RELOC_AARCH64_LD64_GOT_LO12_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_GOTOFF_G1:
- case BFD_RELOC_AARCH64_TLSDESC_ADD_LO12:
- case BFD_RELOC_AARCH64_TLSDESC_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSDESC_ADR_PREL21:
- case BFD_RELOC_AARCH64_TLSDESC_LD32_LO12_NC:
- case BFD_RELOC_AARCH64_TLSDESC_LD64_LO12:
- case BFD_RELOC_AARCH64_TLSDESC_LD_PREL19:
- case BFD_RELOC_AARCH64_TLSDESC_OFF_G0_NC:
- case BFD_RELOC_AARCH64_TLSDESC_OFF_G1:
- case BFD_RELOC_AARCH64_TLSGD_ADD_LO12_NC:
- case BFD_RELOC_AARCH64_TLSGD_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSGD_ADR_PREL21:
- case BFD_RELOC_AARCH64_TLSGD_MOVW_G0_NC:
- case BFD_RELOC_AARCH64_TLSGD_MOVW_G1:
- case BFD_RELOC_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- case BFD_RELOC_AARCH64_TLSIE_LD32_GOTTPREL_LO12_NC:
- case BFD_RELOC_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
- case BFD_RELOC_AARCH64_TLSIE_LD_GOTTPREL_PREL19:
- case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC:
- case BFD_RELOC_AARCH64_TLSIE_MOVW_GOTTPREL_G1:
- case BFD_RELOC_AARCH64_TLSLD_ADD_LO12_NC:
- case BFD_RELOC_AARCH64_TLSLD_ADR_PAGE21:
- case BFD_RELOC_AARCH64_TLSLD_ADR_PREL21:
- if (h != NULL)
- {
- if (h->got.refcount > 0)
- h->got.refcount -= 1;
-
- if (h->type == STT_GNU_IFUNC)
- {
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- }
- else if (locals != NULL)
- {
- if (locals[r_symndx].got_refcount > 0)
- locals[r_symndx].got_refcount -= 1;
- }
- break;
-
- case BFD_RELOC_AARCH64_CALL26:
- case BFD_RELOC_AARCH64_JUMP26:
- /* If this is a local symbol then we resolve it
- directly without creating a PLT entry. */
- if (h == NULL)
- continue;
-
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- break;
-
- case BFD_RELOC_AARCH64_ADD_LO12:
- case BFD_RELOC_AARCH64_ADR_HI21_NC_PCREL:
- case BFD_RELOC_AARCH64_ADR_HI21_PCREL:
- case BFD_RELOC_AARCH64_ADR_LO21_PCREL:
- case BFD_RELOC_AARCH64_LDST128_LO12:
- case BFD_RELOC_AARCH64_LDST16_LO12:
- case BFD_RELOC_AARCH64_LDST32_LO12:
- case BFD_RELOC_AARCH64_LDST64_LO12:
- case BFD_RELOC_AARCH64_LDST8_LO12:
- case BFD_RELOC_AARCH64_LD_LO19_PCREL:
- case BFD_RELOC_AARCH64_MOVW_G0_NC:
- case BFD_RELOC_AARCH64_MOVW_G1_NC:
- case BFD_RELOC_AARCH64_MOVW_G2_NC:
- case BFD_RELOC_AARCH64_MOVW_G3:
- case BFD_RELOC_AARCH64_NN:
- if (h != NULL && !bfd_link_pic (info))
- {
- if (h->plt.refcount > 0)
- h->plt.refcount -= 1;
- }
- break;
-
- default:
- break;
- }
- }
-
- return TRUE;
-}
-
/* Return true if we need copy relocation against EH. */
static bfd_boolean
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
+ if (h->is_weakalias)
{
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
- h->non_got_ref = h->u.weakdef->non_got_ref;
+ h->non_got_ref = def->non_got_ref;
return TRUE;
}
const asection *rel_sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *rela)
{
+ struct elf_aarch64_link_hash_table *htab = elf_aarch64_hash_table (info);
+
+ if (htab->root.dynsym != NULL
+ && htab->root.dynsym->contents != NULL)
+ {
+ /* Check relocation against STT_GNU_IFUNC symbol if there are
+ dynamic symbols. */
+ bfd *abfd = info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned long r_symndx = ELFNN_R_SYM (rela->r_info);
+ if (r_symndx != STN_UNDEF)
+ {
+ Elf_Internal_Sym sym;
+ if (!bed->s->swap_symbol_in (abfd,
+ (htab->root.dynsym->contents
+ + r_symndx * bed->s->sizeof_sym),
+ 0, &sym))
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B symbol number %lu references"
+ " nonexistent SHT_SYMTAB_SHNDX section"),
+ abfd, r_symndx);
+ /* Ideally an error class should be returned here. */
+ }
+ else if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+ return reloc_class_ifunc;
+ }
+ }
+
switch ((int) ELFNN_R_TYPE (rela->r_info))
{
+ case AARCH64_R (IRELATIVE):
+ return reloc_class_ifunc;
case AARCH64_R (RELATIVE):
return reloc_class_relative;
case AARCH64_R (JUMP_SLOT):
if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& (bfd_link_pic (info)
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
{
htab->root.srelgot->size += RELOC_SIZE (htab);
}
visibility. */
if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
eh->dyn_relocs = NULL;
/* Make sure undefined weak symbols are output as a dynamic
{
reloc_howto_type *howto = elfNN_aarch64_howto_from_bfd_reloc (r_type);
- _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
+ /* FIXME: We should check the return value from this function call. */
+ (void) _bfd_aarch64_elf_put_addend (output_bfd, plt_entry, r_type, howto, value);
}
static void
}
if (h->got.offset != (bfd_vma) - 1
- && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL)
+ && elf_aarch64_hash_entry (h)->got_type == GOT_NORMAL
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
{
Elf_Internal_Rela rela;
bfd_byte *loc;
#define elf_backend_finish_dynamic_symbol \
elfNN_aarch64_finish_dynamic_symbol
-#define elf_backend_gc_sweep_hook \
- elfNN_aarch64_gc_sweep_hook
-
#define elf_backend_object_p \
elfNN_aarch64_object_p