aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog22
-rw-r--r--bfd/elf32-ppc.c421
-rw-r--r--bfd/elf32-ppc.h4
-rw-r--r--bfd/elf64-ppc.c284
-rw-r--r--ld/ChangeLog4
-rw-r--r--ld/emultempl/ppc32elf.em2
6 files changed, 493 insertions, 244 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index cb65c7d..f6388c1 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,27 @@
2018-04-09 Alan Modra <amodra@gmail.com>
+ * elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
+ for local symbols to..
+ (write_plt_relocs_for_local_syms): ..here. New function.
+ (ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
+ global symbols to..
+ (build_global_entry_stubs_and_plt): ..here. Rename from
+ build_global_entry_stubs.
+ (ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
+ Call write_plt_relocs_for_local_syms.
+ * elf32-ppc.c (get_sym_h): New function.
+ (ppc_elf_relax_section): Use get_sym_h.
+ (ppc_elf_relocate_section): Move output of PLT relocs and glink
+ stubs for local symbols to..
+ (ppc_finish_symbols): ..here. New function.
+ (ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
+ global syms to..
+ (write_global_sym_plt): ..here. New function.
+ * elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
+ (ppc_finish_symbols): Declare.
+
+2018-04-09 Alan Modra <amodra@gmail.com>
+
* elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs.
(ppc_elf_relocate_section): Likewise.
* elf64-ppc.c (ppc64_elf_check_relocs): Handle PLT16_LO_DS.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 9736301..d24b095 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -5085,6 +5085,93 @@ ppc_elf_gc_mark_hook (asection *sec,
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
+
+static bfd_boolean
+get_sym_h (struct elf_link_hash_entry **hp,
+ Elf_Internal_Sym **symp,
+ asection **symsecp,
+ unsigned char **tls_maskp,
+ Elf_Internal_Sym **locsymsp,
+ unsigned long r_symndx,
+ bfd *ibfd)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+ struct elf_link_hash_entry *h;
+
+ 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;
+
+ if (hp != NULL)
+ *hp = h;
+
+ if (symp != NULL)
+ *symp = NULL;
+
+ if (symsecp != NULL)
+ {
+ asection *symsec = NULL;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ symsec = h->root.u.def.section;
+ *symsecp = symsec;
+ }
+
+ if (tls_maskp != NULL)
+ *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
+ }
+ else
+ {
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Sym *locsyms = *locsymsp;
+
+ if (locsyms == NULL)
+ {
+ locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (locsyms == NULL)
+ locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+ symtab_hdr->sh_info,
+ 0, NULL, NULL, NULL);
+ if (locsyms == NULL)
+ return FALSE;
+ *locsymsp = locsyms;
+ }
+ sym = locsyms + r_symndx;
+
+ if (hp != NULL)
+ *hp = NULL;
+
+ if (symp != NULL)
+ *symp = sym;
+
+ if (symsecp != NULL)
+ *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+
+ if (tls_maskp != NULL)
+ {
+ bfd_signed_vma *local_got;
+ unsigned char *tls_mask;
+
+ tls_mask = NULL;
+ local_got = elf_local_got_refcounts (ibfd);
+ if (local_got != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got + symtab_hdr->sh_info);
+ unsigned char *lgot_masks = (unsigned char *)
+ (local_plt + symtab_hdr->sh_info);
+ tls_mask = &lgot_masks[r_symndx];
+ }
+ *tls_maskp = tls_mask;
+ }
+ }
+ return TRUE;
+}
/* Set plt output section type, htab->tls_get_addr, and call the
generic ELF tls_setup function. */
@@ -6892,6 +6979,7 @@ ppc_elf_relax_section (bfd *abfd,
bfd_byte *hit_addr;
unsigned long t0;
struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *isym;
struct plt_entry **plist;
unsigned char sym_type;
@@ -6919,57 +7007,34 @@ ppc_elf_relax_section (bfd *abfd,
}
/* Get the value of the symbol referred to by the reloc. */
- h = NULL;
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- /* A local symbol. */
- Elf_Internal_Sym *isym;
+ if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
+ ELF32_R_SYM (irel->r_info), abfd))
+ goto error_return;
- /* Read this BFD's local symbols. */
- if (isymbuf == NULL)
- {
- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (isymbuf == NULL)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- symtab_hdr->sh_info, 0,
- NULL, NULL, NULL);
- if (isymbuf == 0)
- goto error_return;
- }
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- if (isym->st_shndx == SHN_UNDEF)
+ if (isym != NULL)
+ {
+ if (tsec != NULL)
+ ;
+ else if (isym->st_shndx == SHN_UNDEF)
tsec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS)
tsec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON)
tsec = bfd_com_section_ptr;
- else
- tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
toff = isym->st_value;
sym_type = ELF_ST_TYPE (isym->st_info);
}
else
{
- /* Global symbol handling. */
- unsigned long indx;
-
- indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
- h = elf_sym_hashes (abfd)[indx];
-
- 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;
-
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- tsec = h->root.u.def.section;
- toff = h->root.u.def.value;
- }
+ if (tsec != NULL)
+ toff = h->root.u.def.value;
else if (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak)
{
+ unsigned long indx;
+
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
tsec = bfd_und_section_ptr;
toff = bfd_link_relocatable (link_info) ? indx : 0;
}
@@ -8308,32 +8373,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
(_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
input_bfd, input_section, rel->r_offset, sym_name);
}
- if (h == NULL && (ent->plt.offset & 1) == 0)
- {
- Elf_Internal_Rela rela;
- bfd_byte *loc;
-
- rela.r_offset = (htab->elf.iplt->output_section->vma
- + htab->elf.iplt->output_offset
- + ent->plt.offset);
- rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
- rela.r_addend = relocation;
- loc = htab->elf.irelplt->contents;
- loc += (htab->elf.irelplt->reloc_count++
- * sizeof (Elf32_External_Rela));
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
- htab->local_ifunc_resolver = 1;
-
- ent->plt.offset |= 1;
- }
- if (h == NULL && (ent->glink_offset & 1) == 0)
- {
- unsigned char *p = ((unsigned char *) htab->glink->contents
- + ent->glink_offset);
-
- write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
- ent->glink_offset |= 1;
- }
unresolved_reloc = FALSE;
if (htab->plt_type == PLT_NEW
@@ -10027,27 +10066,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
return ret;
}
-/* Finish up dynamic symbol handling. We set the contents of various
- dynamic sections here. */
+/* Write out the PLT relocs and entries for H. */
static bfd_boolean
-ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
- struct bfd_link_info *info,
- struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym)
+write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
{
- struct ppc_elf_link_hash_table *htab;
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
struct plt_entry *ent;
bfd_boolean doneone;
-#ifdef DEBUG
- fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
- h->root.root.string);
-#endif
-
- htab = ppc_elf_hash_table (info);
- BFD_ASSERT (htab->elf.dynobj != NULL);
-
doneone = FALSE;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
@@ -10090,10 +10118,10 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
/* Fill in the .plt on VxWorks. */
if (bfd_link_pic (info))
{
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_offset),
htab->elf.splt->contents + ent->plt.offset + 0);
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_offset),
htab->elf.splt->contents + ent->plt.offset + 4);
}
@@ -10101,17 +10129,17 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
{
bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_loc),
htab->elf.splt->contents + ent->plt.offset + 0);
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_loc),
htab->elf.splt->contents + ent->plt.offset + 4);
}
- bfd_put_32 (output_bfd, plt_entry[2],
+ bfd_put_32 (info->output_bfd, plt_entry[2],
htab->elf.splt->contents + ent->plt.offset + 8);
- bfd_put_32 (output_bfd, plt_entry[3],
+ bfd_put_32 (info->output_bfd, plt_entry[3],
htab->elf.splt->contents + ent->plt.offset + 12);
/* This instruction is an immediate load. The value loaded is
@@ -10120,7 +10148,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
low-order 16 bits of the load instruction. */
/* NOTE: It appears that this is now an index rather than a
prescaled offset. */
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
plt_entry[4] | reloc_index,
htab->elf.splt->contents + ent->plt.offset + 16);
/* This instruction is a PC-relative branch whose target is
@@ -10129,21 +10157,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
The address is encoded in bits 6-29, inclusive. The value
stored is right-shifted by two bits, permitting a 26-bit
offset. */
- bfd_put_32 (output_bfd,
+ bfd_put_32 (info->output_bfd,
(plt_entry[5]
| (-(ent->plt.offset + 20) & 0x03fffffc)),
htab->elf.splt->contents + ent->plt.offset + 20);
- bfd_put_32 (output_bfd, plt_entry[6],
+ bfd_put_32 (info->output_bfd, plt_entry[6],
htab->elf.splt->contents + ent->plt.offset + 24);
- bfd_put_32 (output_bfd, plt_entry[7],
+ bfd_put_32 (info->output_bfd, plt_entry[7],
htab->elf.splt->contents + ent->plt.offset + 28);
/* Fill in the GOT entry corresponding to this PLT slot with
the address immediately after the "bctr" instruction
in this PLT entry. */
- bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset + 16),
+ bfd_put_32 (info->output_bfd,
+ (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ + ent->plt.offset + 16),
htab->elf.sgotplt->contents + got_offset);
if (!bfd_link_pic (info))
@@ -10161,7 +10190,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_HA);
rela.r_addend = got_offset;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */
@@ -10171,7 +10200,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO);
rela.r_addend = got_offset;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela);
/* Provide a relocation for the GOT entry corresponding to this
@@ -10182,7 +10211,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
R_PPC_ADDR32);
rela.r_addend = ent->plt.offset + 16;
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
}
/* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
@@ -10217,7 +10246,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+ htab->glink->output_section->vma
+ htab->glink->output_offset);
- bfd_put_32 (output_bfd, val,
+ bfd_put_32 (info->output_bfd, val,
splt->contents + ent->plt.offset);
}
}
@@ -10252,44 +10281,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
if (h->type == STT_GNU_IFUNC && is_static_defined (h))
htab->maybe_local_ifunc_resolver = 1;
}
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-
- if (!h->def_regular)
- {
- /* Mark the symbol as undefined, rather than as
- defined in the .plt section. Leave the value if
- there were any relocations where pointer equality
- matters (this is a clue for the dynamic linker, to
- make function pointer comparisons work between an
- application and shared library), otherwise set it
- to zero. */
- sym->st_shndx = SHN_UNDEF;
- if (!h->pointer_equality_needed)
- sym->st_value = 0;
- else if (!h->ref_regular_nonweak)
- {
- /* This breaks function pointer comparisons, but
- that is better than breaking tests for a NULL
- function pointer. */
- sym->st_value = 0;
- }
- }
- else if (h->type == STT_GNU_IFUNC
- && !bfd_link_pic (info))
- {
- /* Set the value of ifunc symbols in a non-pie
- executable to the glink entry. This is to avoid
- text relocations. We can't do this for ifunc in
- allocate_dynrelocs, as we do for normal dynamic
- function symbols with plt entries, because we need
- to keep the original value around for the ifunc
- relocation. */
- sym->st_shndx = (_bfd_elf_section_from_bfd_section
- (output_bfd, htab->glink->output_section));
- sym->st_value = (ent->glink_offset
- + htab->glink->output_offset
- + htab->glink->output_section->vma);
- }
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
doneone = TRUE;
}
@@ -10298,14 +10290,14 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
|| h->dynindx == -1)
{
unsigned char *p;
- asection *splt = htab->elf.splt;
+ asection *plt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->elf.iplt;
+ plt = htab->elf.iplt;
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
- write_glink_stub (h, ent, splt, p, info);
+ write_glink_stub (h, ent, plt, p, info);
if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
@@ -10314,6 +10306,165 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
else
break;
}
+ return TRUE;
+}
+
+/* Finish up PLT handling. */
+
+bfd_boolean
+ppc_finish_symbols (struct bfd_link_info *info)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+ bfd *ibfd;
+
+ if (!htab)
+ return TRUE;
+
+ elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ bfd_vma *local_got, *end_local_got;
+ struct plt_entry **local_plt, **lplt, **end_local_plt;
+ Elf_Internal_Shdr *symtab_hdr;
+ bfd_size_type locsymcount;
+ Elf_Internal_Sym *local_syms = NULL;
+ struct plt_entry *ent;
+
+ if (!is_ppc_elf (ibfd))
+ continue;
+
+ local_got = elf_local_got_offsets (ibfd);
+ if (!local_got)
+ continue;
+
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+ locsymcount = symtab_hdr->sh_info;
+ end_local_got = local_got + locsymcount;
+ local_plt = (struct plt_entry **) end_local_got;
+ end_local_plt = local_plt + locsymcount;
+ for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+ for (ent = *lplt; ent != NULL; ent = ent->next)
+ {
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ Elf_Internal_Sym *sym;
+ asection *sym_sec;
+ asection *plt, *relplt;
+ bfd_byte *loc;
+ bfd_vma val;
+ Elf_Internal_Rela rela;
+
+ if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+ lplt - local_plt, ibfd))
+ {
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ return FALSE;
+ }
+
+ val = sym->st_value;
+ if (sym_sec != NULL && sym_sec->output_section != NULL)
+ val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+ BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+ htab->local_ifunc_resolver = 1;
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+
+ rela.r_offset = (ent->plt.offset
+ + plt->output_offset
+ + plt->output_section->vma);
+ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+ rela.r_addend = val;
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf32_External_Rela));
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
+ }
+ if ((ent->glink_offset & 1) == 0)
+ {
+ unsigned char *p = ((unsigned char *) htab->glink->contents
+ + ent->glink_offset);
+
+ write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
+ ent->glink_offset |= 1;
+ }
+ }
+
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ }
+ return TRUE;
+}
+
+/* Finish up dynamic symbol handling. We set the contents of various
+ dynamic sections here. */
+
+static bfd_boolean
+ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+ struct plt_entry *ent;
+
+#ifdef DEBUG
+ fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+ h->root.root.string);
+#endif
+
+ if (!h->def_regular
+ || (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ if (!h->def_regular)
+ {
+ /* Mark the symbol as undefined, rather than as
+ defined in the .plt section. Leave the value if
+ there were any relocations where pointer equality
+ matters (this is a clue for the dynamic linker, to
+ make function pointer comparisons work between an
+ application and shared library), otherwise set it
+ to zero. */
+ sym->st_shndx = SHN_UNDEF;
+ if (!h->pointer_equality_needed)
+ sym->st_value = 0;
+ else if (!h->ref_regular_nonweak)
+ {
+ /* This breaks function pointer comparisons, but
+ that is better than breaking tests for a NULL
+ function pointer. */
+ sym->st_value = 0;
+ }
+ }
+ else
+ {
+ /* Set the value of ifunc symbols in a non-pie
+ executable to the glink entry. This is to avoid
+ text relocations. We can't do this for ifunc in
+ allocate_dynrelocs, as we do for normal dynamic
+ function symbols with plt entries, because we need
+ to keep the original value around for the ifunc
+ relocation. */
+ sym->st_shndx
+ = (_bfd_elf_section_from_bfd_section
+ (info->output_bfd, htab->glink->output_section));
+ sym->st_value = (ent->glink_offset
+ + htab->glink->output_offset
+ + htab->glink->output_section->vma);
+ }
+ break;
+ }
if (h->needs_copy)
{
diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h
index f56d027..265859b 100644
--- a/bfd/elf32-ppc.h
+++ b/bfd/elf32-ppc.h
@@ -63,6 +63,6 @@ int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *);
asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *);
-extern bfd_boolean ppc_elf_modify_segment_map (bfd *,
- struct bfd_link_info * ATTRIBUTE_UNUSED);
+extern bfd_boolean ppc_elf_modify_segment_map (bfd *, struct bfd_link_info *);
extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *);
+extern bfd_boolean ppc_finish_symbols (struct bfd_link_info *);
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 835baec..8291db8 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -11158,29 +11158,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
dest += plt->output_offset + plt->output_section->vma;
- if (stub_entry->h == NULL
- && (stub_entry->plt_ent->plt.offset & 1) == 0)
- {
- Elf_Internal_Rela rela;
- bfd_byte *rl;
-
- rela.r_offset = dest;
- if (htab->opd_abi)
- rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
- else
- rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
- rela.r_addend = (stub_entry->target_value
- + stub_entry->target_section->output_offset
- + stub_entry->target_section->output_section->vma);
-
- rl = (htab->elf.irelplt->contents
- + (htab->elf.irelplt->reloc_count++
- * 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
- elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
@@ -13016,34 +12993,84 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
}
/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
- write out any global entry stubs. */
+ write out any global entry stubs, and PLT relocations. */
static bfd_boolean
-build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
+build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
{
struct bfd_link_info *info;
struct ppc_link_hash_table *htab;
- struct plt_entry *pent;
+ struct plt_entry *ent;
asection *s;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
+ info = inf;
+ htab = ppc_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ /* This symbol has an entry in the procedure linkage
+ table. Set it up. */
+ Elf_Internal_Rela rela;
+ bfd_byte *loc;
+
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ if (!(h->def_regular
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)))
+ continue;
+ rela.r_offset = (htab->elf.iplt->output_section->vma
+ + htab->elf.iplt->output_offset
+ + ent->plt.offset);
+ if (htab->opd_abi)
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+ else
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+ rela.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.section->output_section->vma
+ + ent->addend);
+ loc = (htab->elf.irelplt->contents
+ + (htab->elf.irelplt->reloc_count++
+ * sizeof (Elf64_External_Rela)));
+ htab->local_ifunc_resolver = 1;
+ }
+ else
+ {
+ rela.r_offset = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ + ent->plt.offset);
+ rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+ rela.r_addend = ent->addend;
+ 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 (info->output_bfd, &rela, loc);
+ }
+
if (!h->pointer_equality_needed)
return TRUE;
if (h->def_regular)
return TRUE;
- info = inf;
- htab = ppc_hash_table (info);
- if (htab == NULL)
- return FALSE;
-
s = htab->global_entry;
- for (pent = h->plt.plist; pent != NULL; pent = pent->next)
- if (pent->plt.offset != (bfd_vma) -1
- && pent->addend == 0)
+ if (s == NULL || s->size == 0)
+ return TRUE;
+
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1
+ && ent->addend == 0)
{
bfd_byte *p;
asection *plt;
@@ -13054,7 +13081,7 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
plt = htab->elf.iplt;
- off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
+ off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
@@ -13108,6 +13135,91 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
return TRUE;
}
+/* Write PLT relocs for locals. */
+
+static bfd_boolean
+write_plt_relocs_for_local_syms (struct bfd_link_info *info)
+{
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ bfd *ibfd;
+
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+ {
+ struct got_entry **lgot_ents, **end_lgot_ents;
+ struct plt_entry **local_plt, **lplt, **end_local_plt;
+ Elf_Internal_Shdr *symtab_hdr;
+ bfd_size_type locsymcount;
+ Elf_Internal_Sym *local_syms = NULL;
+ struct plt_entry *ent;
+
+ if (!is_ppc64_elf (ibfd))
+ continue;
+
+ lgot_ents = elf_local_got_ents (ibfd);
+ if (!lgot_ents)
+ continue;
+
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+ locsymcount = symtab_hdr->sh_info;
+ end_lgot_ents = lgot_ents + locsymcount;
+ local_plt = (struct plt_entry **) end_lgot_ents;
+ end_local_plt = local_plt + locsymcount;
+ for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+ for (ent = *lplt; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ Elf_Internal_Sym *sym;
+ asection *sym_sec;
+ asection *plt, *relplt;
+ bfd_byte *loc;
+ bfd_vma val;
+ Elf_Internal_Rela rela;
+
+ if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+ lplt - local_plt, ibfd))
+ {
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ free (local_syms);
+ return FALSE;
+ }
+
+ val = sym->st_value + ent->addend;
+ val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
+ if (sym_sec != NULL && sym_sec->output_section != NULL)
+ val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+ BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
+
+ htab->local_ifunc_resolver = 1;
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+
+ rela.r_offset = (ent->plt.offset
+ + plt->output_offset
+ + plt->output_section->vma);
+ if (htab->opd_abi)
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+ else
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+ rela.r_addend = val;
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf64_External_Rela));
+ bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+ }
+
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (!info->keep_memory)
+ free (local_syms);
+ else
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ }
+ return TRUE;
+}
+
/* Build all the stubs associated with the current output file.
The stubs are kept in a hash table attached to the main linker
hash table. This function is called via gldelf64ppc_finish. */
@@ -13262,9 +13374,11 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
}
}
- /* Build .glink global entry stubs. */
- if (htab->global_entry != NULL && htab->global_entry->size != 0)
- elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
+ /* Build .glink global entry stubs, and PLT relocs for globals. */
+ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
+
+ if (!write_plt_relocs_for_local_syms (info))
+ return FALSE;
if (htab->brlt != NULL && htab->brlt->size != 0)
{
@@ -15488,85 +15602,41 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
{
struct ppc_link_hash_table *htab;
struct plt_entry *ent;
- Elf_Internal_Rela rela;
- bfd_byte *loc;
htab = ppc_hash_table (info);
if (htab == NULL)
return FALSE;
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
- if (ent->plt.offset != (bfd_vma) -1)
- {
- /* This symbol has an entry in the procedure linkage
- table. Set it up. */
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- {
- BFD_ASSERT (h->type == STT_GNU_IFUNC
- && h->def_regular
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak));
- rela.r_offset = (htab->elf.iplt->output_section->vma
- + htab->elf.iplt->output_offset
- + ent->plt.offset);
- if (htab->opd_abi)
- rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
- else
- rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
- rela.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_offset
- + h->root.u.def.section->output_section->vma
- + ent->addend);
- loc = (htab->elf.irelplt->contents
- + (htab->elf.irelplt->reloc_count++
- * sizeof (Elf64_External_Rela)));
- htab->local_ifunc_resolver = 1;
- }
- else
- {
- rela.r_offset = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset);
- rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
- rela.r_addend = ent->addend;
- 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);
-
- if (!htab->opd_abi)
- {
- if (!h->def_regular)
- {
- /* Mark the symbol as undefined, rather than as
- defined in glink. Leave the value if there were
- any relocations where pointer equality matters
- (this is a clue for the dynamic linker, to make
- function pointer comparisons work between an
- application and shared library), otherwise set it
- to zero. */
- sym->st_shndx = SHN_UNDEF;
- if (!h->pointer_equality_needed)
- sym->st_value = 0;
- else if (!h->ref_regular_nonweak)
- {
- /* This breaks function pointer comparisons, but
- that is better than breaking tests for a NULL
- function pointer. */
- sym->st_value = 0;
- }
- }
- }
- }
+ if (!htab->opd_abi && !h->def_regular)
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.offset != (bfd_vma) -1)
+ {
+ /* Mark the symbol as undefined, rather than as
+ defined in glink. Leave the value if there were
+ any relocations where pointer equality matters
+ (this is a clue for the dynamic linker, to make
+ function pointer comparisons work between an
+ application and shared library), otherwise set it
+ to zero. */
+ sym->st_shndx = SHN_UNDEF;
+ if (!h->pointer_equality_needed)
+ sym->st_value = 0;
+ else if (!h->ref_regular_nonweak)
+ {
+ /* This breaks function pointer comparisons, but
+ that is better than breaking tests for a NULL
+ function pointer. */
+ sym->st_value = 0;
+ }
+ break;
+ }
if (h->needs_copy)
{
/* This symbol needs a copy reloc. Set it up. */
+ Elf_Internal_Rela rela;
asection *srel;
+ bfd_byte *loc;
if (h->dynindx == -1
|| (h->root.type != bfd_link_hash_defined
diff --git a/ld/ChangeLog b/ld/ChangeLog
index b2fd135..4e697a3 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,7 @@
+2018-04-09 Alan Modra <amodra@gmail.com>
+
+ * ppc32elf.em (ppc_finish): Call ppc_finish_symbols.
+
2018-04-05 H.J. Lu <hongjiu.lu@intel.com>
PR gas/22318
diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index 3c335b7..05a2894 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -212,6 +212,8 @@ ppc_finish (void)
{
if (params.ppc476_workaround)
lang_for_each_statement (no_zero_padding);
+ if (!ppc_finish_symbols (&link_info))
+ einfo (_("%X%P: ppc_finish_symbols problem %E\n"));
finish_default ();
}