Fix "PowerPC64 ELFv2 entry code" for big-endian
[external/binutils.git] / bfd / elf64-ppc.c
index e7e8820..f0bcee1 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright (C) 1999-2015 Free Software Foundation, Inc.
+   Copyright (C) 1999-2016 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
    Largely rewritten by Alan Modra.
@@ -138,6 +138,8 @@ static bfd_vma opd_entry_value
 
 /* TOC base pointers offset from start of TOC.  */
 #define TOC_BASE_OFF   0x8000
+/* TOC base alignment.  */
+#define TOC_BASE_ALIGN 256
 
 /* Offset of tp and dtp pointers from start of TLS block.  */
 #define TP_OFFSET      0x7000
@@ -171,8 +173,12 @@ static bfd_vma opd_entry_value
 #define LD_R2_0R2      0xe8420000      /* ld    %r2,xxx+0(%r2)  */
 
 #define LD_R2_0R1      0xe8410000      /* ld    %r2,0(%r1)      */
+#define LD_R2_0R12     0xe84c0000      /* ld    %r2,0(%r12)     */
+#define ADD_R2_R2_R12  0x7c426214      /* add   %r2,%r2,%r12    */
 
-#define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha     */
+#define LIS_R2         0x3c400000      /* lis %r2,xxx@ha         */
+#define ADDIS_R2_R12   0x3c4c0000      /* addis %r2,%r12,xxx@ha  */
+#define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha  */
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,xxx@ha */
 #define LD_R12_0R12    0xe98c0000      /* ld    %r12,xxx@l(%r12) */
 
@@ -236,6 +242,10 @@ static bfd_vma opd_entry_value
 #define NO_OPD_RELOCS 0
 #endif
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+#endif
+
 static inline int
 abiversion (bfd *abfd)
 {
@@ -2016,6 +2026,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* Like R_PPC64_REL16_HA but for split field in addpcis.  */
+  HOWTO (R_PPC64_REL16DX_HA,   /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_ha_reloc,    /* special_function */
+        "R_PPC64_REL16DX_HA",  /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1fffc1,              /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* Like R_PPC64_ADDR16_HI, but no overflow.  */
   HOWTO (R_PPC64_ADDR16_HIGH,  /* type */
         16,                    /* rightshift */
@@ -2106,6 +2131,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* Marker reloc on ELFv2 large-model function entry.  */
+  HOWTO (R_PPC64_ENTRY,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_ENTRY",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Like ADDR64, but use local entry point of function.  */
   HOWTO (R_PPC64_ADDR64_LOCAL, /* type */
         0,                     /* rightshift */
@@ -2161,13 +2201,10 @@ ppc_howto_init (void)
 {
   unsigned int i, type;
 
-  for (i = 0;
-       i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]);
-       i++)
+  for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++)
     {
       type = ppc64_elf_howto_raw[i].type;
-      BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
-                         / sizeof (ppc64_elf_howto_table[0])));
+      BFD_ASSERT (type < ARRAY_SIZE (ppc64_elf_howto_table));
       ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i];
     }
 }
@@ -2409,6 +2446,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_HI16_S_PCREL:               r = R_PPC64_REL16_HA;
       break;
+    case BFD_RELOC_PPC_REL16DX_HA:             r = R_PPC64_REL16DX_HA;
+      break;
+    case BFD_RELOC_PPC64_ENTRY:                        r = R_PPC64_ENTRY;
+      break;
     case BFD_RELOC_PPC64_ADDR64_LOCAL:         r = R_PPC64_ADDR64_LOCAL;
       break;
     case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
@@ -2426,9 +2467,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]);
-       i++)
+  for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++)
     if (ppc64_elf_howto_raw[i].name != NULL
        && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0)
       return &ppc64_elf_howto_raw[i];
@@ -2449,8 +2488,7 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
     ppc_howto_init ();
 
   type = ELF64_R_TYPE (dst->r_info);
-  if (type >= (sizeof (ppc64_elf_howto_table)
-              / sizeof (ppc64_elf_howto_table[0])))
+  if (type >= ARRAY_SIZE (ppc64_elf_howto_table))
     {
       (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
                             abfd, (int) type);
@@ -2466,6 +2504,11 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                    void *data, asection *input_section,
                    bfd *output_bfd, char **error_message)
 {
+  enum elf_ppc64_reloc_type r_type;
+  long insn;
+  bfd_size_type octets;
+  bfd_vma value;
+
   /* If this is a relocatable link (output_bfd test tells us), just
      call the generic function.  Any adjustment will be done at final
      link time.  */
@@ -2477,7 +2520,29 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
      We won't actually be using the low 16 bits, so trashing them
      doesn't matter.  */
   reloc_entry->addend += 0x8000;
-  return bfd_reloc_continue;
+  r_type = reloc_entry->howto->type;
+  if (r_type != R_PPC64_REL16DX_HA)
+    return bfd_reloc_continue;
+
+  value = 0;
+  if (!bfd_is_com_section (symbol->section))
+    value = symbol->value;
+  value += (reloc_entry->addend
+           + symbol->section->output_offset
+           + symbol->section->output_section->vma);
+  value -= (reloc_entry->address
+           + input_section->output_offset
+           + input_section->output_section->vma);
+  value = (bfd_signed_vma) value >> 16;
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+  insn &= ~0x1fffc1;
+  insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+  if (value + 0x8000 > 0xffff)
+    return bfd_reloc_overflow;
+  return bfd_reloc_ok;
 }
 
 static bfd_reloc_status_type
@@ -3099,11 +3164,11 @@ compare_symbols (const void *ap, const void *bp)
 /* Search SYMS for a symbol of the given VALUE.  */
 
 static asymbol *
-sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
+sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value)
 {
   long mid;
 
-  if (id == -1)
+  if (id == (unsigned) -1)
     {
       while (lo < hi)
        {
@@ -3714,7 +3779,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
     case R_PPC64_TPREL64:
-      return !info->executable;
+      return !bfd_link_executable (info);
     }
 }
 
@@ -3794,7 +3859,22 @@ enum ppc_stub_type {
   ppc_stub_plt_branch_r2off,
   ppc_stub_plt_call,
   ppc_stub_plt_call_r2save,
-  ppc_stub_global_entry
+  ppc_stub_global_entry,
+  ppc_stub_save_res
+};
+
+/* Information on stub grouping.  */
+struct map_stub
+{
+  /* The stub section.  */
+  asection *stub_sec;
+  /* This is the section to which stubs in the group will be attached.  */
+  asection *link_sec;
+  /* Next group.  */
+  struct map_stub *next;
+  /* Whether to emit a copy of register save/restore functions in this
+     group.  */
+  int needs_save_res;
 };
 
 struct ppc_stub_hash_entry {
@@ -3804,8 +3884,8 @@ struct ppc_stub_hash_entry {
 
   enum ppc_stub_type stub_type;
 
-  /* The stub section.  */
-  asection *stub_sec;
+  /* Group information.  */
+  struct map_stub *group;
 
   /* Offset within stub_sec of the beginning of this stub.  */
   bfd_vma stub_offset;
@@ -3819,10 +3899,6 @@ struct ppc_stub_hash_entry {
   struct ppc_link_hash_entry *h;
   struct plt_entry *plt_ent;
 
-  /* Where this stub is being called from, or, in the case of combined
-     stub sections, the first input section in the group.  */
-  asection *id_sec;
-
   /* Symbol st_other.  */
   unsigned char other;
 };
@@ -3886,6 +3962,10 @@ struct ppc_link_hash_entry
   /* Set if we twiddled this symbol to weak at some stage.  */
   unsigned int was_undefined:1;
 
+  /* Set if this is an out-of-line register save/restore function,
+     with non-standard calling convention.  */
+  unsigned int save_res:1;
+
   /* Contexts in which symbol is used in the GOT (or TOC).
      TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
      corresponding relocs are encountered during check_relocs.
@@ -3923,34 +4003,37 @@ struct ppc_link_hash_table
   /* Various options and other info passed from the linker.  */
   struct ppc64_elf_params *params;
 
-  /* Array to keep track of which stub sections have been created, and
-     information on stub grouping.  */
-  struct map_stub {
-    /* This is the section to which stubs in the group will be attached.  */
-    asection *link_sec;
-    /* The stub section.  */
-    asection *stub_sec;
-    /* Along with elf_gp, specifies the TOC pointer used in this group.  */
+  /* The size of sec_info below.  */
+  unsigned int sec_info_arr_size;
+
+  /* Per-section array of extra section info.  Done this way rather
+     than as part of ppc64_elf_section_data so we have the info for
+     non-ppc64 sections.  */
+  struct
+  {
+    /* Along with elf_gp, specifies the TOC pointer used by this section.  */
     bfd_vma toc_off;
-  } *stub_group;
+
+    union
+    {
+      /* The section group that this section belongs to.  */
+      struct map_stub *group;
+      /* A temp section list pointer.  */
+      asection *list;
+    } u;
+  } *sec_info;
+
+  /* Linked list of groups.  */
+  struct map_stub *group;
 
   /* Temp used when calculating TOC pointers.  */
   bfd_vma toc_curr;
   bfd *toc_bfd;
   asection *toc_first_sec;
 
-  /* Highest input section id.  */
-  int top_id;
-
-  /* Highest output section index.  */
-  int top_index;
-
   /* Used when adding symbols.  */
   struct ppc_link_hash_entry *dot_syms;
 
-  /* List of input sections for each output section.  */
-  asection **input_list;
-
   /* Shortcuts to get to dynamic linker sections.  */
   asection *dynbss;
   asection *relbss;
@@ -4054,13 +4137,12 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
       /* Initialize the local fields.  */
       eh = (struct ppc_stub_hash_entry *) entry;
       eh->stub_type = ppc_stub_none;
-      eh->stub_sec = NULL;
+      eh->group = NULL;
       eh->stub_offset = 0;
       eh->target_value = 0;
       eh->target_section = NULL;
       eh->h = NULL;
       eh->plt_ent = NULL;
-      eh->id_sec = NULL;
       eh->other = 0;
     }
 
@@ -4313,7 +4395,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
-  if (!info->shared)
+  if (!bfd_link_pic (info))
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
@@ -4347,7 +4429,7 @@ ppc64_elf_init_stub_bfd (struct bfd_link_info *info,
   htab->elf.dynobj = params->stub_bfd;
   htab->params = params;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   return create_linkage_sections (htab->elf.dynobj, info);
@@ -4410,18 +4492,18 @@ ppc_get_stub_entry (const asection *input_section,
                    struct ppc_link_hash_table *htab)
 {
   struct ppc_stub_hash_entry *stub_entry;
-  const asection *id_sec;
+  struct map_stub *group;
 
   /* If this input section is part of a group of sections sharing one
      stub section, then use the id of the first section in the group.
      Stub names need to include a section id, as there may well be
      more than one stub used to reach say, printf, and we need to
      distinguish between them.  */
-  id_sec = htab->stub_group[input_section->id].link_sec;
+  group = htab->sec_info[input_section->id].u.group;
 
   if (h != NULL && h->u.stub_cache != NULL
       && h->u.stub_cache->h == h
-      && h->u.stub_cache->id_sec == id_sec)
+      && h->u.stub_cache->group == group)
     {
       stub_entry = h->u.stub_cache;
     }
@@ -4429,7 +4511,7 @@ ppc_get_stub_entry (const asection *input_section,
     {
       char *stub_name;
 
-      stub_name = ppc_stub_name (id_sec, sym_sec, h, rel);
+      stub_name = ppc_stub_name (group->link_sec, sym_sec, h, rel);
       if (stub_name == NULL)
        return NULL;
 
@@ -4453,35 +4535,32 @@ ppc_add_stub (const char *stub_name,
              struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  struct map_stub *group;
   asection *link_sec;
   asection *stub_sec;
   struct ppc_stub_hash_entry *stub_entry;
 
-  link_sec = htab->stub_group[section->id].link_sec;
-  stub_sec = htab->stub_group[section->id].stub_sec;
+  group = htab->sec_info[section->id].u.group;
+  link_sec = group->link_sec;
+  stub_sec = group->stub_sec;
   if (stub_sec == NULL)
     {
-      stub_sec = htab->stub_group[link_sec->id].stub_sec;
-      if (stub_sec == NULL)
-       {
-         size_t namelen;
-         bfd_size_type len;
-         char *s_name;
+      size_t namelen;
+      bfd_size_type len;
+      char *s_name;
 
-         namelen = strlen (link_sec->name);
-         len = namelen + sizeof (STUB_SUFFIX);
-         s_name = bfd_alloc (htab->params->stub_bfd, len);
-         if (s_name == NULL)
-           return NULL;
+      namelen = strlen (link_sec->name);
+      len = namelen + sizeof (STUB_SUFFIX);
+      s_name = bfd_alloc (htab->params->stub_bfd, len);
+      if (s_name == NULL)
+       return NULL;
 
-         memcpy (s_name, link_sec->name, namelen);
-         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
-         stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
-         if (stub_sec == NULL)
-           return NULL;
-         htab->stub_group[link_sec->id].stub_sec = stub_sec;
-       }
-      htab->stub_group[section->id].stub_sec = stub_sec;
+      memcpy (s_name, link_sec->name, namelen);
+      memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+      stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
+      if (stub_sec == NULL)
+       return NULL;
+      group->stub_sec = stub_sec;
     }
 
   /* Enter this entry into the linker stub hash table.  */
@@ -4494,9 +4573,8 @@ ppc_add_stub (const char *stub_name,
       return NULL;
     }
 
-  stub_entry->stub_sec = stub_sec;
+  stub_entry->group = group;
   stub_entry->stub_offset = 0;
-  stub_entry->id_sec = link_sec;
   return stub_entry;
 }
 
@@ -4553,11 +4631,11 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!info->shared)
+  if (!bfd_link_pic (info))
     htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
 
   if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss
-      || (!info->shared && !htab->relbss))
+      || (!bfd_link_pic (info) && !htab->relbss))
     abort ();
 
   return TRUE;
@@ -4819,7 +4897,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
        || ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
       && (ibfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+    elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
 
   if (*sec != NULL
       && strcmp ((*sec)->name, ".opd") == 0)
@@ -4832,7 +4910,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
 
       /* If the symbol is a function defined in .opd, and the function
         code is in a discarded group, let it appear to be undefined.  */
-      if (!info->relocatable
+      if (!bfd_link_relocatable (info)
          && (*sec)->reloc_count != 0
          && opd_entry_value (*sec, *value, &code_sec, NULL,
                              FALSE) != (bfd_vma) -1
@@ -4947,7 +5025,7 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
   fdh = lookup_fdh (eh, htab);
   if (fdh == NULL)
     {
-      if (!info->relocatable
+      if (!bfd_link_relocatable (info)
          && (eh->elf.root.type == bfd_link_hash_undefined
              || eh->elf.root.type == bfd_link_hash_undefweak)
          && eh->elf.ref_regular)
@@ -5224,7 +5302,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   asection **opd_sym_map;
   struct elf_link_hash_entry *tga, *dottga;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   /* Don't do anything special with non-loaded, non-alloced sections.
@@ -5262,7 +5340,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       enum elf_ppc64_reloc_type r_type;
       int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
-      struct plt_entry **ifunc;
+      struct plt_entry **ifunc, **plt_list;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -5305,28 +5383,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                return FALSE;
            }
        }
-      r_type = ELF64_R_TYPE (rel->r_info);
-      if (is_branch_reloc (r_type))
-       {
-         if (h != NULL && (h == tga || h == dottga))
-           {
-             if (rel != relocs
-                 && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
-                     || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
-               /* We have a new-style __tls_get_addr call with a marker
-                  reloc.  */
-               ;
-             else
-               /* Mark this section as having an old-style call.  */
-               sec->has_tls_get_addr_call = 1;
-           }
-
-         /* STT_GNU_IFUNC symbols must have a PLT entry.  */
-         if (ifunc != NULL
-             && !update_plt_info (abfd, ifunc, rel->r_addend))
-           return FALSE;
-       }
 
+      r_type = ELF64_R_TYPE (rel->r_info);
       switch (r_type)
        {
        case R_PPC64_TLSGD:
@@ -5353,7 +5411,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -5426,7 +5484,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          /* We may also need a plt entry if the symbol turns out to be
             an ifunc.  */
-         if (h != NULL && !info->shared && abiversion (abfd) != 1)
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
            {
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                return FALSE;
@@ -5438,27 +5496,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_PLT16_LO:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
-         /* This symbol requires a procedure linkage table entry.  We
-            actually build the entry in adjust_dynamic_symbol,
-            because this might be a case of linking PIC code without
-            linking in any dynamic objects, in which case we don't
-            need to generate a procedure linkage table after all.  */
-         if (h == NULL)
-           {
-             /* It does not make sense to have a procedure linkage
-                table entry for a local symbol.  */
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
-         else
+         /* This symbol requires a procedure linkage table entry.  */
+         plt_list = ifunc;
+         if (h != NULL)
            {
-             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
-               return FALSE;
              h->needs_plt = 1;
              if (h->root.root.string[0] == '.'
                  && h->root.root.string[1] != '\0')
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             plt_list = &h->plt.plist;
+           }
+         if (plt_list == NULL)
+           {
+             /* It does not make sense to have a procedure linkage
+                table entry for a non-ifunc local symbol.  */
+             info->callbacks->einfo
+               (_("%P: %H: %s reloc against local symbol\n"),
+                abfd, sec, rel->r_offset,
+                ppc64_elf_howto_table[r_type]->name);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
            }
+         if (!update_plt_info (abfd, plt_list, rel->r_addend))
+           return FALSE;
          break;
 
          /* The following relocations don't need to propagate the
@@ -5489,11 +5549,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_REL16_LO:
        case R_PPC64_REL16_HI:
        case R_PPC64_REL16_HA:
+       case R_PPC64_REL16DX_HA:
          break;
 
          /* Not supported as a dynamic relocation.  */
        case R_PPC64_ADDR64_LOCAL:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                ppc_howto_init ();
@@ -5517,6 +5578,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          sec->has_toc_reloc = 1;
          break;
 
+         /* Marker reloc.  */
+       case R_PPC64_ENTRY:
+         break;
+
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
        case R_PPC64_GNU_VTINHERIT:
@@ -5566,24 +5631,46 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_PPC64_REL24:
-         if (h != NULL && ifunc == NULL)
+         plt_list = ifunc;
+         if (h != NULL)
            {
-             /* We may need a .plt entry if the function this reloc
-                refers to is in a shared lib.  */
-             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
-               return FALSE;
              h->needs_plt = 1;
              if (h->root.root.string[0] == '.'
                  && h->root.root.string[1] != '\0')
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
+
              if (h == tga || h == dottga)
-               sec->has_tls_reloc = 1;
+               {
+                 sec->has_tls_reloc = 1;
+                 if (rel != relocs
+                     && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+                         || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+                   /* We have a new-style __tls_get_addr call with
+                      a marker reloc.  */
+                   ;
+                 else
+                   /* Mark this section as having an old-style call.  */
+                   sec->has_tls_get_addr_call = 1;
+               }
+             plt_list = &h->plt.plist;
            }
+
+         /* We may need a .plt entry if the function this reloc
+            refers to is in a shared lib.  */
+         if (plt_list
+             && !update_plt_info (abfd, plt_list, rel->r_addend))
+           return FALSE;
          break;
 
+       case R_PPC64_ADDR14:
+       case R_PPC64_ADDR14_BRNTAKEN:
+       case R_PPC64_ADDR14_BRTAKEN:
+       case R_PPC64_ADDR24:
+         goto dodyn;
+
        case R_PPC64_TPREL64:
          tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dotlstoc;
 
@@ -5659,7 +5746,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              info->flags |= DF_STATIC_TLS;
              goto dodyn;
@@ -5709,7 +5796,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_ADDR16_LO:
        case R_PPC64_ADDR16_LO_DS:
-         if (h != NULL && !info->shared && abiversion (abfd) != 1
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
              && rel->r_addend == 0)
            {
              /* We may need a .plt entry if this reloc refers to a
@@ -5723,16 +5810,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_REL30:
        case R_PPC64_REL32:
        case R_PPC64_REL64:
-       case R_PPC64_ADDR14:
-       case R_PPC64_ADDR14_BRNTAKEN:
-       case R_PPC64_ADDR14_BRTAKEN:
-       case R_PPC64_ADDR24:
        case R_PPC64_ADDR32:
        case R_PPC64_UADDR16:
        case R_PPC64_UADDR32:
        case R_PPC64_UADDR64:
        case R_PPC64_TOC:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            /* We may need a copy reloc.  */
            h->non_got_ref = 1;
 
@@ -5762,18 +5845,18 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
        dodyn:
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
                       && (!SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular))
-             || (!info->shared
+             || (!bfd_link_pic (info)
                  && ifunc != NULL))
            {
              /* We must copy these reloc types into the output file.
@@ -6032,14 +6115,13 @@ opd_entry_value (asection *opd_sec,
                  if (rh != NULL)
                    {
                      rh = elf_follow_link (rh);
-                     BFD_ASSERT (rh->root.type == bfd_link_hash_defined
-                                 || rh->root.type == bfd_link_hash_defweak);
-                     val = rh->root.u.def.value;
-                     sec = rh->root.u.def.section;
-                     if (sec->owner != opd_bfd)
+                     if (rh->root.type != bfd_link_hash_defined
+                         && rh->root.type != bfd_link_hash_defweak)
+                       break;
+                     if (rh->root.u.def.section->owner == opd_bfd)
                        {
-                         sec = NULL;
-                         val = (bfd_vma) -1;
+                         val = rh->root.u.def.value;
+                         sec = rh->root.u.def.section;
                        }
                    }
                }
@@ -6118,7 +6200,23 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
 
   if (strcmp (sym->section->name, ".opd") == 0)
     {
-      if (opd_entry_value (sym->section, sym->value,
+      struct _opd_sec_data *opd = get_opd_info (sym->section);
+      bfd_vma symval = sym->value;
+
+      if (opd != NULL
+         && opd->adjust != NULL
+         && elf_section_data (sym->section)->relocs != NULL)
+       {
+         /* opd_entry_value will use cached relocs that have been
+            adjusted, but with raw symbols.  That means both local
+            and global symbols need adjusting.  */
+         long adjust = opd->adjust[OPD_NDX (symval)];
+         if (adjust == -1)
+           return 0;
+         symval += adjust;
+       }
+
+      if (opd_entry_value (sym->section, symval,
                           &sec, code_off, TRUE) == (bfd_vma) -1)
        return 0;
       /* An old ABI binary with dot-syms has a size of 24 on the .opd
@@ -6255,7 +6353,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
          || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
-             && (!info->executable
+             && (!bfd_link_executable (info)
                  || info->export_dynamic
                  || (eh->elf.dynamic
                      && d != NULL
@@ -6385,7 +6483,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   struct got_entry **local_got_ents;
   const Elf_Internal_Rela *rel, *relend;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   if ((sec->flags & SEC_ALLOC) == 0)
@@ -6407,6 +6505,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;
       unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -6430,38 +6529,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
              }
        }
 
-      if (is_branch_reloc (r_type))
-       {
-         struct plt_entry **ifunc = NULL;
-         if (h != NULL)
-           {
-             if (h->type == STT_GNU_IFUNC)
-               ifunc = &h->plt.plist;
-           }
-         else if (local_got_ents != NULL)
-           {
-             struct plt_entry **local_plt = (struct plt_entry **)
-               (local_got_ents + symtab_hdr->sh_info);
-             unsigned char *local_got_tls_masks = (unsigned char *)
-               (local_plt + symtab_hdr->sh_info);
-             if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
-               ifunc = local_plt + r_symndx;
-           }
-         if (ifunc != NULL)
-           {
-             struct plt_entry *ent;
-
-             for (ent = *ifunc; ent != NULL; ent = ent->next)
-               if (ent->addend == rel->r_addend)
-                 break;
-             if (ent == NULL)
-               abort ();
-             if (ent->plt.refcount > 0)
-               ent->plt.refcount -= 1;
-             continue;
-           }
-       }
-
       switch (r_type)
        {
        case R_PPC64_GOT_TLSLD16:
@@ -6528,11 +6595,23 @@ 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)
+           {
+             struct plt_entry **local_plt = (struct plt_entry **)
+               (local_got_ents + symtab_hdr->sh_info);
+             unsigned char *local_got_tls_masks = (unsigned char *)
+               (local_plt + symtab_hdr->sh_info);
+             if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+               plt_list = local_plt + r_symndx;
+           }
+         if (plt_list)
            {
              struct plt_entry *ent;
 
-             for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+             for (ent = *plt_list; ent != NULL; ent = ent->next)
                if (ent->addend == rel->r_addend)
                  break;
              if (ent != NULL && ent->plt.refcount > 0)
@@ -6558,10 +6637,14 @@ struct sfpr_def_parms
   bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
 };
 
-/* Auto-generate _save*, _rest* functions in .sfpr.  */
+/* Auto-generate _save*, _rest* functions in .sfpr.
+   If STUB_SEC is non-null, define alias symbols in STUB_SEC
+   instead.  */
 
 static bfd_boolean
-sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
+sfpr_define (struct bfd_link_info *info,
+            const struct sfpr_def_parms *parm,
+            asection *stub_sec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   unsigned int i;
@@ -6577,26 +6660,60 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
 
   for (i = parm->lo; i <= parm->hi; i++)
     {
-      struct elf_link_hash_entry *h;
+      struct ppc_link_hash_entry *h;
 
       sym[len + 0] = i / 10 + '0';
       sym[len + 1] = i % 10 + '0';
-      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
-      if (h != NULL
-         && !h->def_regular)
+      h = (struct ppc_link_hash_entry *)
+       elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+      if (stub_sec != NULL)
        {
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = htab->sfpr;
-         h->root.u.def.value = htab->sfpr->size;
-         h->type = STT_FUNC;
-         h->def_regular = 1;
-         _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
-         writing = TRUE;
-         if (htab->sfpr->contents == NULL)
+         if (h != NULL
+             && h->elf.root.type == bfd_link_hash_defined
+             && h->elf.root.u.def.section == htab->sfpr)
            {
-             htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX);
-             if (htab->sfpr->contents == NULL)
+             struct elf_link_hash_entry *s;
+             char buf[32];
+             sprintf (buf, "%08x.%s", stub_sec->id & 0xffffffff, sym);
+             s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE);
+             if (s == NULL)
                return FALSE;
+             if (s->root.type == bfd_link_hash_new
+                 || (s->root.type = bfd_link_hash_defined
+                     && s->root.u.def.section == stub_sec))
+               {
+                 s->root.type = bfd_link_hash_defined;
+                 s->root.u.def.section = stub_sec;
+                 s->root.u.def.value = (stub_sec->size
+                                        + h->elf.root.u.def.value);
+                 s->ref_regular = 1;
+                 s->def_regular = 1;
+                 s->ref_regular_nonweak = 1;
+                 s->forced_local = 1;
+                 s->non_elf = 0;
+                 s->root.linker_def = 1;
+               }
+           }
+         continue;
+       }
+      if (h != NULL)
+       {
+         h->save_res = 1;
+         if (!h->elf.def_regular)
+           {
+             h->elf.root.type = bfd_link_hash_defined;
+             h->elf.root.u.def.section = htab->sfpr;
+             h->elf.root.u.def.value = htab->sfpr->size;
+             h->elf.type = STT_FUNC;
+             h->elf.def_regular = 1;
+             _bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE);
+             writing = TRUE;
+             if (htab->sfpr->contents == NULL)
+               {
+                 htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX);
+                 if (htab->sfpr->contents == NULL)
+                   return FALSE;
+               }
            }
        }
       if (writing)
@@ -6835,7 +6952,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 
   fdh = lookup_fdh (fh, htab);
   if (fdh == NULL
-      && !info->executable
+      && !bfd_link_executable (info)
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
@@ -6868,7 +6985,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 
   if (fdh != NULL
       && !fdh->elf.forced_local
-      && (!info->executable
+      && (!bfd_link_executable (info)
          || fdh->elf.def_dynamic
          || fdh->elf.ref_dynamic
          || (fdh->elf.root.type == bfd_link_hash_undefweak
@@ -6907,6 +7024,22 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+static const struct sfpr_def_parms save_res_funcs[] =
+  {
+    { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
+    { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
+    { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail },
+    { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail },
+    { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail },
+    { "_savefpr_", 14, 31, savefpr, savefpr0_tail },
+    { "_restfpr_", 14, 29, restfpr, restfpr0_tail },
+    { "_restfpr_", 30, 31, restfpr, restfpr0_tail },
+    { "._savef", 14, 31, savefpr, savefpr1_tail },
+    { "._restf", 14, 31, restfpr, restfpr1_tail },
+    { "_savevr_", 20, 31, savevr, savevr_tail },
+    { "_restvr_", 20, 31, restvr, restvr_tail }
+  };
+
 /* Called near the start of bfd_elf_size_dynamic_sections.  We use
    this hook to a) provide some gcc support functions, and b) transfer
    dynamic linking information gathered so far on function code symbol
@@ -6918,37 +7051,27 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
 {
   struct ppc_link_hash_table *htab;
   unsigned int i;
-  static const struct sfpr_def_parms funcs[] =
-    {
-      { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
-      { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
-      { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail },
-      { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail },
-      { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail },
-      { "_savefpr_", 14, 31, savefpr, savefpr0_tail },
-      { "_restfpr_", 14, 29, restfpr, restfpr0_tail },
-      { "_restfpr_", 30, 31, restfpr, restfpr0_tail },
-      { "._savef", 14, 31, savefpr, savefpr1_tail },
-      { "._restf", 14, 31, restfpr, restfpr1_tail },
-      { "_savevr_", 20, 31, savevr, savevr_tail },
-      { "_restvr_", 20, 31, restvr, restvr_tail }
-    };
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
-  if (!info->relocatable
+  if (!bfd_link_relocatable (info)
       && htab->elf.hgot != NULL)
     {
       _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
       /* Make .TOC. defined so as to prevent it being made dynamic.
         The wrong value here is fixed later in ppc64_elf_set_toc.  */
+      if (!htab->elf.hgot->def_regular
+         || htab->elf.hgot->root.type != bfd_link_hash_defined)
+       {
+         htab->elf.hgot->root.type = bfd_link_hash_defined;
+         htab->elf.hgot->root.u.def.value = 0;
+         htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr;
+         htab->elf.hgot->def_regular = 1;
+         htab->elf.hgot->root.linker_def = 1;
+       }
       htab->elf.hgot->type = STT_OBJECT;
-      htab->elf.hgot->root.type = bfd_link_hash_defined;
-      htab->elf.hgot->root.u.def.value = 0;
-      htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr;
-      htab->elf.hgot->def_regular = 1;
       htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1))
                               | STV_HIDDEN);
     }
@@ -6960,8 +7083,8 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
   /* Provide any missing _save* and _rest* functions.  */
   htab->sfpr->size = 0;
   if (htab->params->save_restore_funcs)
-    for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
-      if (!sfpr_define (info, &funcs[i]))
+    for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+      if (!sfpr_define (info, &save_res_funcs[i], NULL))
        return FALSE;
 
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
@@ -7023,7 +7146,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          || (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->root.type == bfd_link_hash_undefweak)))
+         || ((struct ppc_link_hash_entry *) h)->save_res)
        {
          h->plt.plist = NULL;
          h->needs_plt = 0;
@@ -7083,7 +7207,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (info->shared)
+  if (bfd_link_pic (info))
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -7502,7 +7626,7 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_TPREL16_HIGHERA:
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
-      if (!info->shared)
+      if (!bfd_link_pic (info))
        return TRUE;
 
     case R_PPC64_TPREL64:
@@ -7546,14 +7670,14 @@ dec_dynrel_count (bfd_vma r_info,
        return FALSE;
     }
 
-  if ((info->shared
+  if ((bfd_link_pic (info)
        && (must_be_dyn_reloc (info, r_type)
           || (h != NULL
               && (!SYMBOLIC_BIND (info, h)
                   || h->root.type == bfd_link_hash_defweak
                   || !h->def_regular))))
       || (ELIMINATE_COPY_RELOCS
-         && !info->shared
+         && !bfd_link_pic (info)
          && h != NULL
          && (h->root.type == bfd_link_hash_defweak
              || !h->def_regular)))
@@ -7900,7 +8024,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                    }
                  opd->adjust[OPD_NDX (rel->r_offset)] = -1;
 
-                 if (NO_OPD_RELOCS || info->relocatable)
+                 if (NO_OPD_RELOCS || bfd_link_relocatable (info))
                    rel = next_rel;
                  else
                    while (1)
@@ -8000,7 +8124,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
 
   /* If we are doing a final link and the last .opd entry is just 16 byte
      long, add a 8 byte padding after it.  */
-  if (need_pad != NULL && !info->relocatable)
+  if (need_pad != NULL && !bfd_link_relocatable (info))
     {
       bfd_byte *p;
 
@@ -8063,7 +8187,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
   htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
                           elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                                                 FALSE, FALSE, TRUE));
-  if (!htab->params->no_tls_get_addr_opt)
+  if (htab->params->tls_get_addr_opt)
     {
       struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
 
@@ -8130,8 +8254,8 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
                }
            }
        }
-      else
-       htab->params->no_tls_get_addr_opt = TRUE;
+      else if (htab->params->tls_get_addr_opt < 0)
+       htab->params->tls_get_addr_opt = 0;
     }
   return _bfd_elf_tls_setup (info->output_bfd, info);
 }
@@ -8178,7 +8302,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
   unsigned char *toc_ref;
   int pass;
 
-  if (info->relocatable || !info->executable)
+  if (!bfd_link_executable (info))
     return TRUE;
 
   htab = ppc_hash_table (info);
@@ -8273,7 +8397,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      if (h != NULL
                          && h->root.type == bfd_link_hash_undefweak)
                        ok_tprel = TRUE;
-                     else
+                     else if (sym_sec != NULL
+                              && sym_sec->output_section != NULL)
                        {
                          value += sym_sec->output_offset;
                          value += sym_sec->output_section->vma;
@@ -8834,6 +8959,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                goto error_ret;
 
              if (sym_sec == NULL
+                 || sym_sec->output_section == NULL
                  || discarded_section (sym_sec))
                continue;
 
@@ -9372,7 +9498,7 @@ allocate_got (struct elf_link_hash_entry *h,
       htab->elf.irelplt->size += rentsize;
       htab->got_reli_size += rentsize;
     }
-  else if ((info->shared
+  else if ((bfd_link_pic (info)
            || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
               || h->root.type != bfd_link_hash_undefweak))
@@ -9425,7 +9551,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
   if ((htab->elf.dynamic_sections_created
        && h->dynindx != -1
-       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
       || h->type == STT_GNU_IFUNC)
     {
       struct plt_entry *pent;
@@ -9568,7 +9694,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      space for relocs that have become local due to symbol visibility
      changes.  */
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       /* Relocs that use pc_count are those that appear on a call insn,
         or certain REL relocs (see must_be_dyn_reloc) that can be
@@ -9742,7 +9868,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->elf.dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      if (bfd_link_executable (info) && !info->nointerp)
        {
          s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
@@ -9834,7 +9960,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        htab->elf.irelplt->size += rel_size;
                        htab->got_reli_size += rel_size;
                      }
-                   else if (info->shared)
+                   else if (bfd_link_pic (info))
                      {
                        asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                        srel->size += rel_size;
@@ -9872,7 +9998,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->glink != NULL)
     htab->glink->rawsize = htab->glink->size;
 
-  if (!htab->opd_abi && !info->shared)
+  if (!htab->opd_abi && !bfd_link_pic (info))
     elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info);
 
   first_tlsld = NULL;
@@ -9899,7 +10025,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              ent->got.offset = s->size;
              ent->owner = ibfd;
              s->size += 16;
-             if (info->shared)
+             if (bfd_link_pic (info))
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += sizeof (Elf64_External_Rela);
@@ -10029,7 +10155,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -10052,7 +10178,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            return FALSE;
        }
 
-      tls_opt = (!htab->params->no_tls_get_addr_opt
+      tls_opt = (htab->params->tls_get_addr_opt
                 && htab->tls_get_addr_fd != NULL
                 && htab->tls_get_addr_fd->elf.plt.plist != NULL);
       if (tls_opt || !htab->opd_abi)
@@ -10237,7 +10363,7 @@ plt_stub_size (struct ppc_link_hash_table *htab,
   if (stub_entry->h != NULL
       && (stub_entry->h == htab->tls_get_addr_fd
          || stub_entry->h == htab->tls_get_addr)
-      && !htab->params->no_tls_get_addr_opt)
+      && htab->params->tls_get_addr_opt)
     size += 13 * 4;
   return size;
 }
@@ -10251,7 +10377,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
 {
   int stub_align = 1 << htab->params->plt_stub_align;
   unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
-  bfd_vma stub_off = stub_entry->stub_sec->size;
+  bfd_vma stub_off = stub_entry->group->stub_sec->size;
 
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
@@ -10281,7 +10407,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       && plt_thread_safe
       && !((stub_entry->h == htab->tls_get_addr_fd
            || stub_entry->h == htab->tls_get_addr)
-          && !htab->params->no_tls_get_addr_opt))
+          && htab->params->tls_get_addr_opt))
     {
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
       bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
@@ -10294,7 +10420,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       to = (glinkoff
            + htab->glink->output_offset
            + htab->glink->output_section->vma);
-      from = (p - stub_entry->stub_sec->contents
+      from = (p - stub_entry->group->stub_sec->contents
              + 4 * (ALWAYS_EMIT_R2SAVE
                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
              + 4 * (PPC_HA (offset) != 0)
@@ -10302,8 +10428,8 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                     != PPC_HA (offset))
              + 4 * (plt_static_chain != 0)
              + 20
-             + stub_entry->stub_sec->output_offset
-             + stub_entry->stub_sec->output_section->vma);
+             + stub_entry->group->stub_sec->output_offset
+             + stub_entry->group->stub_sec->output_section->vma);
       cmp_branch_off = to - from;
       use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
     }
@@ -10516,7 +10642,7 @@ get_r2off (struct bfd_link_info *info,
           struct ppc_stub_hash_entry *stub_entry)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
-  bfd_vma r2off = htab->stub_group[stub_entry->target_section->id].toc_off;
+  bfd_vma r2off = htab->sec_info[stub_entry->target_section->id].toc_off;
 
   if (r2off == 0)
     {
@@ -10534,14 +10660,14 @@ get_r2off (struct bfd_link_info *info,
          info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"),
                                  stub_entry->h->elf.root.root.string);
          bfd_set_error (bfd_error_bad_value);
-         return 0;
+         return (bfd_vma) -1;
        }
       if (!bfd_get_section_contents (opd->owner, opd, buf, opd_off + 8, 8))
-       return 0;
+       return (bfd_vma) -1;
       r2off = bfd_get_64 (opd->owner, buf);
       r2off -= elf_gp (info->output_bfd);
     }
-  r2off -= htab->stub_group[stub_entry->id_sec->id].toc_off;
+  r2off -= htab->sec_info[stub_entry->group->link_sec->id].toc_off;
   return r2off;
 }
 
@@ -10568,8 +10694,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     return FALSE;
 
   /* Make a note of the offset within the stubs for this entry.  */
-  stub_entry->stub_offset = stub_entry->stub_sec->size;
-  loc = stub_entry->stub_sec->contents + stub_entry->stub_offset;
+  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+  loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset;
 
   htab->stub_count[stub_entry->stub_type - 1] += 1;
   switch (stub_entry->stub_type)
@@ -10585,31 +10711,36 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       /* And this is where we are coming from.  */
       off -= (stub_entry->stub_offset
-             + stub_entry->stub_sec->output_offset
-             + stub_entry->stub_sec->output_section->vma);
+             + stub_entry->group->stub_sec->output_offset
+             + stub_entry->group->stub_sec->output_section->vma);
 
       size = 4;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
-         if (r2off == 0)
+         if (r2off == (bfd_vma) -1)
            {
              htab->stub_error = TRUE;
              return FALSE;
            }
          bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
          loc += 4;
-         size = 12;
+         size = 8;
          if (PPC_HA (r2off) != 0)
            {
-             size = 16;
              bfd_put_32 (htab->params->stub_bfd,
                          ADDIS_R2_R2 | PPC_HA (r2off), loc);
              loc += 4;
+             size += 4;
+           }
+         if (PPC_LO (r2off) != 0)
+           {
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDI_R2_R2 | PPC_LO (r2off), loc);
+             loc += 4;
+             size += 4;
            }
-         bfd_put_32 (htab->params->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
-         loc += 4;
          off -= size - 4;
        }
       bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
@@ -10625,10 +10756,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
-         r = get_relocs (stub_entry->stub_sec, 1);
+         r = get_relocs (stub_entry->group->stub_sec, 1);
          if (r == NULL)
            return FALSE;
-         r->r_offset = loc - stub_entry->stub_sec->contents;
+         r->r_offset = loc - stub_entry->group->stub_sec->contents;
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
          r->r_addend = dest;
          if (stub_entry->h != NULL)
@@ -10735,7 +10866,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       off = (dest
             - elf_gp (htab->brlt->output_section->owner)
-            - htab->stub_group[stub_entry->id_sec->id].toc_off);
+            - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
@@ -10749,10 +10880,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
-         r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0));
+         r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0));
          if (r == NULL)
            return FALSE;
-         r[0].r_offset = loc - stub_entry->stub_sec->contents;
+         r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
          if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
@@ -10790,7 +10921,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
-         if (r2off == 0 && htab->opd_abi)
+         if (r2off == (bfd_vma) -1)
            {
              htab->stub_error = TRUE;
              return FALSE;
@@ -10841,11 +10972,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
 
          /* If the old-ABI "dot-symbol" is undefined make it weak so
-            we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.
-            FIXME: We used to define the symbol on one of the call
-            stubs instead, which is why we test symbol section id
-            against htab->top_id in various places.  Likely all
-            these checks could now disappear.  */
+            we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.  */
          if (fh->elf.root.type == bfd_link_hash_undefined)
            fh->elf.root.type = bfd_link_hash_undefweak;
          /* Stop undo_symbol_twiddle changing it back to undefined.  */
@@ -10889,7 +11016,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       off = (dest
             - elf_gp (plt->output_section->owner)
-            - htab->stub_group[stub_entry->id_sec->id].toc_off);
+            - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
@@ -10907,15 +11034,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        {
          unsigned pad = plt_stub_pad (htab, stub_entry, off);
 
-         stub_entry->stub_sec->size += pad;
-         stub_entry->stub_offset = stub_entry->stub_sec->size;
+         stub_entry->group->stub_sec->size += pad;
+         stub_entry->stub_offset = stub_entry->group->stub_sec->size;
          loc += pad;
        }
 
       r = NULL;
       if (info->emitrelocations)
        {
-         r = get_relocs (stub_entry->stub_sec,
+         r = get_relocs (stub_entry->group->stub_sec,
                          ((PPC_HA (off) != 0)
                           + (htab->opd_abi
                              ? 2 + (htab->params->plt_static_chain
@@ -10923,7 +11050,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                              : 1)));
          if (r == NULL)
            return FALSE;
-         r[0].r_offset = loc - stub_entry->stub_sec->contents;
+         r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
          r[0].r_addend = dest;
@@ -10931,19 +11058,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
              || stub_entry->h == htab->tls_get_addr)
-         && !htab->params->no_tls_get_addr_opt)
+         && htab->params->tls_get_addr_opt)
        p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
       else
        p = build_plt_stub (htab, stub_entry, loc, off, r);
       size = p - loc;
       break;
 
+    case ppc_stub_save_res:
+      return TRUE;
+
     default:
       BFD_FAIL ();
       return FALSE;
     }
 
-  stub_entry->stub_sec->size += size;
+  stub_entry->group->stub_sec->size += size;
 
   if (htab->params->emit_stub_syms)
     {
@@ -10971,7 +11101,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (h->root.type == bfd_link_hash_new)
        {
          h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = stub_entry->stub_sec;
+         h->root.u.def.section = stub_entry->group->stub_sec;
          h->root.u.def.value = stub_entry->stub_offset;
          h->ref_regular = 1;
          h->def_regular = 1;
@@ -11006,6 +11136,18 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   if (htab == NULL)
     return FALSE;
 
+  if (stub_entry->h != NULL
+      && stub_entry->h->save_res
+      && stub_entry->h->elf.root.type == bfd_link_hash_defined
+      && stub_entry->h->elf.root.u.def.section == htab->sfpr)
+    {
+      /* Don't make stubs to out-of-line register save/restore
+        functions.  Instead, emit copies of the functions.  */
+      stub_entry->group->needs_save_res = 1;
+      stub_entry->stub_type = ppc_stub_save_res;
+      return TRUE;
+    }
+
   if (stub_entry->stub_type == ppc_stub_plt_call
       || stub_entry->stub_type == ppc_stub_plt_call_r2save)
     {
@@ -11021,20 +11163,20 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off += (plt->output_offset
              + plt->output_section->vma
              - elf_gp (plt->output_section->owner)
-             - htab->stub_group[stub_entry->id_sec->id].toc_off);
+             - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
       size = plt_stub_size (htab, stub_entry, off);
       if (htab->params->plt_stub_align)
        size += plt_stub_pad (htab, stub_entry, off);
       if (info->emitrelocations)
        {
-         stub_entry->stub_sec->reloc_count
+         stub_entry->group->stub_sec->reloc_count
            += ((PPC_HA (off) != 0)
                + (htab->opd_abi
                   ? 2 + (htab->params->plt_static_chain
                          && PPC_HA (off + 16) == PPC_HA (off))
                   : 1));
-         stub_entry->stub_sec->flags |= SEC_RELOC;
+         stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
     }
   else
@@ -11047,9 +11189,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off = (stub_entry->target_value
             + stub_entry->target_section->output_offset
             + stub_entry->target_section->output_section->vma);
-      off -= (stub_entry->stub_sec->size
-             + stub_entry->stub_sec->output_offset
-             + stub_entry->stub_sec->output_section->vma);
+      off -= (stub_entry->group->stub_sec->size
+             + stub_entry->group->stub_sec->output_offset
+             + stub_entry->group->stub_sec->output_section->vma);
 
       /* Reset the stub type from the plt variant in case we now
         can reach with a shorter stub.  */
@@ -11060,14 +11202,16 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
          r2off = get_r2off (info, stub_entry);
-         if (r2off == 0 && htab->opd_abi)
+         if (r2off == (bfd_vma) -1)
            {
              htab->stub_error = TRUE;
              return FALSE;
            }
-         size = 12;
+         size = 8;
          if (PPC_HA (r2off) != 0)
-           size = 16;
+           size += 4;
+         if (PPC_LO (r2off) != 0)
+           size += 4;
          off -= size - 4;
        }
 
@@ -11077,7 +11221,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
         Do the same for -R objects without function descriptors.  */
       if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
          || (stub_entry->stub_type == ppc_stub_long_branch_r2off
-             && r2off == 0))
+             && r2off == 0
+             && htab->sec_info[stub_entry->target_section->id].toc_off == 0))
        {
          struct ppc_branch_hash_entry *br_entry;
 
@@ -11112,12 +11257,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                 + htab->brlt->output_offset
                 + htab->brlt->output_section->vma
                 - elf_gp (htab->brlt->output_section->owner)
-                - htab->stub_group[stub_entry->id_sec->id].toc_off);
+                - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
          if (info->emitrelocations)
            {
-             stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0);
-             stub_entry->stub_sec->flags |= SEC_RELOC;
+             stub_entry->group->stub_sec->reloc_count
+               += 1 + (PPC_HA (off) != 0);
+             stub_entry->group->stub_sec->flags |= SEC_RELOC;
            }
 
          if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
@@ -11140,12 +11286,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
       else if (info->emitrelocations)
        {
-         stub_entry->stub_sec->reloc_count += 1;
-         stub_entry->stub_sec->flags |= SEC_RELOC;
+         stub_entry->group->stub_sec->reloc_count += 1;
+         stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
     }
 
-  stub_entry->stub_sec->size += size;
+  stub_entry->group->stub_sec->size += size;
   return TRUE;
 }
 
@@ -11156,57 +11302,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 int
 ppc64_elf_setup_section_lists (struct bfd_link_info *info)
 {
-  bfd *input_bfd;
-  int top_id, top_index, id;
-  asection *section;
-  asection **input_list;
+  unsigned int id;
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
     return -1;
 
-  /* Find the top input section id.  */
-  for (input_bfd = info->input_bfds, top_id = 3;
-       input_bfd != NULL;
-       input_bfd = input_bfd->link.next)
-    {
-      for (section = input_bfd->sections;
-          section != NULL;
-          section = section->next)
-       {
-         if (top_id < section->id)
-           top_id = section->id;
-       }
-    }
-
-  htab->top_id = top_id;
-  amt = sizeof (struct map_stub) * (top_id + 1);
-  htab->stub_group = bfd_zmalloc (amt);
-  if (htab->stub_group == NULL)
+  htab->sec_info_arr_size = bfd_get_next_section_id ();
+  amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size);
+  htab->sec_info = bfd_zmalloc (amt);
+  if (htab->sec_info == NULL)
     return -1;
 
   /* Set toc_off for com, und, abs and ind sections.  */
   for (id = 0; id < 3; id++)
-    htab->stub_group[id].toc_off = TOC_BASE_OFF;
-
-  /* We can't use output_bfd->section_count here to find the top output
-     section index as some sections may have been removed, and
-     strip_excluded_output_sections doesn't renumber the indices.  */
-  for (section = info->output_bfd->sections, top_index = 0;
-       section != NULL;
-       section = section->next)
-    {
-      if (top_index < section->index)
-       top_index = section->index;
-    }
-
-  htab->top_index = top_index;
-  amt = sizeof (asection *) * (top_index + 1);
-  input_list = bfd_zmalloc (amt);
-  htab->input_list = input_list;
-  if (input_list == NULL)
-    return -1;
+    htab->sec_info[id].toc_off = TOC_BASE_OFF;
 
   return 1;
 }
@@ -11257,6 +11368,7 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
          addr = (htab->toc_first_sec->output_offset
                  + htab->toc_first_sec->output_section->vma);
          htab->toc_curr = addr;
+         htab->toc_curr &= -TOC_BASE_ALIGN;
        }
 
       /* toc_curr is the base address of this toc group.  Set elf_gp
@@ -11449,7 +11561,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  htab->elf.irelplt->size += rel_size;
                  htab->got_reli_size += rel_size;
                }
-             else if (info->shared)
+             else if (bfd_link_pic (info))
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += rel_size;
@@ -11474,7 +11586,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
          asection *s = ppc64_elf_tdata (ibfd)->got;
          ent->got.offset = s->size;
          s->size += 16;
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              asection *srel = ppc64_elf_tdata (ibfd)->relgot;
              srel->size += sizeof (Elf64_External_Rela);
@@ -11637,7 +11749,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
                {
                  long adjust;
 
-                 adjust = opd->adjust[OPD_NDX (sym->st_value)];
+                 adjust = opd->adjust[OPD_NDX (sym_value)];
                  if (adjust == -1)
                    /* Assume deleted functions won't ever be called.  */
                    continue;
@@ -11754,15 +11866,13 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
     return FALSE;
 
   if ((isec->output_section->flags & SEC_CODE) != 0
-      && isec->output_section->index <= htab->top_index)
+      && isec->output_section->id < htab->sec_info_arr_size)
     {
-      asection **list = htab->input_list + isec->output_section->index;
-      /* Steal the link_sec pointer for our list.  */
-#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
       /* This happens to make the list in reverse order,
         which is what we want.  */
-      PREV_SEC (isec) = *list;
-      *list = isec;
+      htab->sec_info[isec->id].u.list
+       = htab->sec_info[isec->output_section->id].u.list;
+      htab->sec_info[isec->output_section->id].u.list = isec;
     }
 
   if (htab->multi_toc_needed)
@@ -11786,7 +11896,7 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
        htab->toc_curr = elf_gp (isec->owner);
     }
 
-  htab->stub_group[isec->id].toc_off = htab->toc_curr;
+  htab->sec_info[isec->id].toc_off = htab->toc_curr;
   return TRUE;
 }
 
@@ -11808,8 +11918,8 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
        if (i->has_toc_reloc)
          {
            if (toc_off == 0)
-             toc_off = htab->stub_group[i->id].toc_off;
-           else if (toc_off != htab->stub_group[i->id].toc_off)
+             toc_off = htab->sec_info[i->id].toc_off;
+           else if (toc_off != htab->sec_info[i->id].toc_off)
              return FALSE;
          }
 
@@ -11817,14 +11927,14 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
        for (i = o->map_head.s; i != NULL; i = i->map_head.s)
          if (i->makes_toc_func_call)
            {
-             toc_off = htab->stub_group[i->id].toc_off;
+             toc_off = htab->sec_info[i->id].toc_off;
              break;
            }
 
       /* Make sure the whole pasted function uses the same toc offset.  */
       if (toc_off != 0)
        for (i = o->map_head.s; i != NULL; i = i->map_head.s)
-         htab->stub_group[i->id].toc_off = toc_off;
+         htab->sec_info[i->id].toc_off = toc_off;
     }
   return TRUE;
 }
@@ -11843,15 +11953,20 @@ ppc64_elf_check_init_fini (struct bfd_link_info *info)
    _init and _fini functions into multiple parts.  Putting a stub in
    the middle of a function is not a good idea.  */
 
-static void
-group_sections (struct ppc_link_hash_table *htab,
+static bfd_boolean
+group_sections (struct bfd_link_info *info,
                bfd_size_type stub_group_size,
                bfd_boolean stubs_always_before_branch)
 {
-  asection **list;
+  struct ppc_link_hash_table *htab;
+  asection *osec;
   bfd_size_type stub14_group_size;
   bfd_boolean suppress_size_errors;
 
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   suppress_size_errors = FALSE;
   stub14_group_size = stub_group_size >> 10;
   if (stub_group_size == 1)
@@ -11870,10 +11985,14 @@ group_sections (struct ppc_link_hash_table *htab,
       suppress_size_errors = TRUE;
     }
 
-  list = htab->input_list + htab->top_index;
-  do
+  for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next)
     {
-      asection *tail = *list;
+      asection *tail;
+
+      if (osec->id >= htab->sec_info_arr_size)
+       continue;
+
+      tail = htab->sec_info[osec->id].u.list;
       while (tail != NULL)
        {
          asection *curr;
@@ -11881,6 +12000,7 @@ group_sections (struct ppc_link_hash_table *htab,
          bfd_size_type total;
          bfd_boolean big_sec;
          bfd_vma curr_toc;
+         struct map_stub *group;
 
          curr = tail;
          total = tail->size;
@@ -11890,14 +12010,14 @@ group_sections (struct ppc_link_hash_table *htab,
          if (big_sec && !suppress_size_errors)
            (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
                                     tail->owner, tail);
-         curr_toc = htab->stub_group[tail->id].toc_off;
+         curr_toc = htab->sec_info[tail->id].toc_off;
 
-         while ((prev = PREV_SEC (curr)) != NULL
+         while ((prev = htab->sec_info[curr->id].u.list) != NULL
                 && ((total += curr->output_offset - prev->output_offset)
                     < (ppc64_elf_section_data (prev) != NULL
                        && ppc64_elf_section_data (prev)->has_14bit_branch
                        ? stub14_group_size : stub_group_size))
-                && htab->stub_group[prev->id].toc_off == curr_toc)
+                && htab->sec_info[prev->id].toc_off == curr_toc)
            curr = prev;
 
          /* OK, the size from the start of CURR to the end is less
@@ -11910,11 +12030,19 @@ group_sections (struct ppc_link_hash_table *htab,
             only break if stubs added make the total size more than
             2^25, ie. for the default stub_group_size, if stubs total
             more than 2097152 bytes, or nearly 75000 plt call stubs.  */
+         group = bfd_alloc (curr->owner, sizeof (*group));
+         if (group == NULL)
+           return FALSE;
+         group->link_sec = curr;
+         group->stub_sec = NULL;
+         group->needs_save_res = 0;
+         group->next = htab->group;
+         htab->group = group;
          do
            {
-             prev = PREV_SEC (tail);
+             prev = htab->sec_info[tail->id].u.list;
              /* Set up this stub group.  */
-             htab->stub_group[tail->id].link_sec = curr;
+             htab->sec_info[tail->id].u.group = group;
            }
          while (tail != curr && (tail = prev) != NULL);
 
@@ -11931,19 +12059,17 @@ group_sections (struct ppc_link_hash_table *htab,
                         < (ppc64_elf_section_data (prev) != NULL
                            && ppc64_elf_section_data (prev)->has_14bit_branch
                            ? stub14_group_size : stub_group_size))
-                    && htab->stub_group[prev->id].toc_off == curr_toc)
+                    && htab->sec_info[prev->id].toc_off == curr_toc)
                {
                  tail = prev;
-                 prev = PREV_SEC (tail);
-                 htab->stub_group[tail->id].link_sec = curr;
+                 prev = htab->sec_info[tail->id].u.list;
+                 htab->sec_info[tail->id].u.group = group;
                }
            }
          tail = prev;
        }
     }
-  while (list-- != htab->input_list);
-  free (htab->input_list);
-#undef PREV_SEC
+  return TRUE;
 }
 
 static const unsigned char glink_eh_frame_cie[] =
@@ -11998,7 +12124,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
   if (htab == NULL)
     return FALSE;
 
-  if (htab->params->plt_thread_safe == -1 && !info->executable)
+  if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
     htab->params->plt_thread_safe = 1;
   if (!htab->opd_abi)
     htab->params->plt_thread_safe = 0;
@@ -12032,7 +12158,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
        };
       unsigned i;
 
-      for (i = 0; i < sizeof (thread_starter)/ sizeof (thread_starter[0]); i++)
+      for (i = 0; i < ARRAY_SIZE (thread_starter); i++)
        {
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, thread_starter[i],
@@ -12048,12 +12174,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
   else
     stub_group_size = htab->params->group_size;
 
-  group_sections (htab, stub_group_size, stubs_always_before_branch);
+  if (!group_sections (info, stub_group_size, stubs_always_before_branch))
+    return FALSE;
 
   while (1)
     {
       bfd *input_bfd;
       unsigned int bfd_indx;
+      struct map_stub *group;
       asection *stub_sec;
 
       htab->stub_iteration += 1;
@@ -12155,7 +12283,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                  if (hash == NULL)
                    {
                      sym_value = sym->st_value;
-                     ok_dest = TRUE;
+                     if (sym_sec != NULL
+                         && sym_sec->output_section != NULL)
+                       ok_dest = TRUE;
                    }
                  else if (hash->elf.root.type == bfd_link_hash_defined
                           || hash->elf.root.type == bfd_link_hash_defweak)
@@ -12251,8 +12381,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         fact a call needing a TOC adjustment.  */
                      if (code_sec != NULL
                          && code_sec->output_section != NULL
-                         && (htab->stub_group[code_sec->id].toc_off
-                             != htab->stub_group[section->id].toc_off)
+                         && (htab->sec_info[code_sec->id].toc_off
+                             != htab->sec_info[section->id].toc_off)
                          && (code_sec->has_toc_reloc
                              || code_sec->makes_toc_func_call))
                        stub_type = ppc_stub_long_branch_r2off;
@@ -12292,7 +12422,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    stub_type = ppc_stub_plt_call_r2save;
 
                  /* Support for grouping stub sections.  */
-                 id_sec = htab->stub_group[section->id].link_sec;
+                 id_sec = htab->sec_info[section->id].u.group->link_sec;
 
                  /* Get the name of this stub.  */
                  stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
@@ -12381,6 +12511,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
+      for (group = htab->group; group != NULL; group = group->next)
+       if (group->needs_save_res)
+         group->stub_sec->size += htab->sfpr->size;
+
       if (info->emitrelocations
          && htab->glink != NULL && htab->glink->size != 0)
        {
@@ -12418,7 +12552,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
            stub_sec->size = ((stub_sec->size
                               + (1 << htab->params->plt_stub_align) - 1)
-                             & (-1 << htab->params->plt_stub_align));
+                             & -(1 << htab->params->plt_stub_align));
 
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
@@ -12504,7 +12638,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          *p++ = DW_CFA_advance_loc + 1;
          *p++ = DW_CFA_register;
          *p++ = 65;
-         *p++ = 12;
+         *p++ = htab->opd_abi ? 12 : 0;
          *p++ = DW_CFA_advance_loc + 4;
          *p++ = DW_CFA_restore_extended;
          *p++ = 65;
@@ -12535,7 +12669,35 @@ bfd_vma
 ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 {
   asection *s;
-  bfd_vma TOCstart;
+  bfd_vma TOCstart, adjust;
+
+  if (info != NULL)
+    {
+      struct elf_link_hash_entry *h;
+      struct elf_link_hash_table *htab = elf_hash_table (info);
+
+      if (is_elf_hash_table (htab)
+         && htab->hgot != NULL)
+       h = htab->hgot;
+      else
+       {
+         h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE);
+         if (is_elf_hash_table (htab))
+           htab->hgot = h;
+       }
+      if (h != NULL
+         && h->root.type == bfd_link_hash_defined
+         && !h->root.linker_def
+         && (!is_elf_hash_table (htab)
+             || h->def_regular))
+       {
+         TOCstart = (h->root.u.def.value - TOC_BASE_OFF
+                     + h->root.u.def.section->output_offset
+                     + h->root.u.def.section->output_section->vma);
+         _bfd_set_gp_value (obfd, TOCstart);
+         return TOCstart;
+       }
+    }
 
   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
      order.  The TOC starts where the first of these sections starts.  */
@@ -12583,6 +12745,9 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
   if (s != NULL)
     TOCstart = s->output_section->vma + s->output_offset;
 
+  /* Force alignment.  */
+  adjust = TOCstart & (TOC_BASE_ALIGN - 1);
+  TOCstart -= adjust;
   _bfd_set_gp_value (obfd, TOCstart);
 
   if (info != NULL && s != NULL)
@@ -12593,7 +12758,7 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
        {
          if (htab->elf.hgot != NULL)
            {
-             htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
+             htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust;
              htab->elf.hgot->root.u.def.section = s;
            }
        }
@@ -12601,8 +12766,8 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
        {
          struct bfd_link_hash_entry *bh = NULL;
          _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
-                                           s, TOC_BASE_OFF, NULL, FALSE,
-                                           FALSE, &bh);
+                                           s, TOC_BASE_OFF - adjust,
+                                           NULL, FALSE, FALSE, &bh);
        }
     }
   return TOCstart;
@@ -12710,6 +12875,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
                       char **stats)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  struct map_stub *group;
   asection *stub_sec;
   bfd_byte *p;
   int stub_sec_count = 0;
@@ -12883,6 +13049,23 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
+  for (group = htab->group; group != NULL; group = group->next)
+    if (group->needs_save_res)
+      {
+       stub_sec = group->stub_sec;
+       memcpy (stub_sec->contents + stub_sec->size, htab->sfpr->contents,
+               htab->sfpr->size);
+       if (htab->params->emit_stub_syms)
+         {
+           unsigned int i;
+
+           for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+             if (!sfpr_define (info, &save_res_funcs[i], stub_sec))
+               return FALSE;
+         }
+       stub_sec->size += htab->sfpr->size;
+      }
+
   if (htab->relbrlt != NULL)
     htab->relbrlt->reloc_count = 0;
 
@@ -12893,7 +13076,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
        stub_sec->size = ((stub_sec->size
                           + (1 << htab->params->plt_stub_align) - 1)
-                         & (-1 << htab->params->plt_stub_align));
+                         & -(1 << htab->params->plt_stub_align));
 
   for (stub_sec = htab->params->stub_bfd->sections;
        stub_sec != NULL;
@@ -13034,6 +13217,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *wrel;
   Elf_Internal_Rela *relend;
   Elf_Internal_Rela outrel;
   bfd_byte *loc;
@@ -13065,9 +13249,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   sym_hashes = elf_sym_hashes (input_bfd);
   is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
 
-  rel = relocs;
+  rel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (; rel < relend; wrel++, rel++)
     {
       enum elf_ppc64_reloc_type r_type;
       bfd_vma addend;
@@ -13091,10 +13275,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
-      const Elf_Internal_Rela orig_rel = *rel;
+      Elf_Internal_Rela orig_rel;
       reloc_howto_type *howto;
       struct reloc_howto_struct alt_howto;
 
+    again:
+      orig_rel = *rel;
+
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
 
@@ -13102,10 +13289,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
         symbol of the previous ADDR64 reloc.  The symbol gives us the
         proper TOC base to use.  */
       if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
-         && rel != relocs
-         && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64
+         && wrel != relocs
+         && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64
          && is_opd)
-       r_symndx = ELF64_R_SYM (rel[-1].r_info);
+       r_symndx = ELF64_R_SYM (wrel[-1].r_info);
 
       sym = NULL;
       sec = NULL;
@@ -13186,18 +13373,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       h = (struct ppc_link_hash_entry *) h_elf;
 
       if (sec != NULL && discarded_section (sec))
-       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
-                                        rel, 1, relend,
-                                        ppc64_elf_howto_table[r_type], 0,
-                                        contents);
+       {
+         _bfd_clear_contents (ppc64_elf_howto_table[r_type],
+                              input_bfd, input_section,
+                              contents + rel->r_offset);
+         wrel->r_offset = rel->r_offset;
+         wrel->r_info = 0;
+         wrel->r_addend = 0;
+
+         /* For ld -r, remove relocations in debug sections against
+            sections 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)
+             && (input_section->flags & SEC_DEBUGGING))
+           wrel--;
 
-      if (info->relocatable)
-       continue;
+         continue;
+       }
+
+      if (bfd_link_relocatable (info))
+       goto copy_reloc;
 
       if (h != NULL && &h->elf == htab->elf.hgot)
        {
-         relocation = (TOCstart
-                       + htab->stub_group[input_section->id].toc_off);
+         relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
          sec = bfd_abs_section_ptr;
          unresolved_reloc = FALSE;
        }
@@ -13353,10 +13553,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && (tls_mask & TLS_TPREL) == 0)
            {
            toctprel:
-             insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+             insn = bfd_get_32 (output_bfd,
+                                contents + rel->r_offset - d_offset);
              insn &= 31 << 21;
              insn |= 0x3c0d0000;       /* addis 0,13,0 */
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+             bfd_put_32 (output_bfd, insn,
+                         contents + rel->r_offset - d_offset);
              r_type = R_PPC64_TPREL16_HA;
              if (toc_symndx != 0)
                {
@@ -13364,8 +13566,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
-                 rel--;
-                 continue;
+                 goto again;
                }
              else
                rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -13391,8 +13592,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
-                 rel--;
-                 continue;
+                 goto again;
                }
              else
                rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -13531,8 +13731,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                {
                  /* We changed the symbol.  Start over in order
                     to get h, sym, sec etc. right.  */
-                 rel--;
-                 continue;
+                 goto again;
                }
            }
          break;
@@ -13576,10 +13775,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
              bfd_put_32 (output_bfd, insn2, contents + offset);
              if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
-               {
-                 rel--;
-                 continue;
-               }
+               goto again;
            }
          break;
 
@@ -13621,8 +13817,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  insn2 = NOP;
                }
              bfd_put_32 (output_bfd, insn2, contents + offset);
-             rel--;
-             continue;
+             goto again;
            }
          break;
 
@@ -13663,6 +13858,52 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC64_ENTRY:
+         relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
+         if (!bfd_link_pic (info)
+             && !info->traditional_format
+             && relocation + 0x80008000 <= 0xffffffff)
+           {
+             unsigned int insn1, insn2;
+
+             insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+             if ((insn1 & ~0xfffc) == LD_R2_0R12
+                 && insn2 == ADD_R2_R2_R12)
+               {
+                 bfd_put_32 (output_bfd,
+                             LIS_R2 + PPC_HA (relocation),
+                             contents + rel->r_offset);
+                 bfd_put_32 (output_bfd,
+                             ADDI_R2_R2 + PPC_LO (relocation),
+                             contents + rel->r_offset + 4);
+               }
+           }
+         else
+           {
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             if (relocation + 0x80008000 <= 0xffffffff)
+               {
+                 unsigned int insn1, insn2;
+
+                 insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset);
+                 insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+                 if ((insn1 & ~0xfffc) == LD_R2_0R12
+                     && insn2 == ADD_R2_R2_R12)
+                   {
+                     bfd_put_32 (output_bfd,
+                                 ADDIS_R2_R12 + PPC_HA (relocation),
+                                 contents + rel->r_offset);
+                     bfd_put_32 (output_bfd,
+                                 ADDI_R2_R2 + PPC_LO (relocation),
+                                 contents + rel->r_offset + 4);
+                   }
+               }
+           }
+         break;
+
        case R_PPC64_REL16_HA:
          /* If we are generating a non-PIC executable, edit
             .  0:      addis 2,12,.TOC.-0b@ha
@@ -13671,8 +13912,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             .          lis 2,.TOC.@ha
             .          addi 2,2,.TOC.@l
             if .TOC. is in range.  */
-         if (!info->shared
+         if (!bfd_link_pic (info)
              && !info->traditional_format
+             && !htab->opd_abi
+             && rel->r_addend == d_offset
              && h != NULL && &h->elf == htab->elf.hgot
              && rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
@@ -13684,15 +13927,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              bfd_vma offset = rel->r_offset - d_offset;
              insn1 = bfd_get_32 (output_bfd, contents + offset);
              insn2 = bfd_get_32 (output_bfd, contents + offset + 4);
-             if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */
-                 && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */)
+             if ((insn1 & 0xffff0000) == ADDIS_R2_R12
+                 && (insn2 & 0xffff0000) == ADDI_R2_R2)
                {
                  r_type = R_PPC64_ADDR16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
                  rel->r_addend -= d_offset;
                  rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO);
                  rel[1].r_addend -= d_offset + 4;
-                 bfd_put_32 (output_bfd, 0x3c400000, contents + offset);
+                 bfd_put_32 (output_bfd, LIS_R2, contents + offset);
                }
            }
          break;
@@ -13784,7 +14027,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          if (h != NULL
                              && (h == htab->tls_get_addr_fd
                                  || h == htab->tls_get_addr)
-                             && !htab->params->no_tls_get_addr_opt)
+                             && htab->params->tls_get_addr_opt)
                            {
                              /* Special stub used, leave nop alone.  */
                            }
@@ -13904,9 +14147,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              /* Munge up the value and addend so that we call the stub
                 rather than the procedure directly.  */
-             relocation = (stub_entry->stub_offset
-                           + stub_entry->stub_sec->output_offset
-                           + stub_entry->stub_sec->output_section->vma);
+             asection *stub_sec = stub_entry->group->stub_sec;
+
+             if (stub_entry->stub_type == ppc_stub_save_res)
+               relocation += (stub_sec->output_offset
+                              + stub_sec->output_section->vma
+                              + stub_sec->size - htab->sfpr->size
+                              - htab->sfpr->output_offset
+                              - htab->sfpr->output_section->vma);
+             else
+               relocation = (stub_entry->stub_offset
+                             + stub_sec->output_offset
+                             + stub_sec->output_section->vma);
              addend = 0;
              reloc_dest = DEST_STUB;
 
@@ -13955,7 +14207,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   && addend == 0)
            {
              bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
-             continue;
+             goto copy_reloc;
            }
          break;
        }
@@ -13971,7 +14223,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
@@ -13980,7 +14232,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOCSAVE:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
-         continue;
+       case R_PPC64_ENTRY:
+         goto copy_reloc;
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
             address in the GOT as relocation value instead of the
@@ -14040,9 +14293,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (h != NULL)
                  {
                    bfd_boolean dyn = htab->elf.dynamic_sections_created;
-                   if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
+                   if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
                                                          &h->elf)
-                       || (info->shared
+                       || (bfd_link_pic (info)
                            && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
                      /* This is actually a static link, or it is a
                         -Bsymbolic link and the symbol is defined
@@ -14101,7 +14354,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if (ifunc)
                  relgot = htab->elf.irelplt;
-               else if ((info->shared || indx != 0)
+               else if ((bfd_link_pic (info) || indx != 0)
                         && (h == NULL
                             || (tls_type == (TLS_TLS | TLS_LD)
                                 && !h->elf.def_dynamic)
@@ -14203,7 +14456,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              abort ();
 
            relocation = got->output_section->vma + got->output_offset + off;
-           addend = -(TOCstart + htab->stub_group[input_section->id].toc_off);
+           addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
          }
          break;
 
@@ -14214,41 +14467,54 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLT64:
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
+         {
+           struct plt_entry **plt_list = NULL;
+           if (h != NULL)
+             plt_list = &h->elf.plt.plist;
+           else if (local_got_ents != NULL)
+             {
+               struct plt_entry **local_plt = (struct plt_entry **)
+                 (local_got_ents + symtab_hdr->sh_info);
+               unsigned char *local_got_tls_masks = (unsigned char *)
+                 (local_plt + symtab_hdr->sh_info);
+               if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+                 plt_list = local_plt + r_symndx;
+             }
+           if (plt_list)
+             {
+               struct plt_entry *ent;
 
-         /* Resolve a PLT reloc against a local symbol directly,
-            without using the procedure linkage table.  */
-         if (h == NULL)
-           break;
-
-         /* It's possible that we didn't make a PLT entry for this
-            symbol.  This happens when statically linking PIC code,
-            or when using -Bsymbolic.  Go find a match if there is a
-            PLT entry.  */
-         if (htab->elf.splt != NULL)
-           {
-             struct plt_entry *ent;
-             for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
-               if (ent->plt.offset != (bfd_vma) -1
-                   && ent->addend == orig_rel.r_addend)
-                 {
-                   relocation = (htab->elf.splt->output_section->vma
-                                 + htab->elf.splt->output_offset
-                                 + ent->plt.offset);
-                   unresolved_reloc = FALSE;
-                   break;
-                 }
-           }
+               for (ent = *plt_list; ent != NULL; ent = ent->next)
+                 if (ent->plt.offset != (bfd_vma) -1
+                     && ent->addend == orig_rel.r_addend)
+                   {
+                     asection *plt;
+
+                     plt = htab->elf.splt;
+                     if (!htab->elf.dynamic_sections_created
+                         || h == NULL
+                         || h->elf.dynindx == -1)
+                       plt = htab->elf.iplt;
+                     relocation = (plt->output_section->vma
+                                   + plt->output_offset
+                                   + ent->plt.offset);
+                     addend = 0;
+                     unresolved_reloc = FALSE;
+                     break;
+                   }
+             }
+         }
          break;
 
        case R_PPC64_TOC:
          /* Relocation value is TOC base.  */
          relocation = TOCstart;
          if (r_symndx == STN_UNDEF)
-           relocation += htab->stub_group[input_section->id].toc_off;
+           relocation += htab->sec_info[input_section->id].toc_off;
          else if (unresolved_reloc)
            ;
-         else if (sec != NULL && sec->id <= htab->top_id)
-           relocation += htab->stub_group[sec->id].toc_off;
+         else if (sec != NULL && sec->id < htab->sec_info_arr_size)
+           relocation += htab->sec_info[sec->id].toc_off;
          else
            unresolved_reloc = TRUE;
          goto dodyn;
@@ -14263,7 +14529,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC16_DS:
        case R_PPC64_TOC16_LO_DS:
        case R_PPC64_TOC16_HA:
-         addend -= TOCstart + htab->stub_group[input_section->id].toc_off;
+         addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
          break;
 
          /* Relocate against the beginning of the section.  */
@@ -14281,6 +14547,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_REL16_LO:
        case R_PPC64_REL16_HI:
        case R_PPC64_REL16_HA:
+       case R_PPC64_REL16DX_HA:
          break;
 
        case R_PPC64_REL14:
@@ -14319,7 +14586,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + TP_OFFSET;
-         if (info->shared)
+         if (bfd_link_pic (info))
            /* The TPREL16 relocs shouldn't really be used in shared
               libs as they will result in DT_TEXTREL being set, but
               support them anyway.  */
@@ -14396,19 +14663,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (NO_OPD_RELOCS && is_opd)
            break;
 
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                   || h->elf.root.type != bfd_link_hash_undefweak)
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && h->elf.dynindx != -1
                  && !h->elf.non_got_ref
                  && !h->elf.def_regular)
-             || (!info->shared
+             || (!bfd_link_pic (info)
                  && (h != NULL
                      ? h->elf.type == STT_GNU_IFUNC
                      : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
@@ -14616,7 +14883,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          bfd_set_error (bfd_error_invalid_operation);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
        }
 
       /* Multi-instruction sequences that access the TOC can be
@@ -14693,6 +14960,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_REL16_HA:
+       case R_PPC64_REL16DX_HA:
        case R_PPC64_ADDR16_HA:
        case R_PPC64_ADDR16_HIGHA:
        case R_PPC64_ADDR16_HIGHERA:
@@ -14748,16 +15016,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_DTPREL16_LO_DS:
          insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
          mask = 3;
-         /* If this reloc is against an lq insn, then the value must be
-            a multiple of 16.  This is somewhat of a hack, but the
-            "correct" way to do this by defining _DQ forms of all the
-            _DS relocs bloats all reloc switches in this file.  It
-            doesn't seem to make much sense to use any of these relocs
-            in data, so testing the insn should be safe.  */
-         if ((insn & (0x3f << 26)) == (56u << 26))
+         /* If this reloc is against an lq, lxv, or stxv insn, then
+            the value must be a multiple of 16.  This is somewhat of
+            a hack, but the "correct" way to do this by defining _DQ
+            forms of all the _DS relocs bloats all reloc switches in
+            this file.  It doesn't make much sense to use these
+            relocs in data, so testing the insn should be safe.  */
+         if ((insn & (0x3f << 26)) == (56u << 26)
+             || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1))
            mask = 15;
-         if (((relocation + addend) & mask) != 0)
+         relocation += addend;
+         addend = insn & (mask ^ 3);
+         if ((relocation & mask) != 0)
            {
+             relocation ^= relocation & mask;
              info->callbacks->einfo
                (_("%P: %H: error: %s not a multiple of %u\n"),
                 input_bfd, input_section, rel->r_offset,
@@ -14765,7 +15037,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
              ret = FALSE;
-             continue;
+             goto copy_reloc;
            }
          break;
        }
@@ -14815,8 +15087,30 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
        }
 
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                   rel->r_offset, relocation, addend);
+      if (r_type == R_PPC64_REL16DX_HA)
+       {
+         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         if (rel->r_offset + 4 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             relocation += addend;
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             relocation = (bfd_signed_vma) relocation >> 16;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~0x1fffc1;
+             insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+             r = bfd_reloc_ok;
+             if (relocation + 0x8000 > 0xffff)
+               r = bfd_reloc_overflow;
+           }
+       }
+      else
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
@@ -14864,6 +15158,29 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (more_info != NULL)
            free (more_info);
        }
+    copy_reloc:
+      if (wrel != rel)
+       *wrel = *rel;
+    }
+
+  if (wrel != rel)
+    {
+      Elf_Internal_Shdr *rel_hdr;
+      size_t deleted = rel - wrel;
+
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      if (rel_hdr->sh_size == 0)
+       {
+         /* It is too late to remove an empty reloc section.  Leave
+            one NONE reloc.
+            ??? What is wrong with an empty section???  */
+         rel_hdr->sh_size = rel_hdr->sh_entsize;
+         deleted -= 1;
+       }
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      input_section->reloc_count -= deleted;
     }
 
   /* If we're emitting relocations, then shortly after this function
@@ -14871,7 +15188,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
      adjusted.  Worse, reloc symbol indices will be for the output
      file rather than the input.  Save a copy of the relocs for
      opd_entry_value.  */
-  if (is_opd && (info->emitrelocations || info->relocatable))
+  if (is_opd && (info->emitrelocations || bfd_link_relocatable (info)))
     {
       bfd_size_type amt;
       amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
@@ -14906,7 +15223,7 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
     return 1;
 
   value = elfsym->st_value - input_sec->output_offset;
-  if (!info->relocatable)
+  if (!bfd_link_relocatable (info))
     value -= input_sec->output_section->vma;
 
   adjust = opd->adjust[OPD_NDX (value)];