#define elf_backend_special_sections ppc64_elf_special_sections
#define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute
#define elf_backend_merge_symbol ppc64_elf_merge_symbol
+#define elf_backend_get_reloc_section bfd_get_section_by_name
/* The name of the dynamic interpreter. This is put in the .interp
section. */
/* Set the howto pointer for a PowerPC ELF reloc. */
static void
-ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
unsigned int type;
if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
return 1;
- return 0;
+ return a > b;
}
/* Search SYMS for a symbol of the given VALUE. */
}
}
+/* Whether an undefined weak symbol should resolve to its link-time
+ value, even in PIC or PIE objects. */
+#define UNDEFWEAK_NO_DYNAMIC_RELOC(INFO, H) \
+ ((H)->root.type == bfd_link_hash_undefweak \
+ && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT \
+ || (INFO)->dynamic_undefined_weak == 0))
+
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
copying dynamic variables from a shared lib into an app's dynbss
section, and instead use a dynamic relocation to point into the
/* Whether func_desc_adjust needs to be run over symbols. */
unsigned int need_func_desc_adj:1;
+ /* Whether there exist local gnu indirect function resolvers,
+ referenced by dynamic relocations. */
+ unsigned int local_ifunc_resolver:1;
+ unsigned int maybe_local_ifunc_resolver:1;
+
/* Incremented every time we size stubs. */
unsigned int stub_iteration;
tocsave_htab_hash (const void *p)
{
const struct tocsave_entry *e = (const struct tocsave_entry *) p;
- return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
+ return ((bfd_vma) (intptr_t) e->sec ^ e->offset) >> 3;
}
static int
/* Propagate reference flags from entry symbol to function
descriptor symbol. */
- fdh->elf.root.non_ir_ref |= eh->elf.root.non_ir_ref;
+ fdh->elf.root.non_ir_ref_regular |= eh->elf.root.non_ir_ref_regular;
+ fdh->elf.root.non_ir_ref_dynamic |= eh->elf.root.non_ir_ref_dynamic;
fdh->elf.ref_regular |= eh->elf.ref_regular;
fdh->elf.ref_regular_nonweak |= eh->elf.ref_regular_nonweak;
/* PR15323, ref flags aren't set for references in the same
object. */
- h->root.non_ir_ref = 1;
+ h->root.non_ir_ref_regular = 1;
if (eh->is_func && eh->oh != NULL)
- eh->oh->elf.root.non_ir_ref = 1;
+ eh->oh->elf.root.non_ir_ref_regular = 1;
if (h == htab->elf.hgot)
sec->has_toc_reloc = 1;
unsigned long r_symndx;
enum elf_ppc64_reloc_type r_type;
struct elf_link_hash_entry *h = NULL;
- struct plt_entry **plt_list;
+ struct plt_entry **plt_list = NULL;
unsigned char tls_type = 0;
r_symndx = ELF64_R_SYM (rel->r_info);
if (ent->got.refcount > 0)
ent->got.refcount -= 1;
}
+ if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
+ plt_list = &h->plt.plist;
break;
case R_PPC64_PLT16_HA:
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)
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
plt_list = local_plt + r_symndx;
}
- if (plt_list)
- {
- struct plt_entry *ent;
+ break;
- for (ent = *plt_list; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend)
- break;
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- }
+ case R_PPC64_ADDR64:
+ case R_PPC64_ADDR16:
+ case R_PPC64_ADDR16_DS:
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_ADDR16_HIGH:
+ case R_PPC64_ADDR16_HIGHA:
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_ADDR16_LO_DS:
+ if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
+ && rel->r_addend == 0)
+ plt_list = &h->plt.plist;
break;
default:
break;
}
+ if (plt_list != NULL)
+ {
+ struct plt_entry *ent;
+
+ for (ent = *plt_list; ent != NULL; ent = ent->next)
+ if (ent->addend == rel->r_addend)
+ break;
+ if (ent != NULL && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+ }
}
return TRUE;
}
if (ent == NULL
|| (h->type != STT_GNU_IFUNC
&& (SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
|| ((struct ppc_link_hash_entry *) h)->save_res)
{
h->plt.plist = NULL;
if (ent.sec == NULL || ent.sec->output_section == NULL)
{
_bfd_error_handler
- (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
+ (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd);
return NULL;
}
&& (tga_fd->type == STT_FUNC
|| tga_fd->needs_plt)
&& !(SYMBOL_CALLS_LOCAL (info, tga_fd)
- || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT
- && tga_fd->root.type == bfd_link_hash_undefweak)))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga_fd)))
{
struct plt_entry *ent;
|| (htab->elf.dynamic_sections_created
&& h->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, h)))
- && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
{
asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
relgot->size += rentsize;
struct elf_link_hash_table *htab = elf_hash_table (info);
if (htab->dynamic_sections_created
+ && info->dynamic_undefined_weak != 0
&& h->root.type == bfd_link_hash_undefweak
&& h->dynindx == -1
&& !h->forced_local
allocate_got (h, info, gent);
}
+ /* If no dynamic sections we can't have dynamic relocs, except for
+ IFUNCs which are handled even in static executables. */
if (!htab->elf.dynamic_sections_created
&& h->type != STT_GNU_IFUNC)
eh->dyn_relocs = NULL;
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility, or when dynamic_undefined_weak says so. */
+ else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ eh->dyn_relocs = NULL;
+
if (eh->dyn_relocs != NULL)
{
struct elf_dyn_relocs *p, **pp;
}
}
- /* Also discard relocs on undefined weak syms with
- non-default visibility. */
- if (eh->dyn_relocs != NULL
- && h->root.type == bfd_link_hash_undefweak)
+ if (eh->dyn_relocs != NULL)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
-
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
- else if (!ensure_undefweak_dynamic (info, h))
+ if (!ensure_undefweak_dynamic (info, h))
return FALSE;
}
}
* sizeof (Elf64_External_Rela)));
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
stub_entry->plt_ent->plt.offset |= 1;
+ htab->local_ifunc_resolver = 1;
}
off = (dest
addend = 0;
reloc_dest = DEST_STUB;
- if ((stub_entry->stub_type == ppc_stub_plt_call
+ if ((stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
&& (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
if (!htab->elf.dynamic_sections_created
|| h->elf.dynindx == -1
|| SYMBOL_REFERENCES_LOCAL (info, &h->elf)
- || (ELF_ST_VISIBILITY (h->elf.other) != STV_DEFAULT
- && h->elf.root.type == bfd_link_hash_undefweak))
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
? h->elf.type == STT_GNU_IFUNC
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
if (ifunc)
- relgot = htab->elf.irelplt;
+ {
+ relgot = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (&h->elf))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
else if (indx != 0
|| (bfd_link_pic (info)
&& (h == NULL
- || (ELF_ST_VISIBILITY (h->elf.other)
- == STV_DEFAULT)
- || h->elf.root.type != bfd_link_hash_undefweak
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
|| (tls_type == (TLS_TLS | TLS_LD)
&& !h->elf.def_dynamic))))
relgot = ppc64_elf_tdata (ent->owner)->relgot;
bfd_boolean skip, relocate;
asection *sreloc;
bfd_vma out_off;
+ long indx = 0;
/* When generating a dynamic object, these relocations
are copied into the output file to be resolved at run
&& !is_opd
&& r_type != R_PPC64_TOC)
{
- BFD_ASSERT (h->elf.dynindx != -1);
- outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+ indx = h->elf.dynindx;
+ BFD_ASSERT (indx != -1);
+ outrel.r_info = ELF64_R_INFO (indx, r_type);
}
else
{
}
else
{
- long indx = 0;
-
if (h != NULL
? h->elf.type == STT_GNU_IFUNC
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
if (h != NULL
? h->elf.type == STT_GNU_IFUNC
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
- sreloc = htab->elf.irelplt;
+ {
+ sreloc = htab->elf.irelplt;
+ if (indx == 0)
+ htab->local_ifunc_resolver = 1;
+ else if (is_static_defined (&h->elf))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
if (sreloc == NULL)
abort ();
ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+ Elf_Internal_Sym *sym)
{
struct ppc_link_hash_table *htab;
struct plt_entry *ent;
loc = (htab->elf.irelplt->contents
+ (htab->elf.irelplt->reloc_count++
* sizeof (Elf64_External_Rela)));
+ htab->local_ifunc_resolver = 1;
}
else
{
loc = (htab->elf.srelplt->contents
+ ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
/ PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+ if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
}
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
case DT_PLTRELSZ:
dyn.d_un.d_val = htab->elf.srelplt->size;
break;
+
+ case DT_TEXTREL:
+ if (htab->local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%X%P: text relocations and GNU indirect "
+ "functions will result in a segfault at runtime\n"));
+ else if (htab->maybe_local_ifunc_resolver)
+ info->callbacks->einfo
+ (_("%P: warning: text relocations and GNU indirect "
+ "functions may result in a segfault at runtime\n"));
+ continue;
}
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);