ELF: Don't set non_ir_ref_regular in check_relocs
[binutils-gdb.git] / bfd / elf32-ppc.c
index e71757eab0ff2f533cecf5528c501e9b3b04fcd6..89069715191bec13fb6eb8d4a1984967f647ef58 100644 (file)
@@ -134,7 +134,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 #define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3
 /* The number of relocations in the PLTResolve slot. */
 #define VXWORKS_PLTRESOLVE_RELOCS 2
-/* The number of relocations in the PLTResolve slot when when creating
+/* The number of relocations in the PLTResolve slot when creating
    a shared library. */
 #define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0
 
@@ -1656,6 +1656,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0x3e007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* e_li split20 format.  */
+  HOWTO (R_PPC_VLE_ADDR20,     /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        20,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC_VLE_ADDR20",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1f07ff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   HOWTO (R_PPC_IRELATIVE,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -1746,6 +1761,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0x1fffc1,              /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* A split-field reloc for addpcis, non-relative (gas internal use only).  */
+  HOWTO (R_PPC_16DX_HA,                /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc_elf_addr16_ha_reloc, /* special_function */
+        "R_PPC_16DX_HA",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1fffc1,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1791,56 +1821,6 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 };
-
-/* External 32-bit PPC structure for PRPSINFO.  This structure is
-   ABI-defined, thus we choose to use char arrays here in order to
-   avoid dealing with different types in different architectures.
-
-   The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while
-   most non-PPC architectures use `short int'.
-
-   This structure will ultimately be written in the corefile's note
-   section, as the PRPSINFO.  */
-
-struct elf_external_ppc_linux_prpsinfo32
-  {
-    char pr_state;                     /* Numeric process state.  */
-    char pr_sname;                     /* Char for pr_state.  */
-    char pr_zomb;                      /* Zombie.  */
-    char pr_nice;                      /* Nice val.  */
-    char pr_flag[4];                   /* Flags.  */
-    char pr_uid[4];
-    char pr_gid[4];
-    char pr_pid[4];
-    char pr_ppid[4];
-    char pr_pgrp[4];
-    char pr_sid[4];
-    char pr_fname[16];                 /* Filename of executable.  */
-    char pr_psargs[80];                        /* Initial part of arg list.  */
-  };
-
-/* Helper function to copy an elf_internal_linux_prpsinfo in host
-   endian to an elf_external_ppc_linux_prpsinfo32 in target endian.  */
-
-static inline void
-swap_ppc_linux_prpsinfo32_out (bfd *obfd,
-                              const struct elf_internal_linux_prpsinfo *from,
-                              struct elf_external_ppc_linux_prpsinfo32 *to)
-{
-  bfd_put_8 (obfd, from->pr_state, &to->pr_state);
-  bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
-  bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
-  bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
-  bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
-  bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
-  bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
-  bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
-  bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
-  bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
-  bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
-  strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
-  strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
-}
 \f
 /* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */
 
@@ -2002,6 +1982,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_LO16_PCREL:         r = R_PPC_REL16_LO;             break;
     case BFD_RELOC_HI16_PCREL:         r = R_PPC_REL16_HI;             break;
     case BFD_RELOC_HI16_S_PCREL:       r = R_PPC_REL16_HA;             break;
+    case BFD_RELOC_PPC_16DX_HA:                r = R_PPC_16DX_HA;              break;
     case BFD_RELOC_PPC_REL16DX_HA:     r = R_PPC_REL16DX_HA;           break;
     case BFD_RELOC_VTABLE_INHERIT:     r = R_PPC_GNU_VTINHERIT;        break;
     case BFD_RELOC_VTABLE_ENTRY:       r = R_PPC_GNU_VTENTRY;          break;
@@ -2029,7 +2010,7 @@ ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
-ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
+ppc_elf_info_to_howto (bfd *abfd,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
@@ -2066,10 +2047,10 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
 /* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs.  */
 
 static bfd_reloc_status_type
-ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ppc_elf_addr16_ha_reloc (bfd *abfd,
                         arelent *reloc_entry,
                         asymbol *symbol,
-                        void *data ATTRIBUTE_UNUSED,
+                        void *data,
                         asection *input_section,
                         bfd *output_bfd,
                         char **error_message ATTRIBUTE_UNUSED)
@@ -2377,20 +2358,6 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   return TRUE;
 }
 
-char *
-elfcore_write_ppc_linux_prpsinfo32
-  (bfd *abfd,
-   char *buf,
-   int *bufsiz,
-   const struct elf_internal_linux_prpsinfo *prpsinfo)
-{
-  struct elf_external_ppc_linux_prpsinfo32 data;
-
-  swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
-  return elfcore_write_note (abfd, buf, bufsiz,
-                            "CORE", NT_PRPSINFO, &data, sizeof (data));
-}
-
 static char *
 ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
 {
@@ -2593,7 +2560,7 @@ ppc_elf_modify_segment_map (bfd *abfd,
       amt += (m->count - j - 1) * sizeof (asection *);
       n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
       if (n == NULL)
-        return FALSE;
+       return FALSE;
 
       n->p_type = PT_LOAD;
       n->count = m->count - j;
@@ -2632,7 +2599,7 @@ static struct bfd_elf_special_section ppc_alt_plt =
   { STRING_COMMA_LEN (".plt"),             0, SHT_PROGBITS, SHF_ALLOC };
 
 static const struct bfd_elf_special_section *
-ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_get_sec_type_attr (bfd *abfd, asection *sec)
 {
   const struct bfd_elf_special_section *ssect;
 
@@ -2833,7 +2800,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
     free (buffer);
 
   if (error_message)
-    _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
+    _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd);
 }
 
 /* Prevent the output section from accumulating the input sections'
@@ -3176,9 +3143,9 @@ struct plt_entry
   bfd_vma glink_offset;
 };
 
-/* Of those relocs that might be copied as dynamic relocs, this function
-   selects those that must be copied when linking a shared library,
-   even when the symbol is local.  */
+/* Of those relocs that might be copied as dynamic relocs, this
+   function selects those that must be copied when linking a shared
+   library or PIE, even when the symbol is local.  */
 
 static int
 must_be_dyn_reloc (struct bfd_link_info *info,
@@ -3187,6 +3154,10 @@ must_be_dyn_reloc (struct bfd_link_info *info,
   switch (r_type)
     {
     default:
+      /* Only relative relocs can be resolved when the object load
+        address isn't fixed.  DTPREL32 is excluded because the
+        dynamic linker needs to differentiate global dynamic from
+        local dynamic __tls_index pairs when PPC_OPT_TLS is set.  */
       return 1;
 
     case R_PPC_REL24:
@@ -3201,7 +3172,9 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC_TPREL16_LO:
     case R_PPC_TPREL16_HI:
     case R_PPC_TPREL16_HA:
-      return !bfd_link_executable (info);
+      /* These relocations are relative but in a shared library the
+        linker doesn't know the thread pointer base.  */
+      return bfd_link_dll (info);
     }
 }
 
@@ -3311,6 +3284,14 @@ struct ppc_elf_link_hash_table
   /* True if the target system is VxWorks.  */
   unsigned int is_vxworks: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;
+
+  /* Set if tls optimization is enabled.  */
+  unsigned int do_tls_opt:1;
+
   /* The size of PLT entries.  */
   int plt_entry_size;
   /* The distance between adjacent PLT slots.  */
@@ -3613,6 +3594,10 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
   edir->elf.needs_plt |= eind->elf.needs_plt;
   edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
 
+  /* If we were called to copy over info for a weak sym, that's all.  */
+  if (eind->elf.root.type != bfd_link_hash_indirect)
+    return;
+
   if (eind->dyn_relocs != NULL)
     {
       if (edir->dyn_relocs != NULL)
@@ -3644,16 +3629,6 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
       eind->dyn_relocs = NULL;
     }
 
-  /* If we were called to copy over info for a weak sym, that's all.
-     You might think dyn_relocs need not be copied over;  After all,
-     both syms will be dynamic or both non-dynamic so we're just
-     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS
-     code in ppc_elf_adjust_dynamic_symbol needs to check for
-     dyn_relocs in read-only sections, and it does so on what is the
-     DIR sym here.  */
-  if (eind->elf.root.type != bfd_link_hash_indirect)
-    return;
-
   /* Copy over the GOT refcount entries that we may have already seen to
      the symbol which just became indirect.  */
   edir->elf.got.refcount += eind->elf.got.refcount;
@@ -4024,10 +3999,6 @@ ppc_elf_check_relocs (bfd *abfd,
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-         /* PR15323, ref flags aren't set for references in the same
-            object.  */
-         h->root.non_ir_ref = 1;
        }
 
       /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
@@ -4123,7 +4094,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HA:
-         if (bfd_link_pic (info))
+         if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -4231,6 +4202,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_VLE_HI16D:
        case R_PPC_VLE_HA16A:
        case R_PPC_VLE_HA16D:
+       case R_PPC_VLE_ADDR20:
          break;
 
        case R_PPC_EMB_SDA2REL:
@@ -4351,6 +4323,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_RELAX:
        case R_PPC_RELAX_PLT:
        case R_PPC_RELAX_PLTREL24:
+       case R_PPC_16DX_HA:
          break;
 
          /* These should only appear in dynamic objects.  */
@@ -4401,13 +4374,13 @@ ppc_elf_check_relocs (bfd *abfd,
            return FALSE;
          break;
 
-         /* We shouldn't really be seeing these.  */
+         /* We shouldn't really be seeing TPREL32.  */
        case R_PPC_TPREL32:
        case R_PPC_TPREL16:
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         if (bfd_link_pic (info))
+         if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
@@ -4877,9 +4850,9 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
          error = TRUE;
          _bfd_error_handler
            /* xgettext:c-format */
-           (_("%B: uses different e_flags (0x%lx) fields "
-              "than previous modules (0x%lx)"),
-            ibfd, (long) new_flags, (long) old_flags);
+           (_("%B: uses different e_flags (%#x) fields "
+              "than previous modules (%#x)"),
+            ibfd, new_flags, old_flags);
        }
 
       if (error)
@@ -4904,7 +4877,7 @@ ppc_elf_vle_split16 (bfd *input_bfd,
   unsigned int insn, opcode, top5;
 
   insn = bfd_get_32 (input_bfd, loc);
-  opcode = insn & 0xf300f800;
+  opcode = insn & 0xfc00f800;
   if (opcode == E_OR2I_INSN
       || opcode == E_AND2I_DOT_INSN
       || opcode == E_OR2IS_INSN
@@ -4948,6 +4921,23 @@ ppc_elf_vle_split16 (bfd *input_bfd,
   insn |= value & 0x7ff;
   bfd_put_32 (input_bfd, insn, loc);
 }
+
+static void
+ppc_elf_vle_split20 (bfd *output_bfd, bfd_byte *loc, bfd_vma value)
+{
+  unsigned int insn;
+
+  insn = bfd_get_32 (output_bfd, loc);
+  /* We have an li20 field, bits 17..20, 11..15, 21..31.  */
+  /* Top 4 bits of value to 17..20.  */
+  insn |= (value & 0xf0000) >> 5;
+  /* Next 5 bits of the value to 11..15.  */
+  insn |= (value & 0xf800) << 5;
+  /* And the final 11 bits of the value to bits 21 to 31.  */
+  insn |= value & 0x7ff;
+  bfd_put_32 (output_bfd, insn, loc);
+}
+
 \f
 /* Choose which PLT scheme to use, and set .plt flags appropriately.
    Returns -1 on error, 0 for old PLT, 1 for new PLT.  */
@@ -4974,8 +4964,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
                   || h->needs_plt)
               && h->ref_regular
               && !(SYMBOL_CALLS_LOCAL (info, h)
-                   || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-                       && h->root.type == bfd_link_hash_undefweak)))
+                   || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
        {
          /* Profiling of shared libs (and pies) is not supported with
             secure plt, because ppc32 does profiling before a
@@ -5065,182 +5054,6 @@ ppc_elf_gc_mark_hook (asection *sec,
 
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
-
-/* Update the got, plt and dynamic reloc reference counts for the
-   section being removed.  */
-
-static bfd_boolean
-ppc_elf_gc_sweep_hook (bfd *abfd,
-                      struct bfd_link_info *info,
-                      asection *sec,
-                      const Elf_Internal_Rela *relocs)
-{
-  struct ppc_elf_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
-  asection *got2;
-
-  if (bfd_link_relocatable (info))
-    return TRUE;
-
-  if ((sec->flags & SEC_ALLOC) == 0)
-    return TRUE;
-
-  elf_section_data (sec)->local_dynrel = NULL;
-
-  htab = ppc_elf_hash_table (info);
-  symtab_hdr = &elf_symtab_hdr (abfd);
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
-  got2 = bfd_get_section_by_name (abfd, ".got2");
-
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
-    {
-      unsigned long r_symndx;
-      enum elf_ppc_reloc_type r_type;
-      struct elf_link_hash_entry *h = NULL;
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      if (r_symndx >= symtab_hdr->sh_info)
-       {
-         struct elf_dyn_relocs **pp, *p;
-         struct ppc_elf_link_hash_entry *eh;
-
-         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
-         eh = (struct ppc_elf_link_hash_entry *) h;
-
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-           if (p->sec == sec)
-             {
-               /* Everything must go for SEC.  */
-               *pp = p->next;
-               break;
-             }
-       }
-
-      r_type = ELF32_R_TYPE (rel->r_info);
-      if (!htab->is_vxworks
-         && h == NULL
-         && local_got_refcounts != NULL
-         && (!bfd_link_pic (info)
-             || is_branch_reloc (r_type)))
-       {
-         struct plt_entry **local_plt = (struct plt_entry **)
-           (local_got_refcounts + symtab_hdr->sh_info);
-         char *local_got_tls_masks = (char *)
-           (local_plt + symtab_hdr->sh_info);
-         if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
-           {
-             struct plt_entry **ifunc = local_plt + r_symndx;
-             bfd_vma addend = 0;
-             struct plt_entry *ent;
-
-             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
-               addend = rel->r_addend;
-             ent = find_plt_ent (ifunc, got2, addend);
-             if (ent->plt.refcount > 0)
-               ent->plt.refcount -= 1;
-             continue;
-           }
-       }
-
-      switch (r_type)
-       {
-       case R_PPC_GOT_TLSLD16:
-       case R_PPC_GOT_TLSLD16_LO:
-       case R_PPC_GOT_TLSLD16_HI:
-       case R_PPC_GOT_TLSLD16_HA:
-       case R_PPC_GOT_TLSGD16:
-       case R_PPC_GOT_TLSGD16_LO:
-       case R_PPC_GOT_TLSGD16_HI:
-       case R_PPC_GOT_TLSGD16_HA:
-       case R_PPC_GOT_TPREL16:
-       case R_PPC_GOT_TPREL16_LO:
-       case R_PPC_GOT_TPREL16_HI:
-       case R_PPC_GOT_TPREL16_HA:
-       case R_PPC_GOT_DTPREL16:
-       case R_PPC_GOT_DTPREL16_LO:
-       case R_PPC_GOT_DTPREL16_HI:
-       case R_PPC_GOT_DTPREL16_HA:
-       case R_PPC_GOT16:
-       case R_PPC_GOT16_LO:
-       case R_PPC_GOT16_HI:
-       case R_PPC_GOT16_HA:
-         if (h != NULL)
-           {
-             if (h->got.refcount > 0)
-               h->got.refcount--;
-             if (!bfd_link_pic (info))
-               {
-                 struct plt_entry *ent;
-
-                 ent = find_plt_ent (&h->plt.plist, NULL, 0);
-                 if (ent != NULL && ent->plt.refcount > 0)
-                   ent->plt.refcount -= 1;
-               }
-           }
-         else if (local_got_refcounts != NULL)
-           {
-             if (local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx]--;
-           }
-         break;
-
-       case R_PPC_REL24:
-       case R_PPC_REL14:
-       case R_PPC_REL14_BRTAKEN:
-       case R_PPC_REL14_BRNTAKEN:
-       case R_PPC_REL32:
-         if (h == NULL || h == htab->elf.hgot)
-           break;
-         /* Fall through.  */
-
-       case R_PPC_ADDR32:
-       case R_PPC_ADDR24:
-       case R_PPC_ADDR16:
-       case R_PPC_ADDR16_LO:
-       case R_PPC_ADDR16_HI:
-       case R_PPC_ADDR16_HA:
-       case R_PPC_ADDR14:
-       case R_PPC_ADDR14_BRTAKEN:
-       case R_PPC_ADDR14_BRNTAKEN:
-       case R_PPC_UADDR32:
-       case R_PPC_UADDR16:
-         if (bfd_link_pic (info))
-           break;
-         /* Fall through.  */
-
-       case R_PPC_PLT32:
-       case R_PPC_PLTREL24:
-       case R_PPC_PLTREL32:
-       case R_PPC_PLT16_LO:
-       case R_PPC_PLT16_HI:
-       case R_PPC_PLT16_HA:
-         if (h != NULL)
-           {
-             bfd_vma addend = 0;
-             struct plt_entry *ent;
-
-             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
-               addend = rel->r_addend;
-             ent = find_plt_ent (&h->plt.plist, got2, addend);
-             if (ent != NULL && ent->plt.refcount > 0)
-               ent->plt.refcount -= 1;
-           }
-         break;
-
-       default:
-         break;
-       }
-    }
-  return TRUE;
-}
 \f
 /* Set plt output section type, htab->tls_get_addr, and call the
    generic ELF tls_setup function.  */
@@ -5275,8 +5088,7 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
              && (tga->type == STT_FUNC
                  || tga->needs_plt)
              && !(SYMBOL_CALLS_LOCAL (info, tga)
-                  || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
-                      && tga->root.type == bfd_link_hash_undefweak)))
+                  || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga)))
            {
              struct plt_entry *ent;
              for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
@@ -5598,12 +5410,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
              symtab_hdr->contents = (unsigned char *) locsyms;
          }
       }
+  htab->do_tls_opt = 1;
   return TRUE;
 }
 \f
-/* Return true if we have dynamic relocs that apply to read-only sections.  */
+/* Find dynamic relocs for H that apply to read-only sections.  */
 
-static bfd_boolean
+static asection *
 readonly_dynrelocs (struct elf_link_hash_entry *h)
 {
   struct elf_dyn_relocs *p;
@@ -5612,11 +5425,40 @@ readonly_dynrelocs (struct elf_link_hash_entry *h)
     {
       asection *s = p->sec->output_section;
 
-      if (s != NULL
-         && ((s->flags & (SEC_READONLY | SEC_ALLOC))
-             == (SEC_READONLY | SEC_ALLOC)))
-       return TRUE;
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+       return p->sec;
     }
+  return NULL;
+}
+
+/* Return true if we have dynamic relocs against H or any of its weak
+   aliases, that apply to read-only sections.  Cannot be used after
+   size_dynamic_sections.  */
+
+static bfd_boolean
+alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+  struct ppc_elf_link_hash_entry *eh = ppc_elf_hash_entry (h);
+  do
+    {
+      if (readonly_dynrelocs (&eh->elf))
+       return TRUE;
+      eh = ppc_elf_hash_entry (eh->elf.u.alias);
+    } while (eh != NULL && &eh->elf != h);
+
+  return FALSE;
+}
+
+/* Return whether H has pc-relative dynamic relocs.  */
+
+static bfd_boolean
+pc_dynrelocs (struct elf_link_hash_entry *h)
+{
+  struct elf_dyn_relocs *p;
+
+  for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+    if (p->pc_count != 0)
+      return TRUE;
   return FALSE;
 }
 
@@ -5643,7 +5485,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   BFD_ASSERT (htab->elf.dynobj != NULL
              && (h->needs_plt
                  || h->type == STT_GNU_IFUNC
-                 || h->u.weakdef != NULL
+                 || h->is_weakalias
                  || (h->def_dynamic
                      && h->ref_regular
                      && !h->def_regular)));
@@ -5653,6 +5495,13 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
+      bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h)
+                          || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+      /* Discard dyn_relocs when non-pic if we've decided that a
+        function symbol is local.  */
+      if (!bfd_link_pic (info) && local)
+       ppc_elf_hash_entry (h)->dyn_relocs = NULL;
+
       /* Clear procedure linkage table information for any symbol that
         won't need a .plt entry.  */
       struct plt_entry *ent;
@@ -5660,10 +5509,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || (h->type != STT_GNU_IFUNC
-             && (SYMBOL_CALLS_LOCAL (info, h)
-                 || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-                     && h->root.type == bfd_link_hash_undefweak))))
+         || (h->type != STT_GNU_IFUNC && local))
        {
          /* A PLT entry is not required/allowed when:
 
@@ -5691,19 +5537,26 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             resolution of the symbol to be set at load time rather
             than link time.  */
          if ((h->pointer_equality_needed
-              || (!h->ref_regular_nonweak && h->non_got_ref))
+              || (h->non_got_ref
+                  && !h->ref_regular_nonweak
+                  && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
              && !htab->is_vxworks
              && !ppc_elf_hash_entry (h)->has_sda_refs
              && !readonly_dynrelocs (h))
            {
              h->pointer_equality_needed = 0;
-             /* After adjust_dynamic_symbol, non_got_ref set in the
-                non-pic case means that dyn_relocs for this symbol
-                should be discarded.  */
-             h->non_got_ref = 0;
+             /* If we haven't seen a branch reloc then we don't need
+                a plt entry.  */
+             if (!h->needs_plt)
+               h->plt.plist = NULL;
            }
+         else if (!bfd_link_pic (info))
+           /* We are going to be defining the function symbol on the
+              plt stub, so no dyn_relocs needed when non-pic.  */
+           ppc_elf_hash_entry (h)->dyn_relocs = NULL;
        }
       h->protected_def = 0;
+      /* Function symbols can't have copy relocs.  */
       return TRUE;
     }
   else
@@ -5712,14 +5565,14 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   /* If this is a weak symbol, and there is a real definition, the
      processor independent code will have arranged for us to see the
      real definition first, and we can just use the same value.  */
-  if (h->u.weakdef != NULL)
+  if (h->is_weakalias)
     {
-      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
-                 || h->u.weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->u.weakdef->root.u.def.section;
-      h->root.u.def.value = h->u.weakdef->root.u.def.value;
+      struct elf_link_hash_entry *def = weakdef (h);
+      BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+      h->root.u.def.section = def->root.u.def.section;
+      h->root.u.def.value = def->root.u.def.value;
       if (ELIMINATE_COPY_RELOCS)
-       h->non_got_ref = h->u.weakdef->non_got_ref;
+       h->non_got_ref = def->non_got_ref;
       return TRUE;
     }
 
@@ -5756,16 +5609,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          && htab->params->pic_fixup == 0
          && info->disable_target_specific_optimizations <= 1)
        htab->params->pic_fixup = 1;
-      h->non_got_ref = 0;
       return TRUE;
     }
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
   if (info->nocopyreloc)
-    {
-      h->non_got_ref = 0;
-      return TRUE;
-    }
+    return TRUE;
 
    /* If we didn't find any dynamic relocs in read-only sections, then
       we'll be keeping the dynamic relocs and avoiding the copy reloc.
@@ -5777,11 +5626,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       && !ppc_elf_hash_entry (h)->has_sda_refs
       && !htab->is_vxworks
       && !h->def_regular
-      && !readonly_dynrelocs (h))
-    {
-      h->non_got_ref = 0;
-      return TRUE;
-    }
+      && !alias_readonly_dynrelocs (h))
+    return TRUE;
 
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
@@ -5823,6 +5669,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
+  /* We no longer want dyn_relocs.  */
+  ppc_elf_hash_entry (h)->dyn_relocs = NULL;
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
@@ -5916,16 +5764,57 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
   return where;
 }
 
-/* If H is undefined weak, make it dynamic if that makes sense.  */
+/* Calculate size of GOT entries for symbol given its TLS_MASK.
+   TLS_LD is excluded because those go in a special GOT slot.  */
+
+static inline unsigned int
+got_entries_needed (int tls_mask)
+{
+  unsigned int need;
+  if ((tls_mask & TLS_TLS) == 0)
+    need = 4;
+  else
+    {
+      need = 0;
+      if ((tls_mask & TLS_GD) != 0)
+       need += 8;
+      if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
+       need += 4;
+      if ((tls_mask & TLS_DTPREL) != 0)
+       need += 4;
+    }
+  return need;
+}
+
+/* Calculate size of relocs needed for symbol given its TLS_MASK and
+   NEEDed GOT entries.  KNOWN says a TPREL offset can be calculated at
+   link time.  */
+
+static inline unsigned int
+got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
+{
+  /* All the entries we allocated need relocs.
+     Except IE in executable with a local symbol.  We could also omit
+     the DTPREL reloc on the second word of a GD entry under the same
+     condition as that for IE, but ld.so needs to differentiate
+     LD and GD entries.  */
+  if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known)
+    need -= 4;
+  return need * sizeof (Elf32_External_Rela) / 4;
+}
+
+/* If H is undefined, make it dynamic if that makes sense.  */
 
 static bfd_boolean
-ensure_undefweak_dynamic (struct bfd_link_info *info,
-                         struct elf_link_hash_entry *h)
+ensure_undef_dynamic (struct bfd_link_info *info,
+                     struct elf_link_hash_entry *h)
 {
   struct elf_link_hash_table *htab = elf_hash_table (info);
 
   if (htab->dynamic_sections_created
-      && h->root.type == bfd_link_hash_undefweak
+      && ((info->dynamic_undefined_weak != 0
+          && h->root.type == bfd_link_hash_undefweak)
+         || h->root.type == bfd_link_hash_undefined)
       && h->dynindx == -1
       && !h->forced_local
       && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
@@ -5959,33 +5848,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       unsigned int need;
 
-      /* Make sure this symbol is output as a dynamic symbol.
-        Undefined weak syms won't yet be marked as dynamic.  */
-      if (!ensure_undefweak_dynamic (info, &eh->elf))
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (!ensure_undef_dynamic (info, &eh->elf))
        return FALSE;
 
       need = 0;
-      if ((eh->tls_mask & TLS_TLS) != 0)
+      if ((eh->tls_mask & TLS_LD) != 0)
        {
-         if ((eh->tls_mask & TLS_LD) != 0)
-           {
-             if (!eh->elf.def_dynamic)
-               /* We'll just use htab->tlsld_got.offset.  This should
-                  always be the case.  It's a little odd if we have
-                  a local dynamic reloc against a non-local symbol.  */
-               htab->tlsld_got.refcount += 1;
-             else
-               need += 8;
-           }
-         if ((eh->tls_mask & TLS_GD) != 0)
+         if (!eh->elf.def_dynamic)
+           /* We'll just use htab->tlsld_got.offset.  This should
+              always be the case.  It's a little odd if we have
+              a local dynamic reloc against a non-local symbol.  */
+           htab->tlsld_got.refcount += 1;
+         else
            need += 8;
-         if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
-           need += 4;
-         if ((eh->tls_mask & TLS_DTPREL) != 0)
-           need += 4;
        }
-      else
-       need += 4;
+      need += got_entries_needed (eh->tls_mask);
       if (need == 0)
        eh->elf.got.offset = (bfd_vma) -1;
       else
@@ -5995,29 +5873,42 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
               || (htab->elf.dynamic_sections_created
                   && eh->elf.dynindx != -1
                   && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
-             && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
-                 || eh->elf.root.type != bfd_link_hash_undefweak))
+             && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
            {
-             asection *rsec = htab->elf.srelgot;
-
+             asection *rsec;
+             bfd_boolean tprel_known = (bfd_link_executable (info)
+                                        && SYMBOL_REFERENCES_LOCAL (info,
+                                                                    &eh->elf));
+
+             need = got_relocs_needed (eh->tls_mask, need, tprel_known);
+             if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic)
+               need -= sizeof (Elf32_External_Rela);
+             rsec = htab->elf.srelgot;
              if (eh->elf.type == STT_GNU_IFUNC)
                rsec = htab->elf.irelplt;
-             /* All the entries we allocated need relocs.
-                Except LD only needs one.  */
-             if ((eh->tls_mask & TLS_LD) != 0
-                 && eh->elf.def_dynamic)
-               need -= 4;
-             rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
+             rsec->size += need;
            }
        }
     }
   else
     eh->elf.got.offset = (bfd_vma) -1;
 
+  /* 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;
 
+  /* Discard relocs on undefined symbols that must be local.  */
+  else if (h->root.type == bfd_link_hash_undefined
+          && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+    eh->dyn_relocs = NULL;
+
+  /* Also discard relocs on undefined weak syms with non-default
+     visibility, or when dynamic_undefined_weak says so.  */
+  else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+    eh->dyn_relocs = NULL;
+
   if (eh->dyn_relocs == NULL)
     ;
 
@@ -6062,24 +5953,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
 
-      /* Discard relocs on undefined symbols that must be local.  */
-      if (eh->dyn_relocs != NULL
-         && h->root.type == bfd_link_hash_undefined
-         && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
-             || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
-       eh->dyn_relocs = NULL;
-
-      /* 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 undefined weak symbols are output as a dynamic
-            symbol in PIEs.  */
-         else if (!ensure_undefweak_dynamic (info, h))
+         /* Make sure this symbol is output as a dynamic symbol.  */
+         if (!ensure_undef_dynamic (info, h))
            return FALSE;
        }
     }
@@ -6088,16 +5965,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       /* For the non-pic case, discard space for relocs against
         symbols which turn out to need copy relocs or are not
         dynamic.  */
-      if (!h->non_got_ref
+      if (h->dynamic_adjusted
          && !h->def_regular
+         && !ELF_COMMON_DEF_P (h)
          && !(h->protected_def
               && eh->has_addr16_ha
               && eh->has_addr16_lo
               && htab->params->pic_fixup > 0))
        {
-         /* Make sure this symbol is output as a dynamic symbol.
-            Undefined weak syms won't yet be marked as dynamic.  */
-         if (!ensure_undefweak_dynamic (info, h))
+         /* Make sure this symbol is output as a dynamic symbol.  */
+         if (!ensure_undef_dynamic (info, h))
            return FALSE;
 
          if (h->dynindx == -1)
@@ -6269,14 +6146,22 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
    read-only sections.  */
 
 static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *h, void *info)
+maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
 {
+  asection *sec;
+
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (readonly_dynrelocs (h))
+  sec = readonly_dynrelocs (h);
+  if (sec != NULL)
     {
-      ((struct bfd_link_info *) info)->flags |= DF_TEXTREL;
+      struct bfd_link_info *info = (struct bfd_link_info *) info_p;
+
+      info->flags |= DF_TEXTREL;
+      info->callbacks->minfo
+       (_("%B: dynamic relocation in read-only section `%A'\n"),
+        sec->owner, sec);
 
       /* Not an error, just cut short the traversal.  */
       return FALSE;
@@ -6381,7 +6266,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                  if ((p->sec->output_section->flags
                       & (SEC_READONLY | SEC_ALLOC))
                      == (SEC_READONLY | SEC_ALLOC))
-                   info->flags |= DF_TEXTREL;
+                   {
+                     info->flags |= DF_TEXTREL;
+                     info->callbacks->minfo (_("%B: dynamic relocation in read-only section `%A'\n"),
+                                             p->sec->owner, p->sec);
+                   }
                }
            }
        }
@@ -6400,20 +6289,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       for (; local_got < end_local_got; ++local_got, ++lgot_masks)
        if (*local_got > 0)
          {
-           unsigned int need = 0;
-           if ((*lgot_masks & TLS_TLS) != 0)
-             {
-               if ((*lgot_masks & TLS_GD) != 0)
-                 need += 8;
-               if ((*lgot_masks & TLS_LD) != 0)
-                 htab->tlsld_got.refcount += 1;
-               if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
-                 need += 4;
-               if ((*lgot_masks & TLS_DTPREL) != 0)
-                 need += 4;
-             }
-           else
-             need += 4;
+           unsigned int need;
+           if ((*lgot_masks & TLS_LD) != 0)
+             htab->tlsld_got.refcount += 1;
+           need = got_entries_needed (*lgot_masks);
            if (need == 0)
              *local_got = (bfd_vma) -1;
            else
@@ -6421,10 +6300,14 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                *local_got = allocate_got (htab, need);
                if (bfd_link_pic (info))
                  {
-                   asection *srel = htab->elf.srelgot;
+                   asection *srel;
+                   bfd_boolean tprel_known = bfd_link_executable (info);
+
+                   need = got_relocs_needed (*lgot_masks, need, tprel_known);
+                   srel = htab->elf.srelgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
                      srel = htab->elf.irelplt;
-                   srel->size += need * (sizeof (Elf32_External_Rela) / 4);
+                   srel->size += need;
                  }
              }
          }
@@ -7885,7 +7768,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          wrel->r_addend = 0;
 
          /* For ld -r, remove relocations in debug sections against
-            sections defined in discarded sections.  Not done for
+            symbols defined in discarded sections.  Not done for
             non-debug to preserve relocs in .eh_frame which the
             eh_frame editing code expects to be present.  */
          if (bfd_link_relocatable (info)
@@ -8233,7 +8116,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
                  wrel->r_addend = got_addr;
                  insn &= ~0xffff;
-                 insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+                 insn |= ((unsigned int(got_addr + 0x8000) >> 16) & 0xffff;
                  bfd_put_32 (input_bfd, insn, p);
 
                  /* Convert lis to lwz, loading address from GOT.  */
@@ -8259,9 +8142,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  r_type = R_PPC_GOT16_LO;
                }
              else
-               info->callbacks->einfo
+               _bfd_error_handler
                  /* xgettext:c-format */
-                 (_("%H: error: %s with unexpected instruction %x\n"),
+                 (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"),
                   input_bfd, input_section, rel->r_offset,
                   "R_PPC_ADDR16_HA", insn);
            }
@@ -8294,9 +8177,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  rel->r_info = ELF32_R_INFO (0, r_type);
                }
              else
-               info->callbacks->einfo
+               _bfd_error_handler
                  /* xgettext:c-format */
-                 (_("%H: error: %s with unexpected instruction %x\n"),
+                 (_("%B(%A+%#Lx): error: %s with unexpected instruction %#x"),
                   input_bfd, input_section, rel->r_offset,
                   "R_PPC_ADDR16_LO", insn);
            }
@@ -8369,6 +8252,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  loc += (htab->elf.irelplt->reloc_count++
                          * sizeof (Elf32_External_Rela));
                  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                 htab->local_ifunc_resolver = 1;
 
                  ent->plt.offset |= 1;
                }
@@ -8396,10 +8280,44 @@ ppc_elf_relocate_section (bfd *output_bfd,
        }
 
       addend = rel->r_addend;
-      tls_type = 0;
       howto = NULL;
       if (r_type < R_PPC_max)
        howto = ppc_elf_howto_table[r_type];
+
+      switch (r_type)
+       {
+       default:
+         break;
+
+       case R_PPC_TPREL16_HA:
+         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+           {
+             bfd_byte *p = contents + (rel->r_offset & ~3);
+             unsigned int insn = bfd_get_32 (input_bfd, p);
+             if ((insn & ((0x3f << 26) | 0x1f << 16))
+                 != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
+               /* xgettext:c-format */
+               info->callbacks->minfo
+                 (_("%H: warning: %s unexpected insn %#x.\n"),
+                  input_bfd, input_section, rel->r_offset, howto->name, insn);
+             else
+               bfd_put_32 (input_bfd, NOP, p);
+           }
+         break;
+
+       case R_PPC_TPREL16_LO:
+         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+           {
+             bfd_byte *p = contents + (rel->r_offset & ~3);
+             unsigned int insn = bfd_get_32 (input_bfd, p);
+             insn &= ~(0x1f << 16);
+             insn |= 2 << 16;
+             bfd_put_32 (input_bfd, insn, p);
+           }
+         break;
+       }
+
+      tls_type = 0;
       switch (r_type)
        {
        default:
@@ -8479,8 +8397,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                if (!htab->elf.dynamic_sections_created
                    || h->dynindx == -1
                    || SYMBOL_REFERENCES_LOCAL (info, h)
-                   || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-                       && h->root.type == bfd_link_hash_undefweak))
+                   || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
                  /* This is actually a static link, or it is a
                     -Bsymbolic link and the symbol is defined
                     locally, or the symbol was forced to be local
@@ -8549,15 +8466,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    if (indx != 0
                        || (bfd_link_pic (info)
                            && (h == NULL
-                               || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                               || h->root.type != bfd_link_hash_undefweak
-                               || offp == &htab->tlsld_got.offset)))
+                               || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
+                               || offp == &htab->tlsld_got.offset)
+                           && !(tls_ty == (TLS_TLS | TLS_TPREL)
+                                && bfd_link_executable (info)
+                                && SYMBOL_REFERENCES_LOCAL (info, h))))
                      {
                        asection *rsec = htab->elf.srelgot;
                        bfd_byte * loc;
 
                        if (ifunc != NULL)
-                         rsec = htab->elf.irelplt;
+                         {
+                           rsec = htab->elf.irelplt;
+                           if (indx == 0)
+                             htab->local_ifunc_resolver = 1;
+                           else if (is_static_defined (h))
+                             htab->maybe_local_ifunc_resolver = 1;
+                         }
                        outrel.r_offset = (htab->elf.sgot->output_section->vma
                                           + htab->elf.sgot->output_offset
                                           + off);
@@ -8609,10 +8534,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    else
                      {
                        bfd_vma value = relocation;
-                       int tlsopt = (htab->plt_type == PLT_NEW
-                                     && !htab->params->no_tls_get_addr_opt
-                                     && htab->tls_get_addr != NULL
-                                     && htab->tls_get_addr->plt.plist != NULL);
 
                        if (tls_ty != 0)
                          {
@@ -8624,8 +8545,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                  value = 0;
                                else
                                  value -= htab->elf.tls_sec->vma + DTP_OFFSET;
-                               if ((tls_ty & TLS_TPREL)
-                                   || (tlsopt && !(tls_ty & TLS_DTPREL)))
+                               if (tls_ty & TLS_TPREL)
                                  value += DTP_OFFSET - TP_OFFSET;
                              }
 
@@ -8633,7 +8553,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              {
                                bfd_put_32 (input_bfd, value,
                                            htab->elf.sgot->contents + off + 4);
-                               value = !tlsopt;
+                               value = 1;
                              }
                          }
                        bfd_put_32 (input_bfd, value,
@@ -8760,8 +8680,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          /* The TPREL16 relocs shouldn't really be used in shared
-            libs as they will result in DT_TEXTREL being set, but
-            support them anyway.  */
+            libs or with non-local symbols as that will result in
+            DT_TEXTREL being set, but support them anyway.  */
          goto dodyn;
 
        case R_PPC_TPREL32:
@@ -8827,29 +8747,19 @@ ppc_elf_relocate_section (bfd *output_bfd,
              || is_vxworks_tls)
            break;
 
-         if ((bfd_link_pic (info)
-              && !(h != NULL
-                   && ((h->root.type == bfd_link_hash_undefined
-                        && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
-                            || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
-                       || (h->root.type == bfd_link_hash_undefweak
-                           && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
-              && (must_be_dyn_reloc (info, r_type)
-                  || !SYMBOL_CALLS_LOCAL (info, h)))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && h->dynindx != -1
-                 && !h->non_got_ref
-                 && !h->def_regular
-                 && !(h->protected_def
-                      && ppc_elf_hash_entry (h)->has_addr16_ha
-                      && ppc_elf_hash_entry (h)->has_addr16_lo
-                      && htab->params->pic_fixup > 0)))
+         if (bfd_link_pic (info)
+             ? ((h == NULL
+                 || ppc_elf_hash_entry (h)->dyn_relocs != NULL)
+                && ((h != NULL && pc_dynrelocs (h))
+                    || must_be_dyn_reloc (info, r_type)))
+             : (h != NULL
+                && ppc_elf_hash_entry (h)->dyn_relocs != NULL))
            {
              int skip;
              bfd_byte *loc;
              asection *sreloc;
+             long indx = 0;
+
 #ifdef DEBUG
              fprintf (stderr, "ppc_elf_relocate_section needs to "
                       "create relocation for %s\n",
@@ -8860,12 +8770,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
              /* When generating a shared object, these relocations
                 are copied into the output file to be resolved at run
                 time.  */
-             sreloc = elf_section_data (input_section)->sreloc;
-             if (ifunc)
-               sreloc = htab->elf.irelplt;
-             if (sreloc == NULL)
-               return FALSE;
-
              skip = 0;
              outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
                                                         input_section,
@@ -8878,14 +8782,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if ((h != NULL
-                       && (h->root.type == bfd_link_hash_undefined
-                           || h->root.type == bfd_link_hash_undefweak))
-                      || !SYMBOL_REFERENCES_LOCAL (info, h))
+             else if (!SYMBOL_REFERENCES_LOCAL (info, h))
                {
-                 BFD_ASSERT (h->dynindx != -1);
+                 indx = h->dynindx;
+                 BFD_ASSERT (indx != -1);
                  unresolved_reloc = FALSE;
-                 outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+                 outrel.r_info = ELF32_R_INFO (indx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
              else
@@ -8894,8 +8796,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
                  if (r_type != R_PPC_ADDR32)
                    {
-                     long indx = 0;
-
                      if (ifunc != NULL)
                        {
                          /* If we get here when building a static
@@ -8960,6 +8860,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
                }
 
+             sreloc = elf_section_data (input_section)->sreloc;
+             if (ifunc)
+               {
+                 sreloc = htab->elf.irelplt;
+                 if (indx == 0)
+                   htab->local_ifunc_resolver = 1;
+                 else if (is_static_defined (h))
+                   htab->maybe_local_ifunc_resolver = 1;
+               }
+             if (sreloc == NULL)
+               return FALSE;
+
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
              bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
@@ -8976,34 +8888,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  break;
                }
            }
-         else if (r_type == R_PPC_DTPMOD32
-                  && htab->plt_type == PLT_NEW
-                  && !htab->params->no_tls_get_addr_opt
-                  && htab->tls_get_addr != NULL
-                  && htab->tls_get_addr->plt.plist != NULL)
-           {
-             /* Set up for __tls_get_addr_opt stub when this entry
-                does not have dynamic relocs.  */
-             relocation = 0;
-             /* Set up the next word for local dynamic.  If it turns
-                out to be global dynamic, the reloc will overwrite
-                this value.  */
-             if (rel->r_offset + 8 <= input_section->size)
-               bfd_put_32 (input_bfd, DTP_OFFSET - TP_OFFSET,
-                           contents + rel->r_offset + 4);
-           }
-         else if (r_type == R_PPC_DTPREL32
-                  && htab->plt_type == PLT_NEW
-                  && !htab->params->no_tls_get_addr_opt
-                  && htab->tls_get_addr != NULL
-                  && htab->tls_get_addr->plt.plist != NULL
-                  && rel > relocs
-                  && rel[-1].r_info == ELF32_R_INFO (r_symndx, R_PPC_DTPMOD32)
-                  && rel[-1].r_offset + 4 == rel->r_offset)
-           {
-             /* __tls_get_addr_opt stub value.  */
-             addend += DTP_OFFSET - TP_OFFSET;
-           }
          break;
 
        case R_PPC_RELAX_PLT:
@@ -9471,6 +9355,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
          }
          goto copy_reloc;
 
+       case R_PPC_VLE_ADDR20:
+         ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation);
+         continue;
+
          /* Relocate against the beginning of the section.  */
        case R_PPC_SECTOFF:
        case R_PPC_SECTOFF_LO:
@@ -10250,12 +10138,19 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
-             loc = (htab->elf.irelplt->contents
-                    + (htab->elf.irelplt->reloc_count++
-                       * sizeof (Elf32_External_Rela)));
+             {
+               loc = (htab->elf.irelplt->contents
+                      + (htab->elf.irelplt->reloc_count++
+                         * sizeof (Elf32_External_Rela)));
+               htab->local_ifunc_resolver = 1;
+             }
            else
-             loc = (htab->elf.srelplt->contents
-                    + reloc_index * sizeof (Elf32_External_Rela));
+             {
+               loc = (htab->elf.srelplt->contents
+                      + reloc_index * sizeof (Elf32_External_Rela));
+               if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+                 htab->maybe_local_ifunc_resolver = 1;
+             }
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
            if (!h->def_regular)
@@ -10355,7 +10250,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       if (ppc_elf_hash_entry (h)->has_sda_refs)
        s = htab->relsbss;
-      else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+      else if (h->root.u.def.section == htab->elf.sdynrelro)
        s = htab->elf.sreldynrelro;
       else
        s = htab->elf.srelbss;
@@ -10460,6 +10355,17 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              dyn.d_un.d_ptr = got;
              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;
+
            default:
              if (htab->is_vxworks
                  && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
@@ -10911,11 +10817,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
 #define elf_backend_object_p                   ppc_elf_object_p
 #define elf_backend_gc_mark_hook               ppc_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook              ppc_elf_gc_sweep_hook
 #define elf_backend_section_from_shdr          ppc_elf_section_from_shdr
 #define elf_backend_relocate_section           ppc_elf_relocate_section
 #define elf_backend_create_dynamic_sections    ppc_elf_create_dynamic_sections
 #define elf_backend_check_relocs               ppc_elf_check_relocs
+#define elf_backend_relocs_compatible          _bfd_elf_relocs_compatible
 #define elf_backend_copy_indirect_symbol       ppc_elf_copy_indirect_symbol
 #define elf_backend_adjust_dynamic_symbol      ppc_elf_adjust_dynamic_symbol
 #define elf_backend_add_symbol_hook            ppc_elf_add_symbol_hook
@@ -10925,7 +10831,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_finish_dynamic_sections    ppc_elf_finish_dynamic_sections
 #define elf_backend_fake_sections              ppc_elf_fake_sections
 #define elf_backend_additional_program_headers ppc_elf_additional_program_headers
-#define elf_backend_modify_segment_map         ppc_elf_modify_segment_map
+#define elf_backend_modify_segment_map         ppc_elf_modify_segment_map
 #define elf_backend_grok_prstatus              ppc_elf_grok_prstatus
 #define elf_backend_grok_psinfo                        ppc_elf_grok_psinfo
 #define elf_backend_write_core_note            ppc_elf_write_core_note
@@ -10973,7 +10879,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
 /* VxWorks uses the elf default section flags for .plt.  */
 static const struct bfd_elf_special_section *
-ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
 {
   if (sec->name == NULL)
     return NULL;
@@ -10995,7 +10901,7 @@ ppc_elf_vxworks_link_hash_table_create (bfd *abfd)
   if (ret)
     {
       struct ppc_elf_link_hash_table *htab
-        = (struct ppc_elf_link_hash_table *)ret;
+       = (struct ppc_elf_link_hash_table *)ret;
       htab->is_vxworks = 1;
       htab->plt_type = PLT_VXWORKS;
       htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
@@ -11010,23 +10916,23 @@ static bfd_boolean
 ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
                                 struct bfd_link_info *info,
                                 Elf_Internal_Sym *sym,
-                                const char **namep ATTRIBUTE_UNUSED,
-                                flagword *flagsp ATTRIBUTE_UNUSED,
+                                const char **namep,
+                                flagword *flagsp,
                                 asection **secp,
                                 bfd_vma *valp)
 {
-  if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp,
-                                  valp))
+  if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp,
+                                   valp))
     return FALSE;
 
-  return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
+  return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp);
 }
 
 static void
 ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 {
-  ppc_elf_final_write_processing(abfd, linker);
-  elf_vxworks_final_write_processing(abfd, linker);
+  ppc_elf_final_write_processing (abfd, linker);
+  elf_vxworks_final_write_processing (abfd, linker);
 }
 
 /* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so