/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
+ Copyright (C) 1999-2016 Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra.
htab = ppc_hash_table (info);
- /* Create .sfpr for code to save and restore fp regs. */
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
- flags);
- if (htab->sfpr == NULL
- || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
- return FALSE;
+ if (htab->params->save_restore_funcs)
+ {
+ /* Create .sfpr for code to save and restore fp regs. */
+ htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+ flags);
+ if (htab->sfpr == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+ return FALSE;
+ }
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
/* Create .glink for lazy dynamic linking support. */
htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
linker created stub bfd. This ensures that the GOT header is at
the start of the output TOC section. */
htab = ppc_hash_table (info);
- if (htab == NULL)
- return FALSE;
htab->elf.dynobj = params->stub_bfd;
htab->params = params;
- if (bfd_link_relocatable (info))
- return TRUE;
-
return create_linkage_sections (htab->elf.dynobj, info);
}
enum elf_ppc64_reloc_type r_type;
int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
- struct plt_entry **ifunc;
+ struct plt_entry **ifunc, **plt_list;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
return FALSE;
}
}
- r_type = ELF64_R_TYPE (rel->r_info);
- if (is_branch_reloc (r_type))
- {
- if (h != NULL && (h == tga || h == dottga))
- {
- if (rel != relocs
- && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
- || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
- /* We have a new-style __tls_get_addr call with a marker
- reloc. */
- ;
- else
- /* Mark this section as having an old-style call. */
- sec->has_tls_get_addr_call = 1;
- }
-
- /* STT_GNU_IFUNC symbols must have a PLT entry. */
- if (ifunc != NULL
- && !update_plt_info (abfd, ifunc, rel->r_addend))
- return FALSE;
- }
+ r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
case R_PPC64_TLSGD:
case R_PPC64_PLT16_LO:
case R_PPC64_PLT32:
case R_PPC64_PLT64:
- /* This symbol requires a procedure linkage table entry. We
- actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
- if (h == NULL)
- {
- /* It does not make sense to have a procedure linkage
- table entry for a local symbol. */
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- else
+ /* This symbol requires a procedure linkage table entry. */
+ plt_list = ifunc;
+ if (h != NULL)
{
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
- return FALSE;
h->needs_plt = 1;
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
((struct ppc_link_hash_entry *) h)->is_func = 1;
+ plt_list = &h->plt.plist;
+ }
+ if (plt_list == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a non-ifunc local symbol. */
+ info->callbacks->einfo
+ (_("%P: %H: %s reloc against local symbol\n"),
+ abfd, sec, rel->r_offset,
+ ppc64_elf_howto_table[r_type]->name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
+ if (!update_plt_info (abfd, plt_list, rel->r_addend))
+ return FALSE;
break;
/* The following relocations don't need to propagate the
/* Fall through. */
case R_PPC64_REL24:
- if (h != NULL && ifunc == NULL)
+ plt_list = ifunc;
+ if (h != NULL)
{
- /* We may need a .plt entry if the function this reloc
- refers to is in a shared lib. */
- if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
- return FALSE;
h->needs_plt = 1;
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
((struct ppc_link_hash_entry *) h)->is_func = 1;
+
if (h == tga || h == dottga)
- sec->has_tls_reloc = 1;
+ {
+ sec->has_tls_reloc = 1;
+ if (rel != relocs
+ && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+ || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+ /* We have a new-style __tls_get_addr call with
+ a marker reloc. */
+ ;
+ else
+ /* Mark this section as having an old-style call. */
+ sec->has_tls_get_addr_call = 1;
+ }
+ plt_list = &h->plt.plist;
}
+
+ /* We may need a .plt entry if the function this reloc
+ refers to is in a shared lib. */
+ if (plt_list
+ && !update_plt_info (abfd, plt_list, rel->r_addend))
+ return FALSE;
break;
+ case R_PPC64_ADDR14:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR24:
+ goto dodyn;
+
case R_PPC64_TPREL64:
tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
if (bfd_link_pic (info))
case R_PPC64_REL30:
case R_PPC64_REL32:
case R_PPC64_REL64:
- case R_PPC64_ADDR14:
- case R_PPC64_ADDR14_BRNTAKEN:
- case R_PPC64_ADDR14_BRTAKEN:
- case R_PPC64_ADDR24:
case R_PPC64_ADDR32:
case R_PPC64_UADDR16:
case R_PPC64_UADDR32:
unsigned long r_symndx;
enum elf_ppc64_reloc_type r_type;
struct elf_link_hash_entry *h = NULL;
+ struct plt_entry **plt_list;
unsigned char tls_type = 0;
r_symndx = ELF64_R_SYM (rel->r_info);
}
}
- if (is_branch_reloc (r_type))
- {
- struct plt_entry **ifunc = NULL;
- if (h != NULL)
- {
- if (h->type == STT_GNU_IFUNC)
- ifunc = &h->plt.plist;
- }
- else if (local_got_ents != NULL)
- {
- struct plt_entry **local_plt = (struct plt_entry **)
- (local_got_ents + symtab_hdr->sh_info);
- unsigned char *local_got_tls_masks = (unsigned char *)
- (local_plt + symtab_hdr->sh_info);
- if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
- ifunc = local_plt + r_symndx;
- }
- if (ifunc != NULL)
- {
- struct plt_entry *ent;
-
- for (ent = *ifunc; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend)
- break;
- if (ent == NULL)
- abort ();
- if (ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- continue;
- }
- }
-
switch (r_type)
{
case R_PPC64_GOT_TLSLD16:
case R_PPC64_REL14_BRNTAKEN:
case R_PPC64_REL14_BRTAKEN:
case R_PPC64_REL24:
+ plt_list = NULL;
if (h != NULL)
+ plt_list = &h->plt.plist;
+ else if (local_got_ents != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_ents + symtab_hdr->sh_info);
+ unsigned char *local_got_tls_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+ plt_list = local_plt + r_symndx;
+ }
+ if (plt_list)
{
struct plt_entry *ent;
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ for (ent = *plt_list; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend)
break;
if (ent != NULL && ent->plt.refcount > 0)
sym[len + 0] = i / 10 + '0';
sym[len + 1] = i % 10 + '0';
h = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+ elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE);
if (stub_sec != NULL)
{
if (h != NULL
h->elf.root.u.def.value = htab->sfpr->size;
h->elf.type = STT_FUNC;
h->elf.def_regular = 1;
+ h->elf.non_elf = 0;
_bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE);
writing = TRUE;
if (htab->sfpr->contents == NULL)
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- unsigned int i;
htab = ppc_hash_table (info);
if (htab == NULL)
return FALSE;
- if (!bfd_link_relocatable (info)
- && htab->elf.hgot != NULL)
+ /* Provide any missing _save* and _rest* functions. */
+ if (htab->sfpr != NULL)
+ {
+ unsigned int i;
+
+ htab->sfpr->size = 0;
+ for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+ if (!sfpr_define (info, &save_res_funcs[i], NULL))
+ return FALSE;
+ if (htab->sfpr->size == 0)
+ htab->sfpr->flags |= SEC_EXCLUDE;
+ }
+
+ if (bfd_link_relocatable (info))
+ return TRUE;
+
+ if (htab->elf.hgot != NULL)
{
_bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
/* Make .TOC. defined so as to prevent it being made dynamic.
| STV_HIDDEN);
}
- if (htab->sfpr == NULL)
- /* We don't have any relocs. */
- return TRUE;
-
- /* Provide any missing _save* and _rest* functions. */
- htab->sfpr->size = 0;
- if (htab->params->save_restore_funcs)
- for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
- if (!sfpr_define (info, &save_res_funcs[i], NULL))
- return FALSE;
-
elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
- if (htab->sfpr->size == 0)
- htab->sfpr->flags |= SEC_EXCLUDE;
-
return TRUE;
}
tga_fd->root.type = bfd_link_hash_indirect;
tga_fd->root.u.i.link = &opt_fd->root;
ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+ opt_fd->forced_local = 0;
if (opt_fd->dynindx != -1)
{
/* Use __tls_get_addr_opt in dynamic relocations. */
tga->root.type = bfd_link_hash_indirect;
tga->root.u.i.link = &opt->root;
ppc64_elf_copy_indirect_symbol (info, opt, tga);
+ opt->forced_local = 0;
_bfd_elf_link_hash_hide_symbol (info, opt,
tga->forced_local);
htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
if (!bfd_link_pic (info)
&& !info->traditional_format
&& !htab->opd_abi
+ && rel->r_addend == d_offset
&& h != NULL && &h->elf == htab->elf.hgot
&& rel + 1 < relend
&& rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
case R_PPC64_PLT64:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
+ {
+ struct plt_entry **plt_list = NULL;
+ if (h != NULL)
+ plt_list = &h->elf.plt.plist;
+ else if (local_got_ents != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_ents + symtab_hdr->sh_info);
+ unsigned char *local_got_tls_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+ plt_list = local_plt + r_symndx;
+ }
+ if (plt_list)
+ {
+ struct plt_entry *ent;
- /* Resolve a PLT reloc against a local symbol directly,
- without using the procedure linkage table. */
- if (h == NULL)
- break;
-
- /* It's possible that we didn't make a PLT entry for this
- symbol. This happens when statically linking PIC code,
- or when using -Bsymbolic. Go find a match if there is a
- PLT entry. */
- if (htab->elf.splt != NULL)
- {
- struct plt_entry *ent;
- for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->plt.offset != (bfd_vma) -1
- && ent->addend == orig_rel.r_addend)
- {
- relocation = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset);
- unresolved_reloc = FALSE;
- break;
- }
- }
+ for (ent = *plt_list; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1
+ && ent->addend == orig_rel.r_addend)
+ {
+ asection *plt;
+
+ plt = htab->elf.splt;
+ if (!htab->elf.dynamic_sections_created
+ || h == NULL
+ || h->elf.dynindx == -1)
+ plt = htab->elf.iplt;
+ relocation = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
+ addend = 0;
+ unresolved_reloc = FALSE;
+ break;
+ }
+ }
+ }
break;
case R_PPC64_TOC: