aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-01-13 13:51:16 +1030
committerAlan Modra <amodra@gmail.com>2014-01-13 15:04:15 +1030
commitc7e17e05b647f6233c2062d038e5421686217816 (patch)
tree5a76b6781f9f40342b24ddd40ffa5b1e781a7ff6 /bfd/elf32-ppc.c
parent1a4416c4c7f02a73652429f4e8e8e966f55e3e8b (diff)
downloadgdb-c7e17e05b647f6233c2062d038e5421686217816.zip
gdb-c7e17e05b647f6233c2062d038e5421686217816.tar.gz
gdb-c7e17e05b647f6233c2062d038e5421686217816.tar.bz2
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.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r--bfd/elf32-ppc.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index b601f05..61c45d8 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -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));