SPARC: fix PR ld/18841
authorEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 7 Feb 2019 16:04:31 +0000 (17:04 +0100)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 7 Feb 2019 16:04:31 +0000 (17:04 +0100)
This fixes the last ld failures on SPARC64/Linux:

FAIL: Run pr18841 with libpr18841b.so
FAIL: Run pr18841 with libpr18841c.so
FAIL: Run pr18841 with libpr18841bn.so (-z now)
FAIL: Run pr18841 with libpr18841cn.so (-z now)

by mimicing what has been done on x86-64 and Aarch64 to fix the PR.

bfd/
PR ld/18841
        * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
        reloc_class_ifunc for ifunc symbols.
        * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.

bfd/ChangeLog
bfd/elf32-sparc.c
bfd/elf64-sparc.c

index c0a3a37..9656c50 100644 (file)
@@ -1,5 +1,12 @@
 2019-02-07  Eric Botcazou  <ebotcazou@adacore.com>
 
+       PR ld/18841
+       * elf32-sparc.c (elf32_sparc_reloc_type_class): Return
+       reloc_class_ifunc for ifunc symbols.
+       * elf64-sparc.c (elf64_sparc_reloc_type_class): Likewise.
+
+2019-02-07  Eric Botcazou  <ebotcazou@adacore.com>
+
        * elf32-visium.c (visium_elf_howto_parity_reloc): Minor tweak.
        <R_VISIUM_PC16>: Use explicit range test to detect an overflow.
 
index 1873b1a..f5c5863 100644 (file)
@@ -157,13 +157,44 @@ elf32_sparc_final_write_processing (bfd *abfd,
     }
 }
 
+/* Used to decide how to sort relocs in an optimal manner for the
+   dynamic linker, before writing them out.  */
+
 static enum elf_reloc_type_class
-elf32_sparc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf32_sparc_reloc_type_class (const struct bfd_link_info *info,
                              const asection *rel_sec ATTRIBUTE_UNUSED,
                              const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct _bfd_sparc_elf_link_hash_table *htab
+    = _bfd_sparc_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (htab->elf.dynsym != NULL
+      && htab->elf.dynsym->contents != NULL)
+    {
+      /* Check relocation against STT_GNU_IFUNC symbol if there are
+        dynamic symbols.  */
+      unsigned long r_symndx = htab->r_symndx (rela->r_info);
+      if (r_symndx != STN_UNDEF)
+       {
+         Elf_Internal_Sym sym;
+         if (!bed->s->swap_symbol_in (abfd,
+                                      (htab->elf.dynsym->contents
+                                       + r_symndx * bed->s->sizeof_sym),
+                                      0, &sym))
+           abort ();
+
+         if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+           return reloc_class_ifunc;
+       }
+    }
+
   switch ((int) ELF32_R_TYPE (rela->r_info))
     {
+    case R_SPARC_IRELATIVE:
+      return reloc_class_ifunc;
     case R_SPARC_RELATIVE:
       return reloc_class_relative;
     case R_SPARC_JMP_SLOT:
index 7de32c9..bd29be3 100644 (file)
@@ -769,13 +769,44 @@ elf64_sparc_print_symbol_all (bfd *abfd ATTRIBUTE_UNUSED, void * filep,
     return symbol->name;
 }
 \f
+/* Used to decide how to sort relocs in an optimal manner for the
+   dynamic linker, before writing them out.  */
+
 static enum elf_reloc_type_class
-elf64_sparc_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+elf64_sparc_reloc_type_class (const struct bfd_link_info *info,
                              const asection *rel_sec ATTRIBUTE_UNUSED,
                              const Elf_Internal_Rela *rela)
 {
+  bfd *abfd = info->output_bfd;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  struct _bfd_sparc_elf_link_hash_table *htab
+    = _bfd_sparc_elf_hash_table (info);
+  BFD_ASSERT (htab != NULL);
+
+  if (htab->elf.dynsym != NULL
+      && htab->elf.dynsym->contents != NULL)
+    {
+      /* Check relocation against STT_GNU_IFUNC symbol if there are
+        dynamic symbols.  */
+      unsigned long r_symndx = htab->r_symndx (rela->r_info);
+      if (r_symndx != STN_UNDEF)
+       {
+         Elf_Internal_Sym sym;
+         if (!bed->s->swap_symbol_in (abfd,
+                                      (htab->elf.dynsym->contents
+                                       + r_symndx * bed->s->sizeof_sym),
+                                      0, &sym))
+           abort ();
+
+         if (ELF_ST_TYPE (sym.st_info) == STT_GNU_IFUNC)
+           return reloc_class_ifunc;
+       }
+    }
+
   switch ((int) ELF64_R_TYPE (rela->r_info))
     {
+    case R_SPARC_IRELATIVE:
+      return reloc_class_ifunc;
     case R_SPARC_RELATIVE:
       return reloc_class_relative;
     case R_SPARC_JMP_SLOT: