]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf64-ppc.c
PR 21412, get_reloc_section assumes .rel/.rela name for SHT_REL/RELA.
[thirdparty/binutils-gdb.git] / bfd / elf64-ppc.c
index 84cb2140872381c8a7383edf470a8ad0aa99b9ef..2e8f338748b0dd551c2d2e505d9ec6708219bf9d 100644 (file)
@@ -121,6 +121,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_special_sections         ppc64_elf_special_sections
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
 #define elf_backend_merge_symbol             ppc64_elf_merge_symbol
+#define elf_backend_get_reloc_section        bfd_get_section_by_name
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -2499,7 +2500,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
-ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
                         Elf_Internal_Rela *dst)
 {
   unsigned int type;
@@ -3188,7 +3189,7 @@ compare_symbols (const void *ap, const void *bp)
   if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
     return 1;
 
-  return 0;
+  return a > b;
 }
 
 /* Search SYMS for a symbol of the given VALUE.  */
@@ -4105,6 +4106,11 @@ struct ppc_link_hash_table
   /* Whether func_desc_adjust needs to be run over symbols.  */
   unsigned int need_func_desc_adj:1;
 
+  /* Whether there exist local gnu indirect function resolvers,
+     referenced by dynamic relocations.  */
+  unsigned int local_ifunc_resolver:1;
+  unsigned int maybe_local_ifunc_resolver:1;
+
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
@@ -4278,7 +4284,7 @@ static hashval_t
 tocsave_htab_hash (const void *p)
 {
   const struct tocsave_entry *e = (const struct tocsave_entry *) p;
-  return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
+  return ((bfd_vma) (intptr_t) e->sec ^ e->offset) >> 3;
 }
 
 static int
@@ -6590,7 +6596,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h = NULL;
-      struct plt_entry **plt_list;
+      struct plt_entry **plt_list = NULL;
       unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -6669,6 +6675,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            if (ent->got.refcount > 0)
              ent->got.refcount -= 1;
          }
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
+           plt_list = &h->plt.plist;
          break;
 
        case R_PPC64_PLT16_HA:
@@ -6680,7 +6688,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
-         plt_list = NULL;
          if (h != NULL)
            plt_list = &h->plt.plist;
          else if (local_got_ents != NULL)
@@ -6692,21 +6699,39 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
              if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
                plt_list = local_plt + r_symndx;
            }
-         if (plt_list)
-           {
-             struct plt_entry *ent;
+         break;
 
-             for (ent = *plt_list; ent != NULL; ent = ent->next)
-               if (ent->addend == rel->r_addend)
-                 break;
-             if (ent != NULL && ent->plt.refcount > 0)
-               ent->plt.refcount -= 1;
-           }
+       case R_PPC64_ADDR64:
+       case R_PPC64_ADDR16:
+       case R_PPC64_ADDR16_DS:
+       case R_PPC64_ADDR16_HA:
+       case R_PPC64_ADDR16_HI:
+       case R_PPC64_ADDR16_HIGH:
+       case R_PPC64_ADDR16_HIGHA:
+       case R_PPC64_ADDR16_HIGHER:
+       case R_PPC64_ADDR16_HIGHERA:
+       case R_PPC64_ADDR16_HIGHEST:
+       case R_PPC64_ADDR16_HIGHESTA:
+       case R_PPC64_ADDR16_LO:
+       case R_PPC64_ADDR16_LO_DS:
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
+             && rel->r_addend == 0)
+           plt_list = &h->plt.plist;
          break;
 
        default:
          break;
        }
+      if (plt_list != NULL)
+       {
+         struct plt_entry *ent;
+
+         for (ent = *plt_list; ent != NULL; ent = ent->next)
+           if (ent->addend == rel->r_addend)
+             break;
+         if (ent != NULL && ent->plt.refcount > 0)
+           ent->plt.refcount -= 1;
+       }
     }
   return TRUE;
 }
@@ -7627,7 +7652,7 @@ tocsave_find (struct ppc_link_hash_table *htab,
   if (ent.sec == NULL || ent.sec->output_section == NULL)
     {
       _bfd_error_handler
-       (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
+       (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd);
       return NULL;
     }
 
@@ -9671,6 +9696,7 @@ ensure_undefweak_dynamic (struct bfd_link_info *info,
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   if (htab->dynamic_sections_created
+      && info->dynamic_undefined_weak != 0
       && h->root.type == bfd_link_hash_undefweak
       && h->dynindx == -1
       && !h->forced_local
@@ -9761,10 +9787,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        allocate_got (h, info, gent);
       }
 
+  /* If no dynamic sections we can't have dynamic relocs, except for
+     IFUNCs which are handled even in static executables.  */
   if (!htab->elf.dynamic_sections_created
       && h->type != STT_GNU_IFUNC)
     eh->dyn_relocs = NULL;
 
+  /* Also discard relocs on undefined weak syms with non-default
+     visibility, or when dynamic_undefined_weak says so.  */
+  else if (h->root.type == bfd_link_hash_undefweak
+          && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+              || info->dynamic_undefined_weak == 0))
+    eh->dyn_relocs = NULL;
+
   if (eh->dyn_relocs != NULL)
     {
       struct elf_dyn_relocs *p, **pp;
@@ -9797,17 +9832,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                }
            }
 
-         /* Also discard relocs on undefined weak syms with
-            non-default visibility.  */
-         if (eh->dyn_relocs != NULL
-             && h->root.type == bfd_link_hash_undefweak)
+         if (eh->dyn_relocs != NULL)
            {
-             if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-               eh->dyn_relocs = NULL;
-
              /* Make sure this symbol is output as a dynamic symbol.
                 Undefined weak syms won't yet be marked as dynamic.  */
-             else if (!ensure_undefweak_dynamic (info, h))
+             if (!ensure_undefweak_dynamic (info, h))
                return FALSE;
            }
        }
@@ -11164,6 +11193,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                   * sizeof (Elf64_External_Rela)));
          bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
          stub_entry->plt_ent->plt.offset |= 1;
+         htab->local_ifunc_resolver = 1;
        }
 
       off = (dest
@@ -14295,7 +14325,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              addend = 0;
              reloc_dest = DEST_STUB;
 
-             if ((stub_entry->stub_type == ppc_stub_plt_call
+             if ((stub_entry->stub_type == ppc_stub_plt_call
                   || stub_entry->stub_type == ppc_stub_plt_call_r2save)
                  && (ALWAYS_EMIT_R2SAVE
                      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
@@ -14485,7 +14515,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                         ? h->elf.type == STT_GNU_IFUNC
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if (ifunc)
-                 relgot = htab->elf.irelplt;
+                 {
+                   relgot = htab->elf.irelplt;
+                   if (indx == 0)
+                     htab->local_ifunc_resolver = 1;
+                   else if (is_static_defined (&h->elf))
+                     htab->maybe_local_ifunc_resolver = 1;
+                 }
                else if (indx != 0
                         || (bfd_link_pic (info)
                             && (h == NULL
@@ -14804,8 +14840,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            break;
 
          if (bfd_link_pic (info)
-             ? ((h != NULL && pc_dynrelocs (h))
-                || must_be_dyn_reloc (info, r_type))
+             ? ((h == NULL
+                 || h->dyn_relocs != NULL)
+                && ((h != NULL && pc_dynrelocs (h))
+                    || must_be_dyn_reloc (info, r_type)))
              : (h != NULL
                 ? h->dyn_relocs != NULL
                 : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
@@ -14813,6 +14851,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              bfd_boolean skip, relocate;
              asection *sreloc;
              bfd_vma out_off;
+             long indx = 0;
 
              /* When generating a dynamic object, these relocations
                 are copied into the output file to be resolved at run
@@ -14849,8 +14888,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                {
-                 BFD_ASSERT (h->elf.dynindx != -1);
-                 outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+                 indx = h->elf.dynindx;
+                 BFD_ASSERT (indx != -1);
+                 outrel.r_info = ELF64_R_INFO (indx, r_type);
                }
              else
                {
@@ -14893,8 +14933,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    }
                  else
                    {
-                     long indx = 0;
-
                      if (h != NULL
                          ? h->elf.type == STT_GNU_IFUNC
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
@@ -14949,7 +14987,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (h != NULL
                  ? h->elf.type == STT_GNU_IFUNC
                  : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-               sreloc = htab->elf.irelplt;
+               {
+                 sreloc = htab->elf.irelplt;
+                 if (indx == 0)
+                   htab->local_ifunc_resolver = 1;
+                 else if (is_static_defined (&h->elf))
+                   htab->maybe_local_ifunc_resolver = 1;
+               }
              if (sreloc == NULL)
                abort ();
 
@@ -15398,7 +15442,7 @@ static bfd_boolean
 ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h,
-                                Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+                                Elf_Internal_Sym *sym)
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
@@ -15435,6 +15479,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
            loc = (htab->elf.irelplt->contents
                   + (htab->elf.irelplt->reloc_count++
                      * sizeof (Elf64_External_Rela)));
+           htab->local_ifunc_resolver = 1;
          }
        else
          {
@@ -15446,6 +15491,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
            loc = (htab->elf.srelplt->contents
                   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
                      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+             htab->maybe_local_ifunc_resolver = 1;
          }
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
@@ -15611,6 +15658,17 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
            case DT_PLTRELSZ:
              dyn.d_un.d_val = htab->elf.srelplt->size;
              break;
+
+           case DT_TEXTREL:
+             if (htab->local_ifunc_resolver)
+               info->callbacks->einfo
+                 (_("%X%P: text relocations and GNU indirect "
+                    "functions will result in a segfault at runtime\n"));
+             else if (htab->maybe_local_ifunc_resolver)
+               info->callbacks->einfo
+                 (_("%P: warning: text relocations and GNU indirect "
+                    "functions may result in a segfault at runtime\n"));
+             continue;
            }
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);