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.
This commit is contained in:
Alan Modra 2018-04-09 09:22:53 +09:30
parent 49c09209d0
commit 2d7ad24e87
12 changed files with 701 additions and 231 deletions

View File

@ -1,3 +1,35 @@
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> 2018-04-09 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs * elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs

View File

@ -3248,6 +3248,7 @@ struct ppc_elf_link_hash_entry
/* The above field is also used to mark function symbols. In which /* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */ case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */ #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. */ #define NON_GOT 256 /* local symbol plt, not stored. */
/* Nonzero if we have seen a small data relocation referring to this /* 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]; elf_linker_section_t sdata[2];
asection *sbss; asection *sbss;
asection *glink_eh_frame; asection *glink_eh_frame;
asection *pltlocal;
asection *relpltlocal;
/* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
asection *srelplt2; asection *srelplt2;
@ -3526,6 +3529,26 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
|| ! bfd_set_section_alignment (abfd, s, 2)) || ! bfd_set_section_alignment (abfd, s, 2))
return FALSE; 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, if (!ppc_elf_create_linker_section (abfd, info, 0,
&htab->sdata[0])) &htab->sdata[0]))
return FALSE; return FALSE;
@ -4008,6 +4031,8 @@ ppc_elf_check_relocs (bfd *abfd,
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
int tls_type; int tls_type;
struct plt_entry **ifunc; struct plt_entry **ifunc;
struct plt_entry **pltent;
bfd_vma addend;
r_symndx = ELF32_R_SYM (rel->r_info); r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_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_HI
|| r_type == R_PPC_PLT16_HA) || r_type == R_PPC_PLT16_HA)
{ {
bfd_vma addend = 0; addend = 0;
if (r_type == R_PPC_PLTREL24) if (r_type == R_PPC_PLTREL24)
ppc_elf_tdata (abfd)->makes_plt_call = 1; ppc_elf_tdata (abfd)->makes_plt_call = 1;
if (bfd_link_pic (info) if (bfd_link_pic (info)
@ -4296,33 +4321,27 @@ ppc_elf_check_relocs (bfd *abfd,
/* This symbol requires a procedure linkage table entry. */ /* This symbol requires a procedure linkage table entry. */
if (h == NULL) if (h == NULL)
{ {
if (ifunc == NULL) pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx,
{ NON_GOT | PLT_KEEP);
/* It does not make sense to have a procedure linkage if (pltent == NULL)
table entry for a non-ifunc local symbol. */ return FALSE;
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;
}
} }
else else
{ {
bfd_vma addend = 0; if (r_type != R_PPC_PLTREL24)
ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
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;
h->needs_plt = 1; h->needs_plt = 1;
if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) pltent = &h->plt.plist;
return FALSE;
} }
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; break;
/* The following relocations don't need to propagate the /* 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) if (ent->plt.refcount > 0)
break; break;
if (ent == NULL 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: /* 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); 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; 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; struct plt_entry *ent;
bfd_boolean doneone = FALSE; 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) for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0) if (ent->plt.refcount > 0)
@ -6117,7 +6151,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
asection *s = htab->elf.splt; asection *s = htab->elf.splt;
if (!dyn) 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) 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; ent->plt.offset = plt_offset;
s = htab->glink; if (s == htab->pltlocal)
if (!doneone || bfd_link_pic (info)) ent->glink_offset = glink_offset;
else
{ {
glink_offset = s->size; s = htab->glink;
s->size += GLINK_ENTRY_SIZE (htab, h); if (!doneone || bfd_link_pic (info))
} {
if (!doneone glink_offset = s->size;
&& !bfd_link_pic (info) s->size += GLINK_ENTRY_SIZE (htab, h);
&& h->def_dynamic }
&& !h->def_regular) if (!doneone
{ && !bfd_link_pic (info)
h->root.u.def.section = s; && h->def_dynamic
h->root.u.def.value = glink_offset; && !h->def_regular)
} {
ent->glink_offset = glink_offset; h->root.u.def.section = s;
h->root.u.def.value = glink_offset;
}
ent->glink_offset = glink_offset;
if (htab->params->emit_stub_syms if (htab->params->emit_stub_syms
&& !add_stub_sym (ent, h, info)) && !add_stub_sym (ent, h, info))
return FALSE; return FALSE;
}
} }
else else
{ {
@ -6199,7 +6243,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (!doneone) if (!doneone)
{ {
if (!dyn) 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 else
{ {
htab->elf.srelplt->size += sizeof (Elf32_External_Rela); htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
@ -6425,16 +6480,25 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
continue; continue;
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ /* 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; struct plt_entry *ent;
bfd_boolean doneone = FALSE; 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) for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0) 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) if (!doneone)
{ {
@ -6443,9 +6507,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
} }
ent->plt.offset = plt_offset; ent->plt.offset = plt_offset;
s = htab->glink; if (s != htab->pltlocal && (!doneone || bfd_link_pic (info)))
if (!doneone || bfd_link_pic (info))
{ {
s = htab->glink;
glink_offset = s->size; glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE (htab, NULL); s->size += GLINK_ENTRY_SIZE (htab, NULL);
} }
@ -6453,7 +6517,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
if (!doneone) 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; doneone = TRUE;
} }
} }
@ -6599,6 +6672,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
comment below. */ comment below. */
} }
else if (s == htab->elf.iplt else if (s == htab->elf.iplt
|| s == htab->pltlocal
|| s == htab->glink || s == htab->glink
|| s == htab->glink_eh_frame || s == htab->glink_eh_frame
|| s == htab->elf.sgotplt || s == htab->elf.sgotplt
@ -9173,9 +9247,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_PLT16_LO: case R_PPC_PLT16_LO:
case R_PPC_PLT16_HI: case R_PPC_PLT16_HI:
case R_PPC_PLT16_HA: case R_PPC_PLT16_HA:
plt_list = ifunc; plt_list = NULL;
if (h != NULL) if (h != NULL)
plt_list = &h->plt.plist; 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; unresolved_reloc = TRUE;
if (plt_list != NULL) if (plt_list != NULL)
{ {
@ -9183,11 +9266,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
ent = find_plt_ent (plt_list, got2, ent = find_plt_ent (plt_list, got2,
bfd_link_pic (info) ? addend : 0); bfd_link_pic (info) ? addend : 0);
if (ent != NULL) if (ent != NULL && ent->plt.offset != (bfd_vma) -1)
{ {
asection *plt;
unresolved_reloc = FALSE; unresolved_reloc = FALSE;
relocation = (htab->elf.splt->output_section->vma plt = htab->elf.splt;
+ htab->elf.splt->output_offset 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); + ent->plt.offset);
if (bfd_link_pic (info)) 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; Elf_Internal_Rela rela;
bfd_byte *loc; bfd_byte *loc;
bfd_vma reloc_index; bfd_vma reloc_index;
asection *plt = htab->elf.splt;
asection *relplt = htab->elf.srelplt;
if (htab->plt_type == PLT_NEW if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created || !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, bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_offset), 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, bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_offset), plt_entry[1] | PPC_LO (got_offset),
htab->elf.splt->contents + ent->plt.offset + 4); plt->contents + ent->plt.offset + 4);
} }
else else
{ {
@ -10131,16 +10228,16 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
bfd_put_32 (info->output_bfd, bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_loc), 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, bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_loc), 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], 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], 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 /* This instruction is an immediate load. The value loaded is
the byte offset of the R_PPC_JMP_SLOT relocation from the 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. */ prescaled offset. */
bfd_put_32 (info->output_bfd, bfd_put_32 (info->output_bfd,
plt_entry[4] | reloc_index, 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 /* This instruction is a PC-relative branch whose target is
the start of the PLT section. The address of this branch the start of the PLT section. The address of this branch
instruction is 20 bytes beyond the start of this PLT entry. 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, bfd_put_32 (info->output_bfd,
(plt_entry[5] (plt_entry[5]
| (-(ent->plt.offset + 20) & 0x03fffffc)), | (-(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], 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], 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 /* Fill in the GOT entry corresponding to this PLT slot with
the address immediately after the "bctr" instruction the address immediately after the "bctr" instruction
in this PLT entry. */ in this PLT entry. */
bfd_put_32 (info->output_bfd, bfd_put_32 (info->output_bfd, (plt->output_section->vma
(htab->elf.splt->output_section->vma + plt->output_offset
+ htab->elf.splt->output_offset + ent->plt.offset + 16),
+ ent->plt.offset + 16),
htab->elf.sgotplt->contents + got_offset); htab->elf.sgotplt->contents + got_offset);
if (!bfd_link_pic (info)) 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)); * sizeof (Elf32_External_Rela));
/* Provide the @ha relocation for the first instruction. */ /* Provide the @ha relocation for the first instruction. */
rela.r_offset = (htab->elf.splt->output_section->vma rela.r_offset = (plt->output_section->vma
+ htab->elf.splt->output_offset + plt->output_offset
+ ent->plt.offset + 2); + ent->plt.offset + 2);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_HA); 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); loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */ /* Provide the @l relocation for the second instruction. */
rela.r_offset = (htab->elf.splt->output_section->vma rela.r_offset = (plt->output_section->vma
+ htab->elf.splt->output_offset + plt->output_offset
+ ent->plt.offset + 6); + ent->plt.offset + 6);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO); 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 rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ htab->elf.sgotplt->output_offset + htab->elf.sgotplt->output_offset
+ got_offset); + got_offset);
rela.r_addend = 0;
} }
else else
{ {
asection *splt = htab->elf.splt; rela.r_addend = 0;
if (!htab->elf.dynamic_sections_created if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1) || h->dynindx == -1)
splt = htab->elf.iplt;
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)
{ {
/* We don't need to fill in the .plt. The ppc dynamic if (h->type == STT_GNU_IFUNC)
linker will fill it in. */ {
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);
}
if (relplt == NULL)
{
loc = plt->contents + ent->plt.offset;
bfd_put_32 (info->output_bfd, rela.r_addend, loc);
} }
else else
{ {
bfd_vma val = (htab->glink_pltresolve + ent->plt.offset rela.r_offset = (plt->output_section->vma
+ htab->glink->output_section->vma + plt->output_offset
+ htab->glink->output_offset); + ent->plt.offset);
bfd_put_32 (info->output_bfd, val,
splt->contents + 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. */ if (relplt != NULL)
rela.r_addend = 0;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{ {
BFD_ASSERT (h->type == STT_GNU_IFUNC /* Fill in the entry in the .rela.plt section. */
&& h->def_regular if (!htab->elf.dynamic_sections_created
&& (h->root.type == bfd_link_hash_defined || h->dynindx == -1)
|| h->root.type == bfd_link_hash_defweak)); {
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE); if (h->type == STT_GNU_IFUNC)
rela.r_addend = SYM_VAL (h); 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);
} }
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;
}
bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
doneone = TRUE; doneone = TRUE;
} }
@ -10294,7 +10407,12 @@ write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
if (!htab->elf.dynamic_sections_created if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1) || 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; p = (unsigned char *) htab->glink->contents + ent->glink_offset;
write_glink_stub (h, ent, plt, p, info); 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) if (sym_sec != NULL && sym_sec->output_section != NULL)
val += sym_sec->output_offset + sym_sec->output_section->vma; val += sym_sec->output_offset + sym_sec->output_section->vma;
BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
htab->local_ifunc_resolver = 1; htab->local_ifunc_resolver = 1;
plt = htab->elf.iplt; plt = htab->elf.iplt;
relplt = htab->elf.irelplt; 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 rela.r_offset = (ent->plt.offset
+ plt->output_offset + plt->output_offset
+ plt->output_section->vma); + plt->output_section->vma);
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
rela.r_addend = val; rela.r_addend = val;
loc = relplt->contents + (relplt->reloc_count++ loc = relplt->contents + (relplt->reloc_count++
* sizeof (Elf32_External_Rela)); * sizeof (Elf32_External_Rela));

View File

@ -129,6 +129,7 @@ static bfd_vma opd_entry_value
/* The size in bytes of an entry in the procedure linkage table. */ /* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8) #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. */ /* The initial size of the plt reserved for the dynamic linker. */
#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) #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 ppc_link_hash_entry *h;
struct plt_entry *plt_ent; struct plt_entry *plt_ent;
/* Symbol type. */
unsigned char symtype;
/* Symbol st_other. */ /* Symbol st_other. */
unsigned char 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 /* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */ case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */ #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. */ #define NON_GOT 256 /* local symbol plt, not stored. */
}; };
@ -4124,6 +4129,8 @@ struct ppc_link_hash_table
asection *glink; asection *glink;
asection *global_entry; asection *global_entry;
asection *sfpr; asection *sfpr;
asection *pltlocal;
asection *relpltlocal;
asection *brlt; asection *brlt;
asection *relbrlt; asection *relbrlt;
asection *glink_eh_frame; 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)) || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE; 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)) if (!bfd_link_pic (info))
return TRUE; return TRUE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, htab->relbrlt
".rela.branch_lt", = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
flags);
if (htab->relbrlt == NULL if (htab->relbrlt == NULL
|| ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
return FALSE; 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; return TRUE;
} }
@ -5634,20 +5654,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h->root.root.string[0] == '.' if (h->root.root.string[0] == '.'
&& h->root.root.string[1] != '\0') && h->root.root.string[1] != '\0')
((struct ppc_link_hash_entry *) h)->is_func = 1; ((struct ppc_link_hash_entry *) h)->is_func = 1;
((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP;
plt_list = &h->plt.plist; plt_list = &h->plt.plist;
} }
if (plt_list == NULL) if (plt_list == NULL)
{ plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
/* It does not make sense to have a procedure linkage rel->r_addend,
table entry for a non-ifunc local symbol. */ NON_GOT | PLT_KEEP);
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;
}
if (!update_plt_info (abfd, plt_list, rel->r_addend)) if (!update_plt_info (abfd, plt_list, rel->r_addend))
return FALSE; return FALSE;
break; break;
@ -7201,7 +7214,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
if (ent->plt.refcount > 0) if (ent->plt.refcount > 0)
break; break;
if (ent == NULL 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->plt.plist = NULL;
h->needs_plt = 0; h->needs_plt = 0;
@ -9822,9 +9838,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
} }
} }
if ((htab->elf.dynamic_sections_created /* We might need a PLT entry when the symbol
&& h->dynindx != -1) a) is dynamic, or
|| h->type == STT_GNU_IFUNC) 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; struct plt_entry *pent;
bfd_boolean doneone = FALSE; bfd_boolean doneone = FALSE;
@ -9834,10 +9860,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (!htab->elf.dynamic_sections_created if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1) || h->dynindx == -1)
{ {
s = htab->elf.iplt; if (h->type == STT_GNU_IFUNC)
pent->plt.offset = s->size; {
s->size += PLT_ENTRY_SIZE (htab); s = htab->elf.iplt;
s = htab->elf.irelplt; 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 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. */ /* We also need to make an entry in the .rela.plt section. */
s = htab->elf.srelplt; s = htab->elf.srelplt;
} }
s->size += sizeof (Elf64_External_Rela); if (s != NULL)
s->size += sizeof (Elf64_External_Rela);
doneone = TRUE; doneone = TRUE;
} }
else else
@ -10124,19 +10161,32 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
*pent = ent->next; *pent = ent->next;
} }
/* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt. */ /* Allocate space for plt calls to local syms. */
for (; local_plt < end_local_plt; ++local_plt) lgot_masks = (unsigned char *) end_local_plt;
for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
{ {
struct plt_entry *ent; struct plt_entry *ent;
for (ent = *local_plt; ent != NULL; ent = ent->next) for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0) if (ent->plt.refcount > 0)
{ {
s = htab->elf.iplt; if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
ent->plt.offset = s->size; {
s->size += PLT_ENTRY_SIZE (htab); s = htab->elf.iplt;
ent->plt.offset = s->size;
htab->elf.irelplt->size += sizeof (Elf64_External_Rela); 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 else
ent->plt.offset = (bfd_vma) -1; ent->plt.offset = (bfd_vma) -1;
@ -10199,6 +10249,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
else if (s == htab->elf.sgot else if (s == htab->elf.sgot
|| s == htab->elf.splt || s == htab->elf.splt
|| s == htab->elf.iplt || s == htab->elf.iplt
|| s == htab->pltlocal
|| s == htab->glink || s == htab->glink
|| s == htab->global_entry || s == htab->global_entry
|| s == htab->elf.sdynbss || 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 if (!htab->elf.dynamic_sections_created
|| stub_entry->h == NULL || stub_entry->h == NULL
|| stub_entry->h->elf.dynindx == -1) || 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; 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 if (!htab->elf.dynamic_sections_created
|| stub_entry->h == NULL || stub_entry->h == NULL
|| stub_entry->h->elf.dynindx == -1) || 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 off += (plt->output_offset
+ plt->output_section->vma + plt->output_section->vma
- elf_gp (info->output_bfd) - elf_gp (info->output_bfd)
@ -12655,6 +12716,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
} }
stub_entry->h = hash; stub_entry->h = hash;
stub_entry->plt_ent = plt_ent; 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; stub_entry->other = hash ? hash->elf.other : sym->st_other;
if (stub_entry->h != NULL) 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 /* This symbol has an entry in the procedure linkage
table. Set it up. */ table. Set it up. */
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
asection *plt, *relplt;
bfd_byte *loc; bfd_byte *loc;
if (!htab->elf.dynamic_sections_created 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_defined
|| h->root.type == bfd_link_hash_defweak))) || h->root.type == bfd_link_hash_defweak)))
continue; continue;
rela.r_offset = (htab->elf.iplt->output_section->vma if (h->type == STT_GNU_IFUNC)
+ htab->elf.iplt->output_offset {
+ ent->plt.offset); plt = htab->elf.iplt;
if (htab->opd_abi) relplt = htab->elf.irelplt;
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); 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 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 rela.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_offset + h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma + h->root.u.def.section->output_section->vma
+ ent->addend); + ent->addend);
loc = (htab->elf.irelplt->contents
+ (htab->elf.irelplt->reloc_count++ if (relplt == NULL)
* sizeof (Elf64_External_Rela))); {
htab->local_ifunc_resolver = 1; 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 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))); / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
if (h->type == STT_GNU_IFUNC && is_static_defined (h)) if (h->type == STT_GNU_IFUNC && is_static_defined (h))
htab->maybe_local_ifunc_resolver = 1; 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) 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; plt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1) || 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 = ent->plt.offset + plt->output_offset + plt->output_section->vma;
off -= h->root.u.def.value + s->output_offset + s->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; asection *plt, *relplt;
bfd_byte *loc; bfd_byte *loc;
bfd_vma val; bfd_vma val;
Elf_Internal_Rela rela;
if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms, if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
lplt - local_plt, ibfd)) 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) if (sym_sec != NULL && sym_sec->output_section != NULL)
val += sym_sec->output_offset + sym_sec->output_section->vma; val += sym_sec->output_offset + sym_sec->output_section->vma;
BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
htab->local_ifunc_resolver = 1; htab->local_ifunc_resolver = 1;
plt = htab->elf.iplt; plt = htab->elf.iplt;
relplt = htab->elf.irelplt; 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 else
rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); {
rela.r_addend = val; plt = htab->pltlocal;
loc = relplt->contents + (relplt->reloc_count++ relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
* sizeof (Elf64_External_Rela)); }
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
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
{
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 if (local_syms != NULL
@ -14792,10 +14924,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
{ {
struct plt_entry **local_plt = (struct plt_entry **) struct plt_entry **local_plt = (struct plt_entry **)
(local_got_ents + symtab_hdr->sh_info); (local_got_ents + symtab_hdr->sh_info);
unsigned char *local_got_tls_masks = (unsigned char *) plt_list = local_plt + r_symndx;
(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) if (plt_list)
{ {
@ -14812,7 +14941,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (!htab->elf.dynamic_sections_created if (!htab->elf.dynamic_sections_created
|| h == NULL || h == NULL
|| h->elf.dynindx == -1) || 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 if (r_type == R_PPC64_PLT16_HA
|| r_type ==R_PPC64_PLT16_HI || r_type ==R_PPC64_PLT16_HI
|| r_type ==R_PPC64_PLT16_LO || 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); + htab->sec_info[input_section->id].toc_off);
relocation -= got; relocation -= got;
} }
relocation = (plt->output_section->vma
+ plt->output_offset
+ ent->plt.offset);
addend = 0; addend = 0;
unresolved_reloc = FALSE; unresolved_reloc = FALSE;
break; break;

View File

@ -1,3 +1,18 @@
2018-04-09 Alan Modra <amodra@gmail.com>
* 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.
2018-04-09 Alan Modra <amodra@gmail.com> 2018-04-09 Alan Modra <amodra@gmail.com>
* powerpc.cc (Target_powerpc::plt_off): New functions. * powerpc.cc (Target_powerpc::plt_off): New functions.

View File

@ -607,7 +607,7 @@ class Target_powerpc : public Sized_target<size, big_endian>
Target_powerpc() Target_powerpc()
: Sized_target<size, big_endian>(&powerpc_info), : Sized_target<size, big_endian>(&powerpc_info),
got_(NULL), plt_(NULL), iplt_(NULL), brlt_section_(NULL), got_(NULL), plt_(NULL), iplt_(NULL), lplt_(NULL), brlt_section_(NULL),
glink_(NULL), rela_dyn_(NULL), copy_relocs_(), glink_(NULL), rela_dyn_(NULL), copy_relocs_(),
tlsld_got_offset_(-1U), tlsld_got_offset_(-1U),
stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(), stub_tables_(), branch_lookup_table_(), branch_info_(), tocsave_loc_(),
@ -860,6 +860,13 @@ class Target_powerpc : public Sized_target<size, big_endian>
return this->iplt_; return this->iplt_;
} }
// Get the LPLT section.
const Output_data_plt_powerpc<size, big_endian>*
lplt_section() const
{
return this->lplt_;
}
// Return the plt offset and section for the given global sym. // Return the plt offset and section for the given global sym.
Address Address
plt_off(const Symbol* gsym, plt_off(const Symbol* gsym,
@ -879,7 +886,11 @@ class Target_powerpc : public Sized_target<size, big_endian>
unsigned int local_sym_index, unsigned int local_sym_index,
const Output_data_plt_powerpc<size, big_endian>** sec) const const Output_data_plt_powerpc<size, big_endian>** sec) const
{ {
*sec = this->iplt_section(); const Symbol_value<size>* lsym = relobj->local_symbol(local_sym_index);
if (lsym->is_ifunc_symbol())
*sec = this->iplt_section();
else
*sec = this->lplt_section();
return relobj->local_plt_offset(local_sym_index); return relobj->local_plt_offset(local_sym_index);
} }
@ -1440,6 +1451,9 @@ class Target_powerpc : public Sized_target<size, big_endian>
void void
make_iplt_section(Symbol_table*, Layout*); make_iplt_section(Symbol_table*, Layout*);
void
make_lplt_section(Layout*);
void void
make_brlt_section(Layout*); make_brlt_section(Layout*);
@ -1453,6 +1467,12 @@ class Target_powerpc : public Sized_target<size, big_endian>
Sized_relobj_file<size, big_endian>*, Sized_relobj_file<size, big_endian>*,
unsigned int); unsigned int);
// Create a PLT entry for a local non-IFUNC symbol.
void
make_local_plt_entry(Layout*,
Sized_relobj_file<size, big_endian>*,
unsigned int);
// Create a GOT entry for local dynamic __tls_get_addr. // Create a GOT entry for local dynamic __tls_get_addr.
unsigned int unsigned int
@ -1585,6 +1605,8 @@ class Target_powerpc : public Sized_target<size, big_endian>
// section is emitted and marked with __rela_iplt_start and // section is emitted and marked with __rela_iplt_start and
// __rela_iplt_end symbols. // __rela_iplt_end symbols.
Output_data_plt_powerpc<size, big_endian>* iplt_; Output_data_plt_powerpc<size, big_endian>* iplt_;
// A PLT style section for local, non-ifunc symbols
Output_data_plt_powerpc<size, big_endian>* lplt_;
// Section holding long branch destinations. // Section holding long branch destinations.
Output_data_brlt_powerpc<size, big_endian>* brlt_section_; Output_data_brlt_powerpc<size, big_endian>* brlt_section_;
// The .glink section. // The .glink section.
@ -2469,6 +2491,35 @@ Powerpc_relobj<size, big_endian>::do_relocate_sections(
} }
this->relocate_section_range(symtab, layout, pshdrs, of, pviews, this->relocate_section_range(symtab, layout, pshdrs, of, pviews,
start, this->shnum() - 1); start, this->shnum() - 1);
if (!parameters->options().output_is_position_independent())
{
Target_powerpc<size, big_endian>* target
= static_cast<Target_powerpc<size, big_endian>*>(
parameters->sized_target<size, big_endian>());
if (target->lplt_section() && target->lplt_section()->data_size() != 0)
{
const section_size_type offset = target->lplt_section()->offset();
const section_size_type oview_size
= convert_to_section_size_type(target->lplt_section()->data_size());
unsigned char* const oview = of->get_output_view(offset, oview_size);
bool modified = false;
unsigned int nsyms = this->local_symbol_count();
for (unsigned int i = 0; i < nsyms; i++)
if (this->local_has_plt_offset(i))
{
Address value = this->local_symbol_value(i, 0);
if (size == 64)
value += ppc64_local_entry_offset(i);
size_t off = this->local_plt_offset(i);
elfcpp::Swap<size, big_endian>::writeval(oview + off, value);
modified = true;
}
if (modified)
of->write_output_view(offset, oview_size, oview);
}
}
} }
// Set up some symbols. // Set up some symbols.
@ -3667,6 +3718,9 @@ class Output_data_plt_powerpc : public Output_section_data_build
void void
add_ifunc_entry(Symbol*); add_ifunc_entry(Symbol*);
void
add_local_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
void void
add_local_ifunc_entry(Sized_relobj_file<size, big_endian>*, unsigned int); add_local_ifunc_entry(Sized_relobj_file<size, big_endian>*, unsigned int);
@ -3704,8 +3758,8 @@ class Output_data_plt_powerpc : public Output_section_data_build
unsigned int unsigned int
first_plt_entry_offset() const first_plt_entry_offset() const
{ {
// IPLT has no reserved entry. // IPLT and LPLT have no reserved entry.
if (this->name_[3] == 'I') if (this->name_[3] == 'I' || this->name_[3] == 'L')
return 0; return 0;
return this->targ_->first_plt_entry_offset(); return this->targ_->first_plt_entry_offset();
} }
@ -3768,6 +3822,31 @@ Output_data_plt_powerpc<size, big_endian>::add_ifunc_entry(Symbol* gsym)
} }
} }
// Add an entry for a local symbol to the PLT.
template<int size, bool big_endian>
void
Output_data_plt_powerpc<size, big_endian>::add_local_entry(
Sized_relobj_file<size, big_endian>* relobj,
unsigned int local_sym_index)
{
if (!relobj->local_has_plt_offset(local_sym_index))
{
section_size_type off = this->current_data_size();
relobj->set_local_plt_offset(local_sym_index, off);
if (this->rel_)
{
unsigned int dynrel = elfcpp::R_POWERPC_RELATIVE;
if (size == 64 && this->targ_->abiversion() < 2)
dynrel = elfcpp::R_POWERPC_JMP_SLOT;
this->rel_->add_symbolless_local_addend(relobj, local_sym_index,
dynrel, this, off, 0);
}
off += this->plt_entry_size();
this->set_current_data_size(off);
}
}
// Add an entry for a local ifunc symbol to the IPLT. // Add an entry for a local ifunc symbol to the IPLT.
template<int size, bool big_endian> template<int size, bool big_endian>
@ -3888,7 +3967,7 @@ template<int size, bool big_endian>
void void
Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of) Output_data_plt_powerpc<size, big_endian>::do_write(Output_file* of)
{ {
if (size == 32 && this->name_[3] != 'I') if (size == 32 && (this->name_[3] != 'I' && this->name_[3] != 'L'))
{ {
const section_size_type offset = this->offset(); const section_size_type offset = this->offset();
const section_size_type oview_size const section_size_type oview_size
@ -3966,6 +4045,7 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
if (this->iplt_ == NULL) if (this->iplt_ == NULL)
{ {
this->make_plt_section(symtab, layout); this->make_plt_section(symtab, layout);
this->make_lplt_section(layout);
Reloc_section* iplt_rel = new Reloc_section(false); Reloc_section* iplt_rel = new Reloc_section(false);
if (this->rela_dyn_->output_section()) if (this->rela_dyn_->output_section())
@ -3978,6 +4058,40 @@ Target_powerpc<size, big_endian>::make_iplt_section(Symbol_table* symtab,
} }
} }
// Create the LPLT section.
template<int size, bool big_endian>
void
Target_powerpc<size, big_endian>::make_lplt_section(Layout* layout)
{
if (this->lplt_ == NULL)
{
Reloc_section* lplt_rel = NULL;
if (parameters->options().output_is_position_independent())
{
lplt_rel = new Reloc_section(false);
this->rela_dyn_section(layout);
if (this->rela_dyn_->output_section())
this->rela_dyn_->output_section()
->add_output_section_data(lplt_rel);
}
this->lplt_
= new Output_data_plt_powerpc<size, big_endian>(this, lplt_rel,
"** LPLT");
this->make_brlt_section(layout);
if (this->brlt_section_ && this->brlt_section_->output_section())
this->brlt_section_->output_section()
->add_output_section_data(this->lplt_);
else
layout->add_output_section_data(".branch_lt",
elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE,
this->lplt_,
ORDER_RELRO,
true);
}
}
// A section for huge long branch addresses, similar to plt section. // A section for huge long branch addresses, similar to plt section.
template<int size, bool big_endian> template<int size, bool big_endian>
@ -6132,6 +6246,20 @@ Target_powerpc<size, big_endian>::make_plt_entry(Symbol_table* symtab,
} }
} }
// Make a PLT entry for a local symbol.
template<int size, bool big_endian>
void
Target_powerpc<size, big_endian>::make_local_plt_entry(
Layout* layout,
Sized_relobj_file<size, big_endian>* relobj,
unsigned int r_sym)
{
if (this->lplt_ == NULL)
this->make_lplt_section(layout);
this->lplt_->add_local_entry(relobj, r_sym);
}
// Make a PLT entry for a local STT_GNU_IFUNC symbol. // Make a PLT entry for a local STT_GNU_IFUNC symbol.
template<int size, bool big_endian> template<int size, bool big_endian>
@ -6669,6 +6797,17 @@ Target_powerpc<size, big_endian>::Scan::local(
} }
break; break;
case elfcpp::R_POWERPC_PLT16_LO:
case elfcpp::R_POWERPC_PLT16_HI:
case elfcpp::R_POWERPC_PLT16_HA:
case elfcpp::R_PPC64_PLT16_LO_DS:
if (!is_ifunc)
{
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
target->make_local_plt_entry(layout, object, r_sym);
}
break;
case elfcpp::R_POWERPC_REL24: case elfcpp::R_POWERPC_REL24:
case elfcpp::R_PPC_PLTREL24: case elfcpp::R_PPC_PLTREL24:
case elfcpp::R_PPC_LOCAL24PC: case elfcpp::R_PPC_LOCAL24PC:

