Error on unsupported PowerPC ifuncs
authorAlan Modra <amodra@gmail.com>
Mon, 22 Aug 2016 01:12:26 +0000 (10:42 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 22 Aug 2016 01:25:08 +0000 (10:55 +0930)
The pr19784 tests fail on ppc32 due to a gcc bug.  The failure should
be noticed when building both libpr19784a.so and libpr19784b.so,
rather than ld building a buggy libpr19784a.so that fails at run time.
This patch fixes that by moving the @local ifunc check out of
check_relocs, where a call destination may not yet be known to be
ifunc.  The patch also adds a related error for -mbss-plt code.

* elf32-ppc.c (ppc_elf_check_relocs): Move error for @local ifunc..
(ppc_elf_relocate_section): ..to here.  Comment.  Error on
detecting -mbss-plt -fPIC local ifuncs too.
(ppc_elf_size_dynamic_sections): Comment on unnecessary glink
branch table entries.

bfd/ChangeLog
bfd/elf32-ppc.c

index ea810cd..b588fae 100644 (file)
@@ -1,3 +1,11 @@
+2016-08-22  Alan Modra  <amodra@gmail.com>
+
+       * elf32-ppc.c (ppc_elf_check_relocs): Move error for @local ifunc..
+       (ppc_elf_relocate_section): ..to here.  Comment.  Error on
+       detecting -mbss-plt -fPIC local ifuncs too.
+       (ppc_elf_size_dynamic_sections): Comment on unnecessary glink
+       branch table entries.
+
 2016-08-19  Nick Clifton  <nickc@redhat.com>
 
        * elf.c (assign_section_numbers): Assign number for the .shstrtab
index 8d5131a..92299bc 100644 (file)
@@ -4390,15 +4390,6 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
-             if (bfd_link_pic (info))
-               {
-                 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;
@@ -6504,7 +6495,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       && htab->elf.dynamic_sections_created)
     {
       htab->glink_pltresolve = htab->glink->size;
-      /* Space for the branch table.  */
+      /* Space for the branch table.  ??? We don't need entries for
+        non-dynamic symbols in this table.  This case can arise with
+        static ifuncs or forced local ifuncs.  */
       htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
       /* Pad out to align the start of PLTresolve.  */
       htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
@@ -8308,6 +8301,26 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          if (ent != NULL)
            {
+             if (bfd_link_pic (info)
+                 && ent->sec != got2
+                 && htab->plt_type != PLT_NEW
+                 && (!htab->elf.dynamic_sections_created
+                     || h == NULL
+                     || h->dynindx == -1))
+               {
+                 /* Uh oh, we are going to create a pic glink stub
+                    for an ifunc (here for h == NULL and later in
+                    finish_dynamic_symbol for h != NULL), and
+                    apparently are using code compiled with
+                    -mbss-plt.  The difficulty is that -mbss-plt code
+                    gives no indication via a magic PLTREL24 addend
+                    whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or
+                    is pointing into a .got2 section (and how far
+                    into .got2).  */
+                   info->callbacks->einfo
+                     (_("%X%P: %H: unsupported bss-plt -fPIC ifunc %s\n"),
+                      input_bfd, input_section, rel->r_offset, sym_name);
+               }
              if (h == NULL && (ent->plt.offset & 1) == 0)
                {
                  Elf_Internal_Rela rela;
@@ -8656,6 +8669,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                                    TRUE);
              goto copy_reloc;
            }
+         if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info))
+           {
+             /* @local on an ifunc does not really make sense since
+                the ifunc resolver can take you anywhere.  More
+                seriously, calls to ifuncs must go through a plt call
+                stub, and for pic the plt call stubs uses r30 to
+                access the PLT.  The problem is that a call that is
+                local won't have the +32k reloc addend trick marking
+                -fPIC code, so the linker won't know whether r30 is
+                _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section.  */
+             info->callbacks->einfo (_("%X%P: %H: @local call to ifunc %s\n"),
+                                     input_bfd, input_section, rel->r_offset,
+                                     h->root.root.string);
+           }
          break;
 
        case R_PPC_DTPREL16: