Error on shared lib call to @local ifunc
authorAlan Modra <amodra@gmail.com>
Mon, 13 Jan 2014 03:21:16 +0000 (13:51 +1030)
committerAlan Modra <amodra@gmail.com>
Mon, 13 Jan 2014 04:34:15 +0000 (15:04 +1030)
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.

bfd/elf32-ppc.c

index b601f05eee623bd5bab94c7c5b0c47877c2c69f7..61c45d8437ae4d0e012a77e97002c6342ec6ba7e 100644 (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));