* elf32-ppc.c (ppc_elf_check_relocs): Always add a plt ref count

for local ifunc symbols in non-pie executables, regardless of
	reloc type.  Don't specially create ifunc dyn relocs.  Tidy ifunc
	code so that it's obvious that we only do anything special for
	local ifunc syms.
	(ppc_elf_gc_sweep_hook): Adjust to suit check_relocs changes.
	(allocate_dynrelocs): Correct comment for syms defined in plt.
	Don't specially allocate ifunc dyn relocs.
	(ppc_elf_relax_section): Relax branches to ifunc plt entries too.
	(ppc_elf_relocate_section): Set "relocation" value for ifunc
	syms in non-pie executables.  No specially allocated dyn relocs
	for ifunc to write.  Allow for local sym on R_PPC_RELAX32_PLT.
	(ppc_elf_finish_dynamic_symbol): Set value of ifunc symbols in
	a non-pie executable.
This commit is contained in:
Alan Modra 2009-08-03 10:23:18 +00:00
parent 0329406f62
commit de972ffadd
2 changed files with 160 additions and 112 deletions

View File

@ -1,3 +1,20 @@
2009-08-03 Alan Modra <amodra@bigpond.net.au>
* elf32-ppc.c (ppc_elf_check_relocs): Always add a plt ref count
for local ifunc symbols in non-pie executables, regardless of
reloc type. Don't specially create ifunc dyn relocs. Tidy ifunc
code so that it's obvious that we only do anything special for
local ifunc syms.
(ppc_elf_gc_sweep_hook): Adjust to suit check_relocs changes.
(allocate_dynrelocs): Correct comment for syms defined in plt.
Don't specially allocate ifunc dyn relocs.
(ppc_elf_relax_section): Relax branches to ifunc plt entries too.
(ppc_elf_relocate_section): Set "relocation" value for ifunc
syms in non-pie executables. No specially allocated dyn relocs
for ifunc to write. Allow for local sym on R_PPC_RELAX32_PLT.
(ppc_elf_finish_dynamic_symbol): Set value of ifunc symbols in
a non-pie executable.
2009-08-02 H.J. Lu <hongjiu.lu@intel.com>
Jakub Jelinek <jakub@redhat.com>

View File

