Error on shared lib call to @local ifunc

On powerpc32, making ifuncs have non-default visibility in shared
libraries or pies can result in runtime failures.  The problem is that
if gcc is told that a given function has non-default visibility, then
calls to that function are assumed to be local (which is true) and
thus need not go via a plt call stub (which is false for ifunc).  If
the caller has no other reason to set up the got pointer (r30), code
won't be emitted to do so.  However, a pic plt call stub makes use of
r30 to load the plt entry.  So a call to an ifunc, which always needs
a plt entry, will fail.

This patch makes ld emit an error for the problem case, and allows
calls to non-default visibility ifuncs to work in normal executables.
I also fix some cases where ifuncs fail when using the old bss-plt.

	* elf32-ppc.c (ppc_elf_check_relocs): For @local call to ifunc,
	error when shared and force a plt call otherwise.
	(ppc_elf_size_dynamic_sections): Don't emit DT_PPC_GOT unless
	plt_type == PLT_NEW.
	(ppc_elf_relocate_section): Add missing test to resolve ifuncs to
	the appropriate call stub.
This commit is contained in:
Alan Modra 2014-01-13 13:51:16 +10:30
parent 1a4416c4c7
commit c7e17e05b6
1 changed files with 19 additions and 2 deletions

View File

@ -4283,6 +4283,20 @@ ppc_elf_check_relocs (bfd *abfd,
htab->plt_type = PLT_OLD;
htab->old_bfd = abfd;
}
if (h != NULL && h->type == STT_GNU_IFUNC)
{
if (info->shared)
{
info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
abfd, sec, rel->r_offset,
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
h->needs_plt = 1;
if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
return FALSE;
}
break;
/* This relocation describes the C++ object vtable hierarchy.
@ -6481,7 +6495,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return FALSE;
}
if (htab->glink != NULL && htab->glink->size != 0)
if (htab->plt_type == PLT_NEW
&& htab->glink != NULL
&& htab->glink->size != 0)
{
if (!add_dynamic_entry (DT_PPC_GOT, 0))
return FALSE;
@ -7863,7 +7879,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
unresolved_reloc = FALSE;
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
|| h == NULL)
|| h == NULL
|| h->dynindx == -1)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ (ent->glink_offset & ~1));