Rearrange PLT reloc output on powerpc

The current scheme where we output PLT relocs for global symbols in
finish_dynamic_symbol, and PLT relocs for local symbols when
outputting stubs does not work if PLT entries are to be used for
inline PLT sequences against non-dynamic globals or local symbols.

bfd/
	* elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
	for local symbols to..
	(write_plt_relocs_for_local_syms): ..here.  New function.
	(ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
	global symbols to..
	(build_global_entry_stubs_and_plt): ..here.  Rename from
	build_global_entry_stubs.
	(ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
	Call write_plt_relocs_for_local_syms.
	* elf32-ppc.c (get_sym_h): New function.
	(ppc_elf_relax_section): Use get_sym_h.
	(ppc_elf_relocate_section): Move output of PLT relocs and glink
	stubs for local symbols to..
	(ppc_finish_symbols): ..here.  New function.
	(ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
	global syms to..
	(write_global_sym_plt): ..here.  New function.
	* elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
	(ppc_finish_symbols): Declare.
ld/
	* ppc32elf.em (ppc_finish): Call ppc_finish_symbols.
This commit is contained in:
Alan Modra 2018-04-09 09:21:59 +09:30
parent 08be322439
commit 49c09209d0
6 changed files with 494 additions and 245 deletions

View File

@ -1,3 +1,25 @@
2018-04-09 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc_build_one_stub): Move output of PLT relocs
for local symbols to..
(write_plt_relocs_for_local_syms): ..here. New function.
(ppc64_elf_finish_dynamic_symbol): Move output of PLT relocs for
global symbols to..
(build_global_entry_stubs_and_plt): ..here. Rename from
build_global_entry_stubs.
(ppc64_elf_build_stubs): Always call build_global_entry_stubs_and_plt.
Call write_plt_relocs_for_local_syms.
* elf32-ppc.c (get_sym_h): New function.
(ppc_elf_relax_section): Use get_sym_h.
(ppc_elf_relocate_section): Move output of PLT relocs and glink
stubs for local symbols to..
(ppc_finish_symbols): ..here. New function.
(ppc_elf_finish_dynamic_symbol): Move output of PLT relocs for
global syms to..
(write_global_sym_plt): ..here. New function.
* elf32-ppc.h (ppc_elf_modify_segment_map): Delete attribute.
(ppc_finish_symbols): Declare.
2018-04-09 Alan Modra <amodra@gmail.com> 2018-04-09 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs. * elf32-ppc.c (ppc_elf_check_relocs): Handle PLT16 relocs.

View File

@ -5085,6 +5085,93 @@ ppc_elf_gc_mark_hook (asection *sec,
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
} }
static bfd_boolean
get_sym_h (struct elf_link_hash_entry **hp,
Elf_Internal_Sym **symp,
asection **symsecp,
unsigned char **tls_maskp,
Elf_Internal_Sym **locsymsp,
unsigned long r_symndx,
bfd *ibfd)
{
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
if (r_symndx >= symtab_hdr->sh_info)
{
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
struct elf_link_hash_entry *h;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
if (hp != NULL)
*hp = h;
if (symp != NULL)
*symp = NULL;
if (symsecp != NULL)
{
asection *symsec = NULL;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
symsec = h->root.u.def.section;
*symsecp = symsec;
}
if (tls_maskp != NULL)
*tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
}
else
{
Elf_Internal_Sym *sym;
Elf_Internal_Sym *locsyms = *locsymsp;
if (locsyms == NULL)
{
locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
if (locsyms == NULL)
locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
symtab_hdr->sh_info,
0, NULL, NULL, NULL);
if (locsyms == NULL)
return FALSE;
*locsymsp = locsyms;
}
sym = locsyms + r_symndx;
if (hp != NULL)
*hp = NULL;
if (symp != NULL)
*symp = sym;
if (symsecp != NULL)
*symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
if (tls_maskp != NULL)
{
bfd_signed_vma *local_got;
unsigned char *tls_mask;
tls_mask = NULL;
local_got = elf_local_got_refcounts (ibfd);
if (local_got != NULL)
{
struct plt_entry **local_plt = (struct plt_entry **)
(local_got + symtab_hdr->sh_info);
unsigned char *lgot_masks = (unsigned char *)
(local_plt + symtab_hdr->sh_info);
tls_mask = &lgot_masks[r_symndx];
}
*tls_maskp = tls_mask;
}
}
return TRUE;
}
/* Set plt output section type, htab->tls_get_addr, and call the /* Set plt output section type, htab->tls_get_addr, and call the
generic ELF tls_setup function. */ generic ELF tls_setup function. */
@ -6892,6 +6979,7 @@ ppc_elf_relax_section (bfd *abfd,
bfd_byte *hit_addr; bfd_byte *hit_addr;
unsigned long t0; unsigned long t0;
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
Elf_Internal_Sym *isym;
struct plt_entry **plist; struct plt_entry **plist;
unsigned char sym_type; unsigned char sym_type;
@ -6919,57 +7007,34 @@ ppc_elf_relax_section (bfd *abfd,
} }
/* Get the value of the symbol referred to by the reloc. */ /* Get the value of the symbol referred to by the reloc. */
h = NULL; if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) ELF32_R_SYM (irel->r_info), abfd))
{
/* A local symbol. */
Elf_Internal_Sym *isym;
/* Read this BFD's local symbols. */
if (isymbuf == NULL)
{
isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
if (isymbuf == NULL)
isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
symtab_hdr->sh_info, 0,
NULL, NULL, NULL);
if (isymbuf == 0)
goto error_return; goto error_return;
}
isym = isymbuf + ELF32_R_SYM (irel->r_info); if (isym != NULL)
if (isym->st_shndx == SHN_UNDEF) {
if (tsec != NULL)
;
else if (isym->st_shndx == SHN_UNDEF)
tsec = bfd_und_section_ptr; tsec = bfd_und_section_ptr;
else if (isym->st_shndx == SHN_ABS) else if (isym->st_shndx == SHN_ABS)
tsec = bfd_abs_section_ptr; tsec = bfd_abs_section_ptr;
else if (isym->st_shndx == SHN_COMMON) else if (isym->st_shndx == SHN_COMMON)
tsec = bfd_com_section_ptr; tsec = bfd_com_section_ptr;
else
tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
toff = isym->st_value; toff = isym->st_value;
sym_type = ELF_ST_TYPE (isym->st_info); sym_type = ELF_ST_TYPE (isym->st_info);
} }
else else
{ {
/* Global symbol handling. */ if (tsec != NULL)
unsigned long indx;
indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
h = elf_sym_hashes (abfd)[indx];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
tsec = h->root.u.def.section;
toff = h->root.u.def.value; toff = h->root.u.def.value;
}
else if (h->root.type == bfd_link_hash_undefined else if (h->root.type == bfd_link_hash_undefined
|| h->root.type == bfd_link_hash_undefweak) || h->root.type == bfd_link_hash_undefweak)
{ {
unsigned long indx;
indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
tsec = bfd_und_section_ptr; tsec = bfd_und_section_ptr;
toff = bfd_link_relocatable (link_info) ? indx : 0; toff = bfd_link_relocatable (link_info) ? indx : 0;
} }
@ -8308,32 +8373,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
(_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"), (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
input_bfd, input_section, rel->r_offset, sym_name); input_bfd, input_section, rel->r_offset, sym_name);
} }
if (h == NULL && (ent->plt.offset & 1) == 0)
{
Elf_Internal_Rela rela;
bfd_byte *loc;
rela.r_offset = (htab->elf.iplt->output_section->vma
+ htab->elf.iplt->output_offset
+ ent->plt.offset);
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
rela.r_addend = relocation;
loc = htab->elf.irelplt->contents;
loc += (htab->elf.irelplt->reloc_count++
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
htab->local_ifunc_resolver = 1;
ent->plt.offset |= 1;
}
if (h == NULL && (ent->glink_offset & 1) == 0)
{
unsigned char *p = ((unsigned char *) htab->glink->contents
+ ent->glink_offset);
write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
ent->glink_offset |= 1;
}
unresolved_reloc = FALSE; unresolved_reloc = FALSE;
if (htab->plt_type == PLT_NEW if (htab->plt_type == PLT_NEW
@ -10027,27 +10066,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
return ret; return ret;
} }
/* Finish up dynamic symbol handling. We set the contents of various /* Write out the PLT relocs and entries for H. */
dynamic sections here. */
static bfd_boolean static bfd_boolean
ppc_elf_finish_dynamic_symbol (bfd *output_bfd, write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{ {
struct ppc_elf_link_hash_table *htab; struct bfd_link_info *info = (struct bfd_link_info *) inf;
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
struct plt_entry *ent; struct plt_entry *ent;
bfd_boolean doneone; bfd_boolean doneone;
#ifdef DEBUG
fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
h->root.root.string);
#endif
htab = ppc_elf_hash_table (info);
BFD_ASSERT (htab->elf.dynobj != NULL);
doneone = FALSE; doneone = FALSE;
for (ent = h->plt.plist; ent != NULL; ent = ent->next) for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1) if (ent->plt.offset != (bfd_vma) -1)
@ -10090,10 +10118,10 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
/* Fill in the .plt on VxWorks. */ /* Fill in the .plt on VxWorks. */
if (bfd_link_pic (info)) if (bfd_link_pic (info))
{ {
bfd_put_32 (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); htab->elf.splt->contents + ent->plt.offset + 0);
bfd_put_32 (output_bfd, bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_offset), plt_entry[1] | PPC_LO (got_offset),
htab->elf.splt->contents + ent->plt.offset + 4); htab->elf.splt->contents + ent->plt.offset + 4);
} }
@ -10101,17 +10129,17 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
{ {
bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot); bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
bfd_put_32 (output_bfd, bfd_put_32 (info->output_bfd,
plt_entry[0] | PPC_HA (got_loc), plt_entry[0] | PPC_HA (got_loc),
htab->elf.splt->contents + ent->plt.offset + 0); htab->elf.splt->contents + ent->plt.offset + 0);
bfd_put_32 (output_bfd, bfd_put_32 (info->output_bfd,
plt_entry[1] | PPC_LO (got_loc), plt_entry[1] | PPC_LO (got_loc),
htab->elf.splt->contents + ent->plt.offset + 4); htab->elf.splt->contents + ent->plt.offset + 4);
} }
bfd_put_32 (output_bfd, plt_entry[2], bfd_put_32 (info->output_bfd, plt_entry[2],
htab->elf.splt->contents + ent->plt.offset + 8); htab->elf.splt->contents + ent->plt.offset + 8);
bfd_put_32 (output_bfd, plt_entry[3], bfd_put_32 (info->output_bfd, plt_entry[3],
htab->elf.splt->contents + ent->plt.offset + 12); htab->elf.splt->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
@ -10120,7 +10148,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
low-order 16 bits of the load instruction. */ low-order 16 bits of the load instruction. */
/* NOTE: It appears that this is now an index rather than a /* NOTE: It appears that this is now an index rather than a
prescaled offset. */ prescaled offset. */
bfd_put_32 (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); htab->elf.splt->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
@ -10129,19 +10157,20 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
The address is encoded in bits 6-29, inclusive. The value The address is encoded in bits 6-29, inclusive. The value
stored is right-shifted by two bits, permitting a 26-bit stored is right-shifted by two bits, permitting a 26-bit
offset. */ offset. */
bfd_put_32 (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); htab->elf.splt->contents + ent->plt.offset + 20);
bfd_put_32 (output_bfd, plt_entry[6], bfd_put_32 (info->output_bfd, plt_entry[6],
htab->elf.splt->contents + ent->plt.offset + 24); htab->elf.splt->contents + ent->plt.offset + 24);
bfd_put_32 (output_bfd, plt_entry[7], bfd_put_32 (info->output_bfd, plt_entry[7],
htab->elf.splt->contents + ent->plt.offset + 28); htab->elf.splt->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 (output_bfd, (htab->elf.splt->output_section->vma bfd_put_32 (info->output_bfd,
(htab->elf.splt->output_section->vma
+ htab->elf.splt->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);
@ -10161,7 +10190,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
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);
rela.r_addend = got_offset; rela.r_addend = got_offset;
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela); loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */ /* Provide the @l relocation for the second instruction. */
@ -10171,7 +10200,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO); R_PPC_ADDR16_LO);
rela.r_addend = got_offset; rela.r_addend = got_offset;
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
loc += sizeof (Elf32_External_Rela); loc += sizeof (Elf32_External_Rela);
/* Provide a relocation for the GOT entry corresponding to this /* Provide a relocation for the GOT entry corresponding to this
@ -10182,7 +10211,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
R_PPC_ADDR32); R_PPC_ADDR32);
rela.r_addend = ent->plt.offset + 16; rela.r_addend = ent->plt.offset + 16;
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
} }
/* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
@ -10217,7 +10246,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
bfd_vma val = (htab->glink_pltresolve + ent->plt.offset bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+ htab->glink->output_section->vma + htab->glink->output_section->vma
+ htab->glink->output_offset); + htab->glink->output_offset);
bfd_put_32 (output_bfd, val, bfd_put_32 (info->output_bfd, val,
splt->contents + ent->plt.offset); splt->contents + ent->plt.offset);
} }
} }
@ -10252,8 +10281,152 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
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_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
doneone = TRUE;
}
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
unsigned char *p;
asection *plt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
plt = htab->elf.iplt;
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
write_glink_stub (h, ent, plt, p, info);
if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
break;
}
else
break;
}
return TRUE;
}
/* Finish up PLT handling. */
bfd_boolean
ppc_finish_symbols (struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
bfd *ibfd;
if (!htab)
return TRUE;
elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
bfd_vma *local_got, *end_local_got;
struct plt_entry **local_plt, **lplt, **end_local_plt;
Elf_Internal_Shdr *symtab_hdr;
bfd_size_type locsymcount;
Elf_Internal_Sym *local_syms = NULL;
struct plt_entry *ent;
if (!is_ppc_elf (ibfd))
continue;
local_got = elf_local_got_offsets (ibfd);
if (!local_got)
continue;
symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
local_plt = (struct plt_entry **) end_local_got;
end_local_plt = local_plt + locsymcount;
for (lplt = local_plt; lplt < end_local_plt; ++lplt)
for (ent = *lplt; ent != NULL; ent = ent->next)
{
if (ent->plt.offset != (bfd_vma) -1)
{
Elf_Internal_Sym *sym;
asection *sym_sec;
asection *plt, *relplt;
bfd_byte *loc;
bfd_vma val;
Elf_Internal_Rela rela;
if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
lplt - local_plt, ibfd))
{
if (local_syms != NULL
&& symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
return FALSE;
}
val = sym->st_value;
if (sym_sec != NULL && sym_sec->output_section != NULL)
val += sym_sec->output_offset + sym_sec->output_section->vma;
BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
htab->local_ifunc_resolver = 1;
plt = htab->elf.iplt;
relplt = htab->elf.irelplt;
rela.r_offset = (ent->plt.offset
+ plt->output_offset
+ plt->output_section->vma);
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
rela.r_addend = val;
loc = relplt->contents + (relplt->reloc_count++
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
}
if ((ent->glink_offset & 1) == 0)
{
unsigned char *p = ((unsigned char *) htab->glink->contents
+ ent->glink_offset);
write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
ent->glink_offset |= 1;
}
}
if (local_syms != NULL
&& symtab_hdr->contents != (unsigned char *) local_syms)
{
if (!info->keep_memory)
free (local_syms);
else
symtab_hdr->contents = (unsigned char *) local_syms;
}
}
return TRUE;
}
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
static bfd_boolean
ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
struct plt_entry *ent;
#ifdef DEBUG
fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
h->root.root.string);
#endif
if (!h->def_regular
|| (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
if (!h->def_regular) if (!h->def_regular)
{ {
/* Mark the symbol as undefined, rather than as /* Mark the symbol as undefined, rather than as
@ -10274,8 +10447,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0; sym->st_value = 0;
} }
} }
else if (h->type == STT_GNU_IFUNC else
&& !bfd_link_pic (info))
{ {
/* Set the value of ifunc symbols in a non-pie /* Set the value of ifunc symbols in a non-pie
executable to the glink entry. This is to avoid executable to the glink entry. This is to avoid
@ -10284,34 +10456,13 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
function symbols with plt entries, because we need function symbols with plt entries, because we need
to keep the original value around for the ifunc to keep the original value around for the ifunc
relocation. */ relocation. */
sym->st_shndx = (_bfd_elf_section_from_bfd_section sym->st_shndx
(output_bfd, htab->glink->output_section)); = (_bfd_elf_section_from_bfd_section
(info->output_bfd, htab->glink->output_section));
sym->st_value = (ent->glink_offset sym->st_value = (ent->glink_offset
+ htab->glink->output_offset + htab->glink->output_offset
+ htab->glink->output_section->vma); + htab->glink->output_section->vma);
} }
doneone = TRUE;
}
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
unsigned char *p;
asection *splt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
splt = htab->elf.iplt;
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
write_glink_stub (h, ent, splt, p, info);
if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
break;
}
else
break; break;
} }

View File

@ -63,6 +63,6 @@ int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *);
asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *); asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *); bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *); void ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *);
extern bfd_boolean ppc_elf_modify_segment_map (bfd *, extern bfd_boolean ppc_elf_modify_segment_map (bfd *, struct bfd_link_info *);
struct bfd_link_info * ATTRIBUTE_UNUSED);
extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *); extern bfd_boolean ppc_elf_section_processing (bfd *, Elf_Internal_Shdr *);
extern bfd_boolean ppc_finish_symbols (struct bfd_link_info *);

View File

@ -11158,29 +11158,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
dest += plt->output_offset + plt->output_section->vma; dest += plt->output_offset + plt->output_section->vma;
if (stub_entry->h == NULL
&& (stub_entry->plt_ent->plt.offset & 1) == 0)
{
Elf_Internal_Rela rela;
bfd_byte *rl;
rela.r_offset = dest;
if (htab->opd_abi)
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
else
rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
rela.r_addend = (stub_entry->target_value
+ stub_entry->target_section->output_offset
+ stub_entry->target_section->output_section->vma);
rl = (htab->elf.irelplt->contents
+ (htab->elf.irelplt->reloc_count++
* sizeof (Elf64_External_Rela)));
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
stub_entry->plt_ent->plt.offset |= 1;
htab->local_ifunc_resolver = 1;
}
off = (dest off = (dest
- elf_gp (info->output_bfd) - elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off); - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
@ -13016,34 +12993,84 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
} }
/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to /* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
write out any global entry stubs. */ write out any global entry stubs, and PLT relocations. */
static bfd_boolean static bfd_boolean
build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
{ {
struct bfd_link_info *info; struct bfd_link_info *info;
struct ppc_link_hash_table *htab; struct ppc_link_hash_table *htab;
struct plt_entry *pent; struct plt_entry *ent;
asection *s; asection *s;
if (h->root.type == bfd_link_hash_indirect) if (h->root.type == bfd_link_hash_indirect)
return TRUE; return TRUE;
if (!h->pointer_equality_needed)
return TRUE;
if (h->def_regular)
return TRUE;
info = inf; info = inf;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (htab == NULL) if (htab == NULL)
return FALSE; return FALSE;
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
/* This symbol has an entry in the procedure linkage
table. Set it up. */
Elf_Internal_Rela rela;
bfd_byte *loc;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
if (!(h->def_regular
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)))
continue;
rela.r_offset = (htab->elf.iplt->output_section->vma
+ htab->elf.iplt->output_offset
+ ent->plt.offset);
if (htab->opd_abi)
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
else
rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
rela.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma
+ ent->addend);
loc = (htab->elf.irelplt->contents
+ (htab->elf.irelplt->reloc_count++
* sizeof (Elf64_External_Rela)));
htab->local_ifunc_resolver = 1;
}
else
{
rela.r_offset = (htab->elf.splt->output_section->vma
+ htab->elf.splt->output_offset
+ ent->plt.offset);
rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
rela.r_addend = ent->addend;
loc = (htab->elf.srelplt->contents
+ ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
/ PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
if (h->type == STT_GNU_IFUNC && is_static_defined (h))
htab->maybe_local_ifunc_resolver = 1;
}
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
}
if (!h->pointer_equality_needed)
return TRUE;
if (h->def_regular)
return TRUE;
s = htab->global_entry; s = htab->global_entry;
for (pent = h->plt.plist; pent != NULL; pent = pent->next) if (s == NULL || s->size == 0)
if (pent->plt.offset != (bfd_vma) -1 return TRUE;
&& pent->addend == 0)
for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1
&& ent->addend == 0)
{ {
bfd_byte *p; bfd_byte *p;
asection *plt; asection *plt;
@ -13054,7 +13081,7 @@ build_global_entry_stubs (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; plt = htab->elf.iplt;
off = pent->plt.offset + plt->output_offset + plt->output_section->vma; off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
off -= h->root.u.def.value + s->output_offset + s->output_section->vma; off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
if (off + 0x80008000 > 0xffffffff || (off & 3) != 0) if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
@ -13108,6 +13135,91 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
return TRUE; return TRUE;
} }
/* Write PLT relocs for locals. */
static bfd_boolean
write_plt_relocs_for_local_syms (struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
bfd *ibfd;
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
struct got_entry **lgot_ents, **end_lgot_ents;
struct plt_entry **local_plt, **lplt, **end_local_plt;
Elf_Internal_Shdr *symtab_hdr;
bfd_size_type locsymcount;
Elf_Internal_Sym *local_syms = NULL;
struct plt_entry *ent;
if (!is_ppc64_elf (ibfd))
continue;
lgot_ents = elf_local_got_ents (ibfd);
if (!lgot_ents)
continue;
symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
end_lgot_ents = lgot_ents + locsymcount;
local_plt = (struct plt_entry **) end_lgot_ents;
end_local_plt = local_plt + locsymcount;
for (lplt = local_plt; lplt < end_local_plt; ++lplt)
for (ent = *lplt; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1)
{
Elf_Internal_Sym *sym;
asection *sym_sec;
asection *plt, *relplt;
bfd_byte *loc;
bfd_vma val;
Elf_Internal_Rela rela;
if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
lplt - local_plt, ibfd))
{
if (local_syms != NULL
&& symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
return FALSE;
}
val = sym->st_value + ent->addend;
val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
if (sym_sec != NULL && sym_sec->output_section != NULL)
val += sym_sec->output_offset + sym_sec->output_section->vma;
BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
htab->local_ifunc_resolver = 1;
plt = htab->elf.iplt;
relplt = htab->elf.irelplt;
rela.r_offset = (ent->plt.offset
+ plt->output_offset
+ plt->output_section->vma);
if (htab->opd_abi)
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
else
rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
rela.r_addend = val;
loc = relplt->contents + (relplt->reloc_count++
* sizeof (Elf64_External_Rela));
bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
}
if (local_syms != NULL
&& symtab_hdr->contents != (unsigned char *) local_syms)
{
if (!info->keep_memory)
free (local_syms);
else
symtab_hdr->contents = (unsigned char *) local_syms;
}
}
return TRUE;
}
/* Build all the stubs associated with the current output file. /* Build all the stubs associated with the current output file.
The stubs are kept in a hash table attached to the main linker The stubs are kept in a hash table attached to the main linker
hash table. This function is called via gldelf64ppc_finish. */ hash table. This function is called via gldelf64ppc_finish. */
@ -13262,9 +13374,11 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
} }
} }
/* Build .glink global entry stubs. */ /* Build .glink global entry stubs, and PLT relocs for globals. */
if (htab->global_entry != NULL && htab->global_entry->size != 0) elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
if (!write_plt_relocs_for_local_syms (info))
return FALSE;
if (htab->brlt != NULL && htab->brlt->size != 0) if (htab->brlt != NULL && htab->brlt->size != 0)
{ {
@ -15488,59 +15602,14 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
{ {
struct ppc_link_hash_table *htab; struct ppc_link_hash_table *htab;
struct plt_entry *ent; struct plt_entry *ent;
Elf_Internal_Rela rela;
bfd_byte *loc;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (htab == NULL) if (htab == NULL)
return FALSE; return FALSE;
if (!htab->opd_abi && !h->def_regular)
for (ent = h->plt.plist; ent != NULL; ent = ent->next) for (ent = h->plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.offset != (bfd_vma) -1) if (ent->plt.offset != (bfd_vma) -1)
{
/* This symbol has an entry in the procedure linkage
table. Set it up. */
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
BFD_ASSERT (h->type == STT_GNU_IFUNC
&& h->def_regular
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak));
rela.r_offset = (htab->elf.iplt->output_section->vma
+ htab->elf.iplt->output_offset
+ ent->plt.offset);
if (htab->opd_abi)
rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
else
rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
rela.r_addend = (h->root.u.def.value
+ h->root.u.def.section->output_offset
+ h->root.u.def.section->output_section->vma
+ ent->addend);
loc = (htab->elf.irelplt->contents
+ (htab->elf.irelplt->reloc_count++
* sizeof (Elf64_External_Rela)));
htab->local_ifunc_resolver = 1;
}
else
{
rela.r_offset = (htab->elf.splt->output_section->vma
+ htab->elf.splt->output_offset
+ ent->plt.offset);
rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
rela.r_addend = ent->addend;
loc = (htab->elf.srelplt->contents
+ ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
/ PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
if (h->type == STT_GNU_IFUNC && is_static_defined (h))
htab->maybe_local_ifunc_resolver = 1;
}
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
if (!htab->opd_abi)
{
if (!h->def_regular)
{ {
/* Mark the symbol as undefined, rather than as /* Mark the symbol as undefined, rather than as
defined in glink. Leave the value if there were defined in glink. Leave the value if there were
@ -15559,14 +15628,15 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
function pointer. */ function pointer. */
sym->st_value = 0; sym->st_value = 0;
} }
} break;
}
} }
if (h->needs_copy) if (h->needs_copy)
{ {
/* This symbol needs a copy reloc. Set it up. */ /* This symbol needs a copy reloc. Set it up. */
Elf_Internal_Rela rela;
asection *srel; asection *srel;
bfd_byte *loc;
if (h->dynindx == -1 if (h->dynindx == -1
|| (h->root.type != bfd_link_hash_defined || (h->root.type != bfd_link_hash_defined

View File

@ -1,3 +1,7 @@
2018-04-09 Alan Modra <amodra@gmail.com>
* ppc32elf.em (ppc_finish): Call ppc_finish_symbols.
2018-04-05 H.J. Lu <hongjiu.lu@intel.com> 2018-04-05 H.J. Lu <hongjiu.lu@intel.com>
PR gas/22318 PR gas/22318

View File

@ -212,6 +212,8 @@ ppc_finish (void)
{ {
if (params.ppc476_workaround) if (params.ppc476_workaround)
lang_for_each_statement (no_zero_padding); lang_for_each_statement (no_zero_padding);
if (!ppc_finish_symbols (&link_info))
einfo (_("%X%P: ppc_finish_symbols problem %E\n"));
finish_default (); finish_default ();
} }