aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2018-04-09 09:22:53 +0930
committerAlan Modra <amodra@gmail.com>2018-04-09 17:05:09 +0930
commit2d7ad24e8726ba4c45c9e67be08223a146a837ce (patch)
tree8a2b8f6e54f874207d4ee8c66f9180448d4f35ca /bfd
parent49c09209d06885dc8350042ce77e442bfbb5bf27 (diff)
downloadgdb-2d7ad24e8726ba4c45c9e67be08223a146a837ce.zip
gdb-2d7ad24e8726ba4c45c9e67be08223a146a837ce.tar.gz
gdb-2d7ad24e8726ba4c45c9e67be08223a146a837ce.tar.bz2
Support PLT16 relocs against local symbols
Necessary if gcc is to use PLT16 relocs to implement -mlongcall, and there isn't a good technical reason why local symbols should be excluded from PLT16 support. Non-ifunc local symbol PLT entries go in a separate section to other PLT entries. In a fixed position executable they won't need to be relocated, and in a PIE or shared library I chose to not implement lazy relocation. bfd/ * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define. (struct ppc_stub_hash_entry): Add symtype field. (PLT_KEEP): Define. (struct ppc_link_hash_table): Add pltlocal and relpltlocal. (create_linkage_sections): Create pltlocal and relpltlocal. (ppc64_elf_check_relocs): Allow PLT relocs on local symbols. Set PLT_KEEP. (ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. (allocate_dynrelocs): Allocate pltlocal and relpltlocal. (ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal. Keep PLT entries for inline calls against locals. (ppc_build_one_stub): Use pltlocal as appropriate. (ppc_size_one_stub): Likewise. (ppc64_elf_size_stubs): Set symtype. (build_global_entry_stubs_and_plt): Init pltlocal and write relpltlocal for globals. (write_plt_relocs_for_local_syms): Likewise for local syms. (ppc64_elf_relocate_section): Support PLT for local syms. * elf32-ppc.c (PLT_KEEP): Define. (struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal. (ppc_elf_create_glink): Create pltlocal and relpltlocal. (ppc_elf_check_relocs): Allow PLT relocs on local symbols. Set PLT_KEEP. Adjust update_local_sym_info call. (ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls. (allocate_dynrelocs): Allocate pltlocal and relpltlocal. (ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal. (ppc_elf_relocate_section): Support PLT16 relocs for local syms. (write_global_sym_plt): Init pltlocal and write relpltlocal. (ppc_finish_symbols): Likewise for locals. ld/ * emulparams/elf32ppc.sh (OTHER_RELRO_SECTIONS_2): Add .branch_lt. (OTHER_GOT_RELOC_SECTIONS): Add .rela.branch_lt. * testsuite/ld-powerpc/elfv2so.d: Update for symbol/stub reordering. * testsuite/ld-powerpc/relbrlt.d: Likewise. * testsuite/ld-powerpc/relbrlt.s: Likewise. * testsuite/ld-powerpc/tlsso.r: Likewise. * testsuite/ld-powerpc/tlstocso.r: Likewise. gold/ * powerpc.cc (Target_powerpc::lplt_): New variable. (Target_powerpc::lplt_section): Associated accessor. (Target_powerpc::plt_off): Handle local non-ifunc symbols. (Target_powerpc::make_lplt_section): New function. (Target_powerpc::make_local_plt_entry): New function. (Powerpc_relobj::do_relocate_sections): Write out lplt. (Output_data_plt_powerpc::first_plt_entry_offset): Zero for lplt. (Output_data_plt_powerpc::add_local_entry): New function. (Output_data_plt_powerpc::do_write): Ignore lplt. (Target_powerpc::make_iplt_section): Make lplt first. (Target_powerpc::make_brlt_section): Make .branch_lt relro. (Target_powerpc::Scan::local): Handle PLT16 relocs.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog32
-rw-r--r--bfd/elf32-ppc.c386
-rw-r--r--bfd/elf64-ppc.c272
3 files changed, 496 insertions, 194 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index f6388c1..099d106 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,37 @@
2018-04-09 Alan Modra <amodra@gmail.com>
+ * elf64-ppc.c (LOCAL_PLT_ENTRY_SIZE): Define.
+ (struct ppc_stub_hash_entry): Add symtype field.
+ (PLT_KEEP): Define.
+ (struct ppc_link_hash_table): Add pltlocal and relpltlocal.
+ (create_linkage_sections): Create pltlocal and relpltlocal.
+ (ppc64_elf_check_relocs): Allow PLT relocs on local symbols.
+ Set PLT_KEEP.
+ (ppc64_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
+ (allocate_dynrelocs): Allocate pltlocal and relpltlocal.
+ (ppc64_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
+ Keep PLT entries for inline calls against locals.
+ (ppc_build_one_stub): Use pltlocal as appropriate.
+ (ppc_size_one_stub): Likewise.
+ (ppc64_elf_size_stubs): Set symtype.
+ (build_global_entry_stubs_and_plt): Init pltlocal and write
+ relpltlocal for globals.
+ (write_plt_relocs_for_local_syms): Likewise for local syms.
+ (ppc64_elf_relocate_section): Support PLT for local syms.
+ * elf32-ppc.c (PLT_KEEP): Define.
+ (struct ppc_elf_link_hash_table): Add pltlocal and relpltlocal.
+ (ppc_elf_create_glink): Create pltlocal and relpltlocal.
+ (ppc_elf_check_relocs): Allow PLT relocs on local symbols.
+ Set PLT_KEEP. Adjust update_local_sym_info call.
+ (ppc_elf_adjust_dynamic_symbol): Keep PLT entries for inline calls.
+ (allocate_dynrelocs): Allocate pltlocal and relpltlocal.
+ (ppc_elf_size_dynamic_sections): Size pltlocal and relpltlocal.
+ (ppc_elf_relocate_section): Support PLT16 relocs for local syms.
+ (write_global_sym_plt): Init pltlocal and write relpltlocal.
+ (ppc_finish_symbols): Likewise for locals.
+
+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.
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index d24b095..5da7230 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -3248,6 +3248,7 @@ struct ppc_elf_link_hash_entry
/* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */
+#define PLT_KEEP 4 /* inline plt call requires plt entry. */
#define NON_GOT 256 /* local symbol plt, not stored. */
/* Nonzero if we have seen a small data relocation referring to this
@@ -3277,6 +3278,8 @@ struct ppc_elf_link_hash_table
elf_linker_section_t sdata[2];
asection *sbss;
asection *glink_eh_frame;
+ asection *pltlocal;
+ asection *relpltlocal;
/* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
asection *srelplt2;
@@ -3526,6 +3529,26 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
|| ! bfd_set_section_alignment (abfd, s, 2))
return FALSE;
+ /* Local plt entries. */
+ flags = (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->pltlocal = bfd_make_section_anyway_with_flags (abfd, ".branch_lt",
+ flags);
+ if (htab->pltlocal == NULL
+ || ! bfd_set_section_alignment (abfd, htab->pltlocal, 2))
+ return FALSE;
+
+ if (bfd_link_pic (info))
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->relpltlocal
+ = bfd_make_section_anyway_with_flags (abfd, ".rela.branch_lt", flags);
+ if (htab->relpltlocal == NULL
+ || ! bfd_set_section_alignment (abfd, htab->relpltlocal, 2))
+ return FALSE;
+ }
+
if (!ppc_elf_create_linker_section (abfd, info, 0,
&htab->sdata[0]))
return FALSE;
@@ -4008,6 +4031,8 @@ ppc_elf_check_relocs (bfd *abfd,
struct elf_link_hash_entry *h;
int tls_type;
struct plt_entry **ifunc;
+ struct plt_entry **pltent;
+ bfd_vma addend;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
@@ -4061,7 +4086,7 @@ ppc_elf_check_relocs (bfd *abfd,
|| r_type == R_PPC_PLT16_HI
|| r_type == R_PPC_PLT16_HA)
{
- bfd_vma addend = 0;
+ addend = 0;
if (r_type == R_PPC_PLTREL24)
ppc_elf_tdata (abfd)->makes_plt_call = 1;
if (bfd_link_pic (info)
@@ -4296,33 +4321,27 @@ ppc_elf_check_relocs (bfd *abfd,
/* This symbol requires a procedure linkage table entry. */
if (h == NULL)
{
- if (ifunc == NULL)
- {
- /* It does not make sense to have a procedure linkage
- table entry for a non-ifunc local symbol. */
- info->callbacks->einfo
- /* xgettext:c-format */
- (_("%H: %s reloc against local symbol\n"),
- abfd, sec, rel->r_offset,
- ppc_elf_howto_table[r_type]->name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+ NON_GOT | PLT_KEEP);
+ if (pltent == NULL)
+ return FALSE;
}
else
{
- bfd_vma addend = 0;
-
- if (bfd_link_pic (info)
- && (r_type == R_PPC_PLTREL24
- || r_type == R_PPC_PLT16_LO
- || r_type == R_PPC_PLT16_HI
- || r_type == R_PPC_PLT16_HA))
- addend = rel->r_addend;
+ if (r_type != R_PPC_PLTREL24)
+ ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
h->needs_plt = 1;
- if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
- return FALSE;
+ pltent = &h->plt.plist;
}
+ addend = 0;
+ if (bfd_link_pic (info)
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_PLT16_LO
+ || r_type == R_PPC_PLT16_HI
+ || r_type == R_PPC_PLT16_HA))
+ addend = rel->r_addend;
+ if (!update_plt_info (abfd, pltent, got2, addend))
+ return FALSE;
break;
/* The following relocations don't need to propagate the
@@ -5617,7 +5636,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
if (ent->plt.refcount > 0)
break;
if (ent == NULL
- || (h->type != STT_GNU_IFUNC && local))
+ || (h->type != STT_GNU_IFUNC
+ && local
+ && ((ppc_elf_hash_entry (h)->tls_mask & (TLS_TLS | PLT_KEEP))
+ != PLT_KEEP)))
{
/* A PLT entry is not required/allowed when:
@@ -6103,13 +6125,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
sreloc->size += p->count * sizeof (Elf32_External_Rela);
}
- /* Handle PLT relocs. Done last, after dynindx has settled. */
+ /* Handle PLT relocs. Done last, after dynindx has settled.
+ We might need a PLT entry when the symbol
+ a) is dynamic, or
+ b) is an ifunc, or
+ c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+ d) has plt16 relocs and we are linking statically. */
dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
- if (dyn || h->type == STT_GNU_IFUNC)
+ if (dyn
+ || h->type == STT_GNU_IFUNC
+ || (h->needs_plt && h->dynamic_adjusted)
+ || (h->needs_plt
+ && h->def_regular
+ && !htab->elf.dynamic_sections_created
+ && (ppc_elf_hash_entry (h)->tls_mask
+ & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
- bfd_vma plt_offset = 0, glink_offset = 0;
+ bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
@@ -6117,7 +6151,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
asection *s = htab->elf.splt;
if (!dyn)
- s = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ s = htab->elf.iplt;
+ else
+ s = htab->pltlocal;
+ }
if (htab->plt_type == PLT_NEW || !dyn)
{
@@ -6128,25 +6167,30 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
ent->plt.offset = plt_offset;
- s = htab->glink;
- if (!doneone || bfd_link_pic (info))
- {
- glink_offset = s->size;
- s->size += GLINK_ENTRY_SIZE (htab, h);
- }
- if (!doneone
- && !bfd_link_pic (info)
- && h->def_dynamic
- && !h->def_regular)
+ if (s == htab->pltlocal)
+ ent->glink_offset = glink_offset;
+ else
{
- h->root.u.def.section = s;
- h->root.u.def.value = glink_offset;
- }
- ent->glink_offset = glink_offset;
+ s = htab->glink;
+ if (!doneone || bfd_link_pic (info))
+ {
+ glink_offset = s->size;
+ s->size += GLINK_ENTRY_SIZE (htab, h);
+ }
+ if (!doneone
+ && !bfd_link_pic (info)
+ && h->def_dynamic
+ && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = glink_offset;
+ }
+ ent->glink_offset = glink_offset;
- if (htab->params->emit_stub_syms
- && !add_stub_sym (ent, h, info))
- return FALSE;
+ if (htab->params->emit_stub_syms
+ && !add_stub_sym (ent, h, info))
+ return FALSE;
+ }
}
else
{
@@ -6199,7 +6243,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (!doneone)
{
if (!dyn)
- htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+ {
+ if (h->type == STT_GNU_IFUNC)
+ {
+ s = htab->elf.irelplt;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ else if (bfd_link_pic (info))
+ {
+ s = htab->relpltlocal;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ }
else
{
htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
@@ -6425,16 +6480,25 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
continue;
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
- for (; local_plt < end_local_plt; ++local_plt)
+ lgot_masks = (char *) end_local_plt;
+ for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
{
struct plt_entry *ent;
bfd_boolean doneone = FALSE;
- bfd_vma plt_offset = 0, glink_offset = 0;
+ bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
- s = htab->elf.iplt;
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+ s = htab->elf.iplt;
+ else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+ {
+ ent->plt.offset = (bfd_vma) -1;
+ continue;
+ }
+ else
+ s = htab->pltlocal;
if (!doneone)
{
@@ -6443,9 +6507,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
}
ent->plt.offset = plt_offset;
- s = htab->glink;
- if (!doneone || bfd_link_pic (info))
+ if (s != htab->pltlocal && (!doneone || bfd_link_pic (info)))
{
+ s = htab->glink;
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE (htab, NULL);
}
@@ -6453,7 +6517,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
if (!doneone)
{
- htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+ {
+ s = htab->elf.irelplt;
+ s->size += sizeof (Elf32_External_Rela);
+ }
+ else if (bfd_link_pic (info))
+ {
+ s = htab->relpltlocal;
+ s->size += sizeof (Elf32_External_Rela);
+ }
doneone = TRUE;
}
}
@@ -6599,6 +6672,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
comment below. */
}
else if (s == htab->elf.iplt
+ || s == htab->pltlocal
|| s == htab->glink
|| s == htab->glink_eh_frame
|| s == htab->elf.sgotplt
@@ -9173,9 +9247,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_PLT16_LO:
case R_PPC_PLT16_HI:
case R_PPC_PLT16_HA:
- plt_list = ifunc;
+ plt_list = NULL;
if (h != NULL)
plt_list = &h->plt.plist;
+ else if (ifunc != NULL)
+ plt_list = ifunc;
+ else if (local_got_offsets != NULL)
+ {
+ struct plt_entry **local_plt;
+ local_plt = (struct plt_entry **) (local_got_offsets
+ + symtab_hdr->sh_info);
+ plt_list = local_plt + r_symndx;
+ }
unresolved_reloc = TRUE;
if (plt_list != NULL)
{
@@ -9183,11 +9266,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
ent = find_plt_ent (plt_list, got2,
bfd_link_pic (info) ? addend : 0);
- if (ent != NULL)
+ if (ent != NULL && ent->plt.offset != (bfd_vma) -1)
{
+ asection *plt;
+
unresolved_reloc = FALSE;
- relocation = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
+ plt = htab->elf.splt;
+ if (!htab->elf.dynamic_sections_created
+ || h == NULL
+ || h->dynindx == -1)
+ {
+ if (ifunc != NULL)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
+ relocation = (plt->output_section->vma
+ + plt->output_offset
+ ent->plt.offset);
if (bfd_link_pic (info))
{
@@ -10085,6 +10180,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
Elf_Internal_Rela rela;
bfd_byte *loc;
bfd_vma reloc_index;
+ asection *plt = htab->elf.splt;
+ asection *relplt = htab->elf.srelplt;
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
@@ -10120,10 +10217,10 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
{
bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_offset),
- htab->elf.splt->contents + ent->plt.offset + 0);
+ plt->contents + ent->plt.offset + 0);
bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_offset),
- htab->elf.splt->contents + ent->plt.offset + 4);
+ plt->contents + ent->plt.offset + 4);
}
else
{
@@ -10131,16 +10228,16 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_loc),
- htab->elf.splt->contents + ent->plt.offset + 0);
+ plt->contents + ent->plt.offset + 0);
bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_loc),
- htab->elf.splt->contents + ent->plt.offset + 4);
+ plt->contents + ent->plt.offset + 4);
}
bfd_put_32 (info->output_bfd, plt_entry[2],
- htab->elf.splt->contents + ent->plt.offset + 8);
+ plt->contents + ent->plt.offset + 8);
bfd_put_32 (info->output_bfd, plt_entry[3],
- htab->elf.splt->contents + ent->plt.offset + 12);
+ plt->contents + ent->plt.offset + 12);
/* This instruction is an immediate load. The value loaded is
the byte offset of the R_PPC_JMP_SLOT relocation from the
@@ -10150,7 +10247,7 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
prescaled offset. */
bfd_put_32 (info->output_bfd,
plt_entry[4] | reloc_index,
- htab->elf.splt->contents + ent->plt.offset + 16);
+ plt->contents + ent->plt.offset + 16);
/* This instruction is a PC-relative branch whose target is
the start of the PLT section. The address of this branch
instruction is 20 bytes beyond the start of this PLT entry.
@@ -10160,19 +10257,18 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
bfd_put_32 (info->output_bfd,
(plt_entry[5]
| (-(ent->plt.offset + 20) & 0x03fffffc)),
- htab->elf.splt->contents + ent->plt.offset + 20);
+ plt->contents + ent->plt.offset + 20);
bfd_put_32 (info->output_bfd, plt_entry[6],
- htab->elf.splt->contents + ent->plt.offset + 24);
+ plt->contents + ent->plt.offset + 24);
bfd_put_32 (info->output_bfd, plt_entry[7],
- htab->elf.splt->contents + ent->plt.offset + 28);
+ plt->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 (info->output_bfd,
- (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + ent->plt.offset + 16),
+ bfd_put_32 (info->output_bfd, (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset + 16),
htab->elf.sgotplt->contents + got_offset);
if (!bfd_link_pic (info))
@@ -10184,8 +10280,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
* sizeof (Elf32_External_Rela));
/* Provide the @ha relocation for the first instruction. */
- rela.r_offset = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ ent->plt.offset + 2);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_HA);
@@ -10194,8 +10290,8 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */
- rela.r_offset = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ ent->plt.offset + 6);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO);
@@ -10222,66 +10318,83 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset
+ got_offset);
-
+ rela.r_addend = 0;
}
else
{
- asection *splt = htab->elf.splt;
+ rela.r_addend = 0;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ {
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ }
+ else
+ {
+ plt = htab->pltlocal;
+ relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+ }
+ if (h->def_regular
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
+ rela.r_addend = SYM_VAL (h);
+ }
- rela.r_offset = (splt->output_section->vma
- + splt->output_offset
- + ent->plt.offset);
- if (htab->plt_type == PLT_OLD
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (relplt == NULL)
{
- /* We don't need to fill in the .plt. The ppc dynamic
- linker will fill it in. */
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_32 (info->output_bfd, rela.r_addend, loc);
}
else
{
- bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
- + htab->glink->output_section->vma
- + htab->glink->output_offset);
- bfd_put_32 (info->output_bfd, val,
- splt->contents + ent->plt.offset);
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
+
+ if (htab->plt_type == PLT_OLD
+ || !htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ /* We don't need to fill in the .plt. The ppc dynamic
+ linker will fill it in. */
+ }
+ else
+ {
+ bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+ + htab->glink->output_section->vma
+ + htab->glink->output_offset);
+ bfd_put_32 (info->output_bfd, val,
+ plt->contents + ent->plt.offset);
+ }
}
}
- /* Fill in the entry in the .rela.plt section. */
- rela.r_addend = 0;
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (relplt != NULL)
{
- 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_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
- rela.r_addend = SYM_VAL (h);
- }
- else
- rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
-
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- {
- loc = (htab->elf.irelplt->contents
- + (htab->elf.irelplt->reloc_count++
- * sizeof (Elf32_External_Rela)));
- htab->local_ifunc_resolver = 1;
- }
- else
- {
- loc = (htab->elf.srelplt->contents
- + reloc_index * sizeof (Elf32_External_Rela));
- if (h->type == STT_GNU_IFUNC && is_static_defined (h))
- htab->maybe_local_ifunc_resolver = 1;
+ /* Fill in the entry in the .rela.plt section. */
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ if (h->type == STT_GNU_IFUNC)
+ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+ else
+ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf32_External_Rela));
+ htab->local_ifunc_resolver = 1;
+ }
+ else
+ {
+ rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+ loc = relplt->contents + (reloc_index
+ * sizeof (Elf32_External_Rela));
+ if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+ htab->maybe_local_ifunc_resolver = 1;
+ }
+ bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
}
- bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
doneone = TRUE;
}
@@ -10294,7 +10407,12 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- plt = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ break;
+ }
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
write_glink_stub (h, ent, plt, p, info);
@@ -10368,16 +10486,32 @@ ppc_finish_symbols (struct bfd_link_info *info)
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;
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ {
+ htab->local_ifunc_resolver = 1;
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+ }
+ else
+ {
+ plt = htab->pltlocal;
+ if (bfd_link_pic (info))
+ {
+ relplt = htab->relpltlocal;
+ rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+ }
+ else
+ {
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_32 (info->output_bfd, val, loc);
+ continue;
+ }
+ }
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));
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 8291db8..4ea6a9e 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -129,6 +129,7 @@ static bfd_vma opd_entry_value
/* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8)
+#define LOCAL_PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 16 : 8)
/* The initial size of the plt reserved for the dynamic linker. */
#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
@@ -3977,6 +3978,9 @@ struct ppc_stub_hash_entry {
struct ppc_link_hash_entry *h;
struct plt_entry *plt_ent;
+ /* Symbol type. */
+ unsigned char symtype;
+
/* Symbol st_other. */
unsigned char other;
};
@@ -4068,6 +4072,7 @@ struct ppc_link_hash_entry
/* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */
+#define PLT_KEEP 4 /* inline plt call requires plt entry. */
#define NON_GOT 256 /* local symbol plt, not stored. */
};
@@ -4124,6 +4129,8 @@ struct ppc_link_hash_table
asection *glink;
asection *global_entry;
asection *sfpr;
+ asection *pltlocal;
+ asection *relpltlocal;
asection *brlt;
asection *relbrlt;
asection *glink_eh_frame;
@@ -4505,18 +4512,31 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
|| ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE;
+ /* Local plt entries, put in .branch_lt but a separate section for
+ convenience. */
+ htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
+ flags);
+ if (htab->pltlocal == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+ return FALSE;
+
if (!bfd_link_pic (info))
return TRUE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
- ".rela.branch_lt",
- flags);
+ htab->relbrlt
+ = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
if (htab->relbrlt == NULL
|| ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
return FALSE;
+ htab->relpltlocal
+ = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
+ if (htab->relpltlocal == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+ return FALSE;
+
return TRUE;
}
@@ -5634,20 +5654,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0')
((struct ppc_link_hash_entry *) h)->is_func = 1;
+ ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP;
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
- /* xgettext:c-format */
- (_("%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;
- }
+ plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+ rel->r_addend,
+ NON_GOT | PLT_KEEP);
if (!update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE;
break;
@@ -7201,7 +7214,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
if (ent->plt.refcount > 0)
break;
if (ent == NULL
- || (h->type != STT_GNU_IFUNC && local))
+ || (h->type != STT_GNU_IFUNC
+ && local
+ && (((struct ppc_link_hash_entry *) h)->tls_mask
+ & (TLS_TLS | PLT_KEEP)) != PLT_KEEP))
{
h->plt.plist = NULL;
h->needs_plt = 0;
@@ -9822,9 +9838,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
}
- if ((htab->elf.dynamic_sections_created
- && h->dynindx != -1)
- || h->type == STT_GNU_IFUNC)
+ /* We might need a PLT entry when the symbol
+ a) is dynamic, or
+ b) is an ifunc, or
+ c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+ d) has plt16 relocs and we are linking statically. */
+ if ((htab->elf.dynamic_sections_created && h->dynindx != -1)
+ || h->type == STT_GNU_IFUNC
+ || (h->needs_plt && h->dynamic_adjusted)
+ || (h->needs_plt
+ && h->def_regular
+ && !htab->elf.dynamic_sections_created
+ && (((struct ppc_link_hash_entry *) h)->tls_mask
+ & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
{
struct plt_entry *pent;
bfd_boolean doneone = FALSE;
@@ -9834,10 +9860,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
- s = htab->elf.iplt;
- pent->plt.offset = s->size;
- s->size += PLT_ENTRY_SIZE (htab);
- s = htab->elf.irelplt;
+ if (h->type == STT_GNU_IFUNC)
+ {
+ s = htab->elf.iplt;
+ pent->plt.offset = s->size;
+ s->size += PLT_ENTRY_SIZE (htab);
+ s = htab->elf.irelplt;
+ }
+ else
+ {
+ s = htab->pltlocal;
+ pent->plt.offset = s->size;
+ s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+ s = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+ }
}
else
{
@@ -9869,7 +9905,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* We also need to make an entry in the .rela.plt section. */
s = htab->elf.srelplt;
}
- s->size += sizeof (Elf64_External_Rela);
+ if (s != NULL)
+ s->size += sizeof (Elf64_External_Rela);
doneone = TRUE;
}
else
@@ -10124,19 +10161,32 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
*pent = ent->next;
}
- /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */
- for (; local_plt < end_local_plt; ++local_plt)
+ /* Allocate space for plt calls to local syms. */
+ lgot_masks = (unsigned char *) end_local_plt;
+ for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
{
struct plt_entry *ent;
for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
- s = htab->elf.iplt;
- ent->plt.offset = s->size;
- s->size += PLT_ENTRY_SIZE (htab);
-
- htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+ if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+ {
+ s = htab->elf.iplt;
+ ent->plt.offset = s->size;
+ s->size += PLT_ENTRY_SIZE (htab);
+ htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+ }
+ else if ((*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+ ent->plt.offset = (bfd_vma) -1;
+ else
+ {
+ s = htab->pltlocal;
+ ent->plt.offset = s->size;
+ s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+ if (bfd_link_pic (info))
+ htab->relpltlocal->size += sizeof (Elf64_External_Rela);
+ }
}
else
ent->plt.offset = (bfd_vma) -1;
@@ -10199,6 +10249,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
else if (s == htab->elf.sgot
|| s == htab->elf.splt
|| s == htab->elf.iplt
+ || s == htab->pltlocal
|| s == htab->glink
|| s == htab->global_entry
|| s == htab->elf.sdynbss
@@ -11154,7 +11205,12 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (!htab->elf.dynamic_sections_created
|| stub_entry->h == NULL
|| stub_entry->h->elf.dynindx == -1)
- plt = htab->elf.iplt;
+ {
+ if (stub_entry->symtype == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
dest += plt->output_offset + plt->output_section->vma;
@@ -11303,7 +11359,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (!htab->elf.dynamic_sections_created
|| stub_entry->h == NULL
|| stub_entry->h->elf.dynindx == -1)
- plt = htab->elf.iplt;
+ {
+ if (stub_entry->symtype == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
off += (plt->output_offset
+ plt->output_section->vma
- elf_gp (info->output_bfd)
@@ -12655,6 +12716,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
}
stub_entry->h = hash;
stub_entry->plt_ent = plt_ent;
+ stub_entry->symtype
+ = hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info);
stub_entry->other = hash ? hash->elf.other : sym->st_other;
if (stub_entry->h != NULL)
@@ -13017,6 +13080,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
/* This symbol has an entry in the procedure linkage
table. Set it up. */
Elf_Internal_Rela rela;
+ asection *plt, *relplt;
bfd_byte *loc;
if (!htab->elf.dynamic_sections_created
@@ -13026,21 +13090,55 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
&& (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);
+ if (h->type == STT_GNU_IFUNC)
+ {
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ htab->local_ifunc_resolver = 1;
+ 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);
+ }
else
- rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+ {
+ plt = htab->pltlocal;
+ if (bfd_link_pic (info))
+ {
+ relplt = htab->relpltlocal;
+ if (htab->opd_abi)
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+ else
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+ }
+ else
+ relplt = NULL;
+ }
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;
+
+ if (relplt == NULL)
+ {
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_64 (info->output_bfd, rela.r_addend, loc);
+ if (htab->opd_abi)
+ {
+ bfd_vma toc = elf_gp (info->output_bfd);
+ toc += htab->sec_info[h->root.u.def.section->id].toc_off;
+ bfd_put_64 (info->output_bfd, toc, loc + 8);
+ }
+ }
+ else
+ {
+ rela.r_offset = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
+ loc = relplt->contents + (relplt->reloc_count++
+ * sizeof (Elf64_External_Rela));
+ bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+ }
}
else
{
@@ -13054,8 +13152,8 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
/ 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);
}
- bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
}
if (!h->pointer_equality_needed)
@@ -13080,7 +13178,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
plt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- plt = htab->elf.iplt;
+ {
+ if (h->type == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
@@ -13173,7 +13276,6 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
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))
@@ -13189,23 +13291,53 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
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;
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ {
+ htab->local_ifunc_resolver = 1;
+ plt = htab->elf.iplt;
+ relplt = htab->elf.irelplt;
+ }
+ else
+ {
+ plt = htab->pltlocal;
+ relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+ }
- 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);
+ if (relplt == NULL)
+ {
+ loc = plt->contents + ent->plt.offset;
+ bfd_put_64 (info->output_bfd, val, loc);
+ if (htab->opd_abi)
+ {
+ bfd_vma toc = elf_gp (ibfd);
+ bfd_put_64 (info->output_bfd, toc, loc + 8);
+ }
+ }
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);
+ {
+ Elf_Internal_Rela rela;
+ rela.r_offset = (ent->plt.offset
+ + plt->output_offset
+ + plt->output_section->vma);
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ {
+ 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);
+ }
+ else
+ {
+ if (htab->opd_abi)
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+ else
+ rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+ }
+ 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
@@ -14792,10 +14924,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{
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;
+ plt_list = local_plt + r_symndx;
}
if (plt_list)
{
@@ -14812,7 +14941,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (!htab->elf.dynamic_sections_created
|| h == NULL
|| h->elf.dynindx == -1)
- plt = htab->elf.iplt;
+ {
+ if (h != NULL
+ ? h->elf.type == STT_GNU_IFUNC
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+ plt = htab->elf.iplt;
+ else
+ plt = htab->pltlocal;
+ }
+ relocation = (plt->output_section->vma
+ + plt->output_offset
+ + ent->plt.offset);
if (r_type == R_PPC64_PLT16_HA
|| r_type ==R_PPC64_PLT16_HI
|| r_type ==R_PPC64_PLT16_LO
@@ -14822,9 +14961,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
+ htab->sec_info[input_section->id].toc_off);
relocation -= got;
}
- relocation = (plt->output_section->vma
- + plt->output_offset
- + ent->plt.offset);
addend = 0;
unresolved_reloc = FALSE;
break;