View File

@ -1,3 +1,13 @@
2018-04-09 Alan Modra <amodra@gmail.com>
* 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.
2018-04-09 Alan Modra <amodra@gmail.com> 2018-04-09 Alan Modra <amodra@gmail.com>
* ppc32elf.em (ppc_finish): Call ppc_finish_symbols. * ppc32elf.em (ppc_finish): Call ppc_finish_symbols.

View File

@ -15,6 +15,10 @@ GOTPLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) }"
PLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) } PLT=".plt ${RELOCATING-0} : SPECIAL { *(.plt) }
.iplt ${RELOCATING-0} : { *(.iplt) }" .iplt ${RELOCATING-0} : { *(.iplt) }"
OTHER_TEXT_SECTIONS="*(.glink)" OTHER_TEXT_SECTIONS="*(.glink)"
OTHER_GOT_RELOC_SECTIONS="
.rela.branch_lt ${RELOCATING-0} : { *(.rela.branch_lt) }"
OTHER_RELRO_SECTIONS_2="
.branch_lt ${RELOCATING-0} :${RELOCATING+ ALIGN(4)} { *(.branch_lt) }"
EXTRA_EM_FILE=ppc32elf EXTRA_EM_FILE=ppc32elf
if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then if grep -q 'ld_elf32_spu_emulation' ldemul-list.h; then
# crt1.o defines data_start and __data_start. Keep them first. # crt1.o defines data_start and __data_start. Keep them first.