@ -3458,15 +3458,13 @@ ppc_elf_check_relocs (bfd *abfd,
tls_type = 0;
ifunc = NULL;
r_type = ELF32_R_TYPE (rel->r_info);
if (!htab->is_vxworks)
{
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
{
h->needs_plt = 1;
ifunc = &h->plt.plist;
}
ifunc = &h->plt.plist;
}
else
{
@ -3475,46 +3473,47 @@ ppc_elf_check_relocs (bfd *abfd,
if (isym == NULL)
return FALSE;
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
&& (!info->shared
|| is_branch_reloc (r_type)))
{
bfd_vma addend;
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
PLT_IFUNC);
if (ifunc == NULL)
return FALSE;
/* STT_GNU_IFUNC symbols must have a PLT entry;
In a non-pie executable even when there are
no plt calls. */
addend = 0;
if (r_type == R_PPC_PLTREL24)
{
ppc_elf_tdata (abfd)->makes_plt_call = 1;
addend = rel->r_addend;
}
if (!update_plt_info (abfd, ifunc,
addend < 32768 ? NULL : got2, addend))
return FALSE;
}
}
}
r_type = ELF32_R_TYPE (rel->r_info);
if (!htab->is_vxworks && is_branch_reloc (r_type))
if (!htab->is_vxworks
&& is_branch_reloc (r_type)
&& h != NULL
&& h == tga)
{
if (h != NULL && h == tga)
{
if (rel != relocs
&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
|| ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
/* We have a new-style __tls_get_addr call with a marker
reloc. */
;
else
/* Mark this section as having an old-style call. */
sec->has_tls_get_addr_call = 1;
}
/* STT_GNU_IFUNC symbols must have a PLT entry. */
if (ifunc != NULL)
{
bfd_vma addend = 0;
if (r_type == R_PPC_PLTREL24)
{
ppc_elf_tdata (abfd)->makes_plt_call = 1;
addend = rel->r_addend;
}
if (!update_plt_info (abfd, ifunc,
addend < 32768 ? NULL : got2, addend))
return FALSE;
}
if (rel != relocs
&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
|| ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
/* We have a new-style __tls_get_addr call with a marker
reloc. */
;
else
/* Mark this section as having an old-style call. */
sec->has_tls_get_addr_call = 1;
}
switch (r_type)
@ -3690,7 +3689,7 @@ ppc_elf_check_relocs (bfd *abfd,
break;
case R_PPC_PLTREL24:
if (h == NULL || ifunc != NULL)
if (h == NULL)
break;
/* Fall through */
case R_PPC_PLT32:
@ -3903,8 +3902,7 @@ ppc_elf_check_relocs (bfd *abfd,
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
h->needs_plt = 1;
if (ifunc == NULL
&& !update_plt_info (abfd, &h->plt.plist, NULL, 0))
if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
return FALSE;
break;
}
@ -3941,9 +3939,7 @@ ppc_elf_check_relocs (bfd *abfd,
&& !info->shared
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular))
|| (!info->shared
&& ifunc != NULL))
|| !h->def_regular)))
{
struct ppc_elf_dyn_relocs *p;
struct ppc_elf_dyn_relocs **head;
@ -4415,25 +4411,19 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
}
r_type = ELF32_R_TYPE (rel->r_info);
if (!htab->is_vxworks && is_branch_reloc (r_type))
if (!htab->is_vxworks
&& h == NULL
&& local_got_refcounts != NULL
&& (!info->shared
|| is_branch_reloc (r_type)))
{
struct plt_entry **ifunc = NULL;
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
ifunc = &h->plt.plist;
}
else if (local_got_refcounts != NULL)
{
struct plt_entry **local_plt = (struct plt_entry **)
(local_got_refcounts + symtab_hdr->sh_info);
char *local_got_tls_masks = (char *)
(local_plt + symtab_hdr->sh_info);
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
ifunc = local_plt + r_symndx;
}
if (ifunc != NULL)
struct plt_entry **local_plt = (struct plt_entry **)
(local_got_refcounts + symtab_hdr->sh_info);
char *local_got_tls_masks = (char *)
(local_plt + symtab_hdr->sh_info);
if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
{
struct plt_entry **ifunc = local_plt + r_symndx;
bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
struct plt_entry *ent = find_plt_ent (ifunc, got2, addend);
if (ent->plt.refcount > 0)
@ -5166,8 +5156,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
/* If this symbol is not defined in a regular
file, and we are not generating a shared
library, then set the symbol to this location
in the .plt. This is required to make
library, then set the symbol to this location
in the .plt. This is to avoid text
relocations, and is required to make
function pointers compare as equal between
the normal executable and the shared library. */
if (! info->shared
@ -5313,8 +5304,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
eh->elf.got.offset = (bfd_vma) -1;
if (eh->dyn_relocs == NULL
|| (!htab->elf.dynamic_sections_created
&& h->type != STT_GNU_IFUNC))
|| !htab->elf.dynamic_sections_created)
return TRUE;
/* In the shared -Bsymbolic case, discard space allocated for
@ -5385,11 +5375,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
}
}
else if (h->type == STT_GNU_IFUNC)
{
if (!h->non_got_ref)
eh->dyn_relocs = NULL;
}
else if (ELIMINATE_COPY_RELOCS)
{
/* For the non-shared case, discard space for relocs against
@ -5938,6 +5923,7 @@ ppc_elf_relax_section (bfd *abfd,
bfd_vma max_branch_offset, val;
bfd_byte *hit_addr;
unsigned long t0;
struct elf_link_hash_entry *h;
unsigned char sym_type;
switch (r_type)
@ -5959,6 +5945,7 @@ ppc_elf_relax_section (bfd *abfd,
}
/* Get the value of the symbol referred to by the reloc. */
h = NULL;
if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
/* A local symbol. */
@ -5992,7 +5979,6 @@ ppc_elf_relax_section (bfd *abfd,
{
/* Global symbol handling. */
unsigned long indx;
struct elf_link_hash_entry *h;
indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
h = elf_sym_hashes (abfd)[indx];
@ -6003,26 +5989,6 @@ ppc_elf_relax_section (bfd *abfd,
tsec = NULL;
toff = 0;
if (r_type == R_PPC_PLTREL24
&& htab->plt != NULL)
{
struct plt_entry *ent = find_plt_ent (&h->plt.plist,
got2, irel->r_addend);
if (ent != NULL)
{
if (htab->plt_type == PLT_NEW)
{
tsec = htab->glink;
toff = ent->glink_offset;
}
else
{
tsec = htab->plt;
toff = ent->plt.offset;
}
}
}
if (tsec != NULL)
;
else if (h->root.type == bfd_link_hash_defined
@ -6043,6 +6009,46 @@ ppc_elf_relax_section (bfd *abfd,
sym_type = h->type;
}
if (is_branch_reloc (r_type))
{
struct plt_entry **plist = NULL;
if (h != NULL)
plist = &h->plt.plist;
else if (sym_type == STT_GNU_IFUNC)
{
bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
struct plt_entry **local_plt = (struct plt_entry **)
(local_got_offsets + symtab_hdr->sh_info);
plist = local_plt + ELF32_R_SYM (irel->r_info);
}
if (plist != NULL)
{
bfd_vma addend = 0;
struct plt_entry *ent;
if (r_type == R_PPC_PLTREL24)
addend = irel->r_addend;
ent = find_plt_ent (plist, got2, addend);
if (ent != NULL)
{
if (htab->plt_type == PLT_NEW
|| h == NULL
|| !htab->elf.dynamic_sections_created
|| h->dynindx == -1)
{
tsec = htab->glink;
toff = ent->glink_offset;
}
else
{
tsec = htab->plt;
toff = ent->plt.offset;
}
}
}
}
/* If the branch and target are in the same section, you have
no hope of adding stubs. We'll error out later should the
branch overflow. */
@ -6940,25 +6946,35 @@ ppc_elf_relocate_section (bfd *output_bfd,
ifunc = NULL;
if (!htab->is_vxworks)
{
struct plt_entry *ent;
if (h != NULL)
{
if (h->type == STT_GNU_IFUNC)
ifunc = &h->plt.plist;
}
else if (local_got_offsets != NULL)
else if (local_got_offsets != NULL
&& ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
struct plt_entry **local_plt = (struct plt_entry **)
(local_got_offsets + symtab_hdr->sh_info);
struct plt_entry **local_plt;
ifunc = local_plt + r_symndx;
}
local_plt = (struct plt_entry **) (local_got_offsets
+ symtab_hdr->sh_info);
ifunc = local_plt + r_symndx;
}
if (ifunc != NULL && is_branch_reloc (r_type))
{
struct plt_entry *ent = find_plt_ent (ifunc, got2, rel->r_addend);
ent = NULL;
if (ifunc != NULL
&& (!info->shared
|| is_branch_reloc (r_type)))
{
addend = 0;
if (r_type == R_PPC_PLTREL24)
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
}
if (ent != NULL)
{
if (h == NULL && (ent->plt.offset & 1) == 0)
{
Elf_Internal_Rela rela;
@ -7385,9 +7401,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
&& !h->def_regular)
|| (!info->shared
&& ifunc != NULL))
&& !h->def_regular))
{
int skip;
@ -7526,18 +7540,19 @@ ppc_elf_relocate_section (bfd *output_bfd,
case R_PPC_RELAX32PC_PLT:
case R_PPC_RELAX32_PLT:
{
struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, addend);
if (htab->plt_type == PLT_NEW)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ ent->glink_offset);
else
relocation = (htab->plt->output_section->vma
+ htab->plt->output_offset
+ ent->plt.offset);
}
if (h != NULL)
{
struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
addend);
if (htab->plt_type == PLT_NEW)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ ent->glink_offset);
else
relocation = (htab->plt->output_section->vma
+ htab->plt->output_offset
+ ent->plt.offset);
}
if (r_type == R_PPC_RELAX32_PLT)
goto relax32;
/* Fall thru */
@ -8164,6 +8179,22 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
}
else if (h->type == STT_GNU_IFUNC
&& !info->shared)
{
/* Set the value of ifunc symbols in a non-pie
executable to the glink entry. This is to avoid
text relocations. We can't do this for ifunc in
allocate_dynrelocs, as we do for normal dynamic
function symbols with plt entries, because we need
to keep the original value around for the ifunc
relocation. */
sym->st_shndx = (_bfd_elf_section_from_bfd_section
(output_bfd, htab->glink->output_section));
sym->st_value = (ent->glink_offset +
htab->glink->output_offset
+ htab->glink->output_section->vma);
}
doneone = TRUE;
}