View File

@ -14,16 +14,16 @@ Disassembly of section \.text:
.*: (4e 80 04 20|20 04 80 4e) bctr .*: (4e 80 04 20|20 04 80 4e) bctr
\.\.\. \.\.\.
.* <.*\.plt_call\.f1>: .* <.*\.plt_call\.f3>:
.*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\) .*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\)
.*: (e9 82 80 40|40 80 82 e9) ld r12,-32704\(r2\) .*: (e9 82 80 28|28 80 82 e9) ld r12,-32728\(r2\)
.*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 .*: (7d 89 03 a6|a6 03 89 7d) mtctr r12
.*: (4e 80 04 20|20 04 80 4e) bctr .*: (4e 80 04 20|20 04 80 4e) bctr
\.\.\. \.\.\.
.* <.*\.plt_call\.f3>: .* <.*\.plt_call\.f1>:
.*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\) .*: (f8 41 00 18|18 00 41 f8) std r2,24\(r1\)
.*: (e9 82 80 28|28 80 82 e9) ld r12,-32728\(r2\) .*: (e9 82 80 40|40 80 82 e9) ld r12,-32704\(r2\)
.*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 .*: (7d 89 03 a6|a6 03 89 7d) mtctr r12
.*: (4e 80 04 20|20 04 80 4e) bctr .*: (4e 80 04 20|20 04 80 4e) bctr
\.\.\. \.\.\.
@ -41,12 +41,12 @@ Disassembly of section \.text:
.*: (7c 08 02 a6|a6 02 08 7c) mflr r0 .*: (7c 08 02 a6|a6 02 08 7c) mflr r0
.*: (f8 21 ff e1|e1 ff 21 f8) stdu r1,-32\(r1\) .*: (f8 21 ff e1|e1 ff 21 f8) stdu r1,-32\(r1\)
.*: (f8 01 00 30|30 00 01 f8) std r0,48\(r1\) .*: (f8 01 00 30|30 00 01 f8) std r0,48\(r1\)
.*: (4b ff ff 8d|8d ff ff 4b) bl .*\.plt_call\.f1> .*: (4b ff ff ad|ad ff ff 4b) bl .*\.plt_call\.f1>
.*: (e8 62 80 08|08 80 62 e8) ld r3,-32760\(r2\) .*: (e8 62 80 08|08 80 62 e8) ld r3,-32760\(r2\)
.*: (4b ff ff c5|c5 ff ff 4b) bl .*\.plt_call\.f2> .*: (4b ff ff c5|c5 ff ff 4b) bl .*\.plt_call\.f2>
.*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\)
.*: (e8 62 80 10|10 80 62 e8) ld r3,-32752\(r2\) .*: (e8 62 80 10|10 80 62 e8) ld r3,-32752\(r2\)
.*: (4b ff ff 99|99 ff ff 4b) bl .*\.plt_call\.f3> .*: (4b ff ff 79|79 ff ff 4b) bl .*\.plt_call\.f3>
.*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\)
.*: (4b ff ff 51|51 ff ff 4b) bl .*\.plt_call\.f4> .*: (4b ff ff 51|51 ff ff 4b) bl .*\.plt_call\.f4>
.*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\) .*: (e8 41 00 18|18 00 41 e8) ld r2,24\(r1\)

View File

@ -8,32 +8,32 @@
Disassembly of section \.text: Disassembly of section \.text:
0*100000c0 <_start>: 0*100000c0 <_start>:
[0-9a-f ]*: (49 bf 00 21|21 00 bf 49) bl .* [0-9a-f ]*: (49 bf 00 2d|2d 00 bf 49) bl .*
[0-9a-f ]*: R_PPC64_REL24 \.text\+0x37e003c [0-9a-f ]*: R_PPC64_REL24 \.text\+0x37e003c
[0-9a-f ]*: (60 00 00 00|00 00 00 60) nop [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop
[0-9a-f ]*: (49 bf 00 1d|1d 00 bf 49) bl .* [0-9a-f ]*: (49 bf 00 19|19 00 bf 49) bl .*
[0-9a-f ]*: R_PPC64_REL24 \.text\+0x3bf002c [0-9a-f ]*: R_PPC64_REL24 \.text\+0x3bf0020
[0-9a-f ]*: (60 00 00 00|00 00 00 60) nop [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop
[0-9a-f ]*: (49 bf 00 21|21 00 bf 49) bl .* [0-9a-f ]*: (49 bf 00 21|21 00 bf 49) bl .*
[0-9a-f ]*: R_PPC64_REL24 \.text\+0x57e0030 [0-9a-f ]*: R_PPC64_REL24 \.text\+0x57e0024
[0-9a-f ]*: (60 00 00 00|00 00 00 60) nop [0-9a-f ]*: (60 00 00 00|00 00 00 60) nop
[0-9a-f ]*: 00 00 00 00 \.long 0x0 [0-9a-f ]*: 00 00 00 00 \.long 0x0
[0-9a-f ]*: (4b ff ff e4|e4 ff ff 4b) b .* <_start> [0-9a-f ]*: (4b ff ff e4|e4 ff ff 4b) b .* <_start>
\.\.\. \.\.\.
[0-9a-f ]*<.*long_branch.*>:
[0-9a-f ]*: (49 bf 00 1c|1c 00 bf 49) b .* <far>
[0-9a-f ]*: R_PPC64_REL24 \*ABS\*\+0x137e00fc
[0-9a-f ]*<.*plt_branch.*>: [0-9a-f ]*<.*plt_branch.*>:
[0-9a-f ]*: (e9 82 80 f8|f8 80 82 e9) ld r12,-32520\(r2\) [0-9a-f ]*: (e9 82 80 e8|e8 80 82 e9) ld r12,-32536\(r2\)
[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00f8 [0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00e8
[0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 [0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12
[0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr [0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr
[0-9a-f ]*<.*long_branch.*>:
[0-9a-f ]*: (49 bf 00 10|10 00 bf 49) b .* <far>
[0-9a-f ]*: R_PPC64_REL24 \*ABS\*\+0x137e00fc
[0-9a-f ]*<.*plt_branch.*>: [0-9a-f ]*<.*plt_branch.*>:
[0-9a-f ]*: (e9 82 81 00|00 81 82 e9) ld r12,-32512\(r2\) [0-9a-f ]*: (e9 82 80 f0|f0 80 82 e9) ld r12,-32528\(r2\)
[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f0100 [0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00f0
[0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12 [0-9a-f ]*: (7d 89 03 a6|a6 03 89 7d) mtctr r12
[0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr [0-9a-f ]*: (4e 80 04 20|20 04 80 4e) bctr
\.\.\. \.\.\.
@ -42,19 +42,19 @@ Disassembly of section \.text:
[0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr
\.\.\. \.\.\.
0*13bf00ec <far2far>: 0*13bf00e0 <far2far>:
[0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr
\.\.\. \.\.\.
0*157e00f0 <huge>: 0*157e00e4 <huge>:
[0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr [0-9a-f ]*: (4e 80 00 20|20 00 80 4e) blr
Disassembly of section \.branch_lt: Disassembly of section \.branch_lt:
0*157f00f8 .*: 0*157f00e8 .*:
[0-9a-f ]*: (00 00 00 00|ec 00 bf 13) .* [0-9a-f ]*: (00 00 00 00|e0 00 bf 13) .*
[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x13bf00ec [0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x13bf00e0
[0-9a-f ]*: (13 bf 00 ec|00 00 00 00) .* [0-9a-f ]*: (13 bf 00 e0|00 00 00 00) .*
[0-9a-f ]*: (00 00 00 00|f0 00 7e 15) .* [0-9a-f ]*: (00 00 00 00|e4 00 7e 15) .*
[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x157e00f0 [0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x157e00e4
[0-9a-f ]*: (15 7e 00 f0|00 00 00 00) .* [0-9a-f ]*: (15 7e 00 e4|00 00 00 00) .*

View File

@ -20,7 +20,7 @@ far:
blr blr
.section .text.pad2,"ax" .section .text.pad2,"ax"
.space 0x40ffec .space 0x40ffe0
.section .text.far2far,"ax" .section .text.far2far,"ax"
far2far: far2far:

View File

@ -114,8 +114,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
.* TLS +LOCAL +DEFAULT +7 le5 .* TLS +LOCAL +DEFAULT +7 le5
.* FILE +LOCAL +DEFAULT +ABS .* FILE +LOCAL +DEFAULT +ABS
.* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
.* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve
.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
.* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +UND gd
.* TLS +GLOBAL +DEFAULT +8 le0 .* TLS +GLOBAL +DEFAULT +8 le0
.* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr

View File

@ -110,8 +110,8 @@ Symbol table '\.symtab' contains [0-9]+ entries:
.* NOTYPE +LOCAL +DEFAULT +11 \.Lie0 .* NOTYPE +LOCAL +DEFAULT +11 \.Lie0
.* FILE +LOCAL +DEFAULT +ABS .* FILE +LOCAL +DEFAULT +ABS
.* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC .* OBJECT +LOCAL +DEFAULT +9 _DYNAMIC
.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
.* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve .* NOTYPE +LOCAL +DEFAULT +6 __glink_PLTresolve
.* NOTYPE +LOCAL +DEFAULT +6 .*\.plt_call\.__tls_get_addr
.* TLS +GLOBAL +DEFAULT +UND gd .* TLS +GLOBAL +DEFAULT +UND gd
.* TLS +GLOBAL +DEFAULT +8 le0 .* TLS +GLOBAL +DEFAULT +8 le0
.* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr .* NOTYPE +GLOBAL +DEFAULT +UND __tls_get_addr