Frame static link: Handle null pointer.
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 136887f25e2d7de673450f44a0ae3d065dd77d19..41fe87919a9840cf4c218ba2f585cf2d3cafc97f 100644 (file)
@@ -1,6 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010, 2011, 2012 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.
@@ -57,15 +56,15 @@ static bfd_reloc_status_type ppc64_elf_unhandled_reloc
 static bfd_vma opd_entry_value
   (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
 
-#define TARGET_LITTLE_SYM      bfd_elf64_powerpcle_vec
+#define TARGET_LITTLE_SYM      powerpc_elf64_le_vec
 #define TARGET_LITTLE_NAME     "elf64-powerpcle"
-#define TARGET_BIG_SYM         bfd_elf64_powerpc_vec
+#define TARGET_BIG_SYM         powerpc_elf64_vec
 #define TARGET_BIG_NAME                "elf64-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
 #define ELF_TARGET_ID          PPC64_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
-#define ELF_COMMONPAGESIZE     0x1000
+#define ELF_COMMONPAGESIZE     0x10000
 #define elf_info_to_howto      ppc64_elf_info_to_howto
 
 #define elf_backend_want_got_sym 0
@@ -85,7 +84,6 @@ static bfd_vma opd_entry_value
 #define bfd_elf64_bfd_print_private_bfd_data  ppc64_elf_print_private_bfd_data
 #define bfd_elf64_new_section_hook           ppc64_elf_new_section_hook
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
-#define bfd_elf64_bfd_link_hash_table_free    ppc64_elf_link_hash_table_free
 #define bfd_elf64_get_synthetic_symtab       ppc64_elf_get_synthetic_symtab
 #define bfd_elf64_bfd_link_just_syms         ppc64_elf_link_just_syms
 
@@ -96,7 +94,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
 #define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
 #define elf_backend_add_symbol_hook          ppc64_elf_add_symbol_hook
-#define elf_backend_check_directives         ppc64_elf_process_dot_syms
+#define elf_backend_check_directives         ppc64_elf_before_check_relocs
 #define elf_backend_notice_as_needed         ppc64_elf_notice_as_needed
 #define elf_backend_archive_symbol_lookup     ppc64_elf_archive_symbol_lookup
 #define elf_backend_check_relocs             ppc64_elf_check_relocs
@@ -118,7 +116,6 @@ static bfd_vma opd_entry_value
 #define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections         ppc64_elf_special_sections
-#define elf_backend_post_process_headers      _bfd_elf_set_osabi
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
 
 /* The name of the dynamic interpreter.  This is put in the .interp
@@ -134,13 +131,15 @@ static bfd_vma opd_entry_value
 /* Offsets to some stack save slots.  */
 #define STK_LR 16
 #define STK_TOC(htab) (htab->opd_abi ? 40 : 24)
-/* This one is dodgy.  ABIv2 does not have a linker word, so use the
+/* This one is dodgy.  ELFv2 does not have a linker word, so use the
    CR save slot.  Used only by optimised __tls_get_addr call stub,
    relying on __tls_get_addr_opt not saving CR..  */
 #define STK_LINKER(htab) (htab->opd_abi ? 32 : 8)
 
 /* 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
@@ -174,7 +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 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) */
 
@@ -237,6 +241,23 @@ static bfd_vma opd_entry_value
 #ifndef NO_OPD_RELOCS
 #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)
+{
+  return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI;
+}
+
+static inline void
+set_abiversion (bfd *abfd, int ver)
+{
+  elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI;
+  elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI;
+}
 \f
 #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
 
@@ -247,8 +268,8 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
   /* This reloc does nothing.  */
   HOWTO (R_PPC64_NONE,         /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
@@ -359,7 +380,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_branch_reloc, /* special_function */
         "R_PPC64_ADDR14",      /* name */
         FALSE,                 /* partial_inplace */
@@ -376,7 +397,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRTAKEN",/* name */
         FALSE,                 /* partial_inplace */
@@ -393,7 +414,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRNTAKEN",/* name */
         FALSE,                 /* partial_inplace */
@@ -634,7 +655,6 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         32,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        /* FIXME: Verify.  Was complain_overflow_bitfield.  */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL32",       /* name */
@@ -729,7 +749,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF",     /* name */
         FALSE,                 /* partial_inplace */
@@ -1017,7 +1037,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         64,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_toc64_reloc, /* special_function */
         "R_PPC64_TOC",         /* name */
         FALSE,                 /* partial_inplace */
@@ -1105,7 +1125,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_DS",   /* name */
         FALSE,                 /* partial_inplace */
@@ -1180,7 +1200,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_DS",  /* name */
         FALSE,                 /* partial_inplace */
@@ -1952,7 +1972,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL16",       /* name */
         FALSE,                 /* partial_inplace */
@@ -2006,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 */
@@ -2096,6 +2131,36 @@ 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 */
+        4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_ADDR64_LOCAL", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,        /* type */
         0,                     /* rightshift */
@@ -2136,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];
     }
 }
@@ -2384,6 +2446,12 @@ 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;
       break;
     case BFD_RELOC_VTABLE_ENTRY:               r = R_PPC64_GNU_VTENTRY;
@@ -2399,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];
@@ -2422,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);
@@ -2439,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.  */
@@ -2450,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
@@ -2473,6 +2565,30 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                                      + symbol->section->output_section->vma
                                      + symbol->section->output_offset);
     }
+  else
+    {
+      elf_symbol_type *elfsym = (elf_symbol_type *) symbol;
+
+      if (symbol->section->owner != abfd
+         && symbol->section->owner != NULL
+         && abiversion (symbol->section->owner) >= 2)
+       {
+         unsigned int i;
+
+         for (i = 0; i < symbol->section->owner->symcount; ++i)
+           {
+             asymbol *symdef = symbol->section->owner->outsymbols[i];
+
+             if (strcmp (symdef->name, symbol->name) == 0)
+               {
+                 elfsym = (elf_symbol_type *) symdef;
+                 break;
+               }
+           }
+       }
+      reloc_entry->addend
+       += PPC64_LOCAL_ENTRY_OFFSET (elfsym->internal_elf_sym.st_other);
+    }
   return bfd_reloc_continue;
 }
 
@@ -2904,7 +3020,9 @@ struct _ppc64_elf_section_data
 
   union
   {
-    /* An array with one entry for each opd function descriptor.  */
+    /* An array with one entry for each opd function descriptor,
+       and some spares since opd entries may be either 16 or 24 bytes.  */
+#define OPD_NDX(OFF) ((OFF) >> 4)
     struct _opd_sec_data
     {
       /* Points to the function code section for local opd entries.  */
@@ -2961,19 +3079,6 @@ get_opd_info (asection * sec)
     return &ppc64_elf_section_data (sec)->u.opd;
   return NULL;
 }
-
-static inline int
-abiversion (bfd *abfd)
-{
-  return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI;
-}
-
-static inline void
-set_abiversion (bfd *abfd, int ver)
-{
-  elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI;
-  elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI;
-}
 \f
 /* Parameters for the qsort hook.  */
 static bfd_boolean synthetic_relocatable;
@@ -3060,11 +3165,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)
        {
@@ -3107,7 +3212,8 @@ section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
 }
 
 /* Create synthetic symbols, effectively restoring "dot-symbol" function
-   entry syms.  Also generate @plt symbols for the glink branch table.  */
+   entry syms.  Also generate @plt symbols for the glink branch table.
+   Returns count of synthetic symbols in RET or -1 on error.  */
 
 static long
 ppc64_elf_get_synthetic_symtab (bfd *abfd,
@@ -3250,6 +3356,8 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            }
        }
 
+      if (size == 0)
+       goto done;
       s = *ret = bfd_malloc (size);
       if (s == NULL)
        {
@@ -3310,10 +3418,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
       if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents))
        {
+       free_contents_and_exit_err:
+         count = -1;
        free_contents_and_exit:
          if (contents)
            free (contents);
-         count = -1;
          goto done;
        }
 
@@ -3344,7 +3453,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
          void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
 
          if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
-           goto free_contents_and_exit;
+           goto free_contents_and_exit_err;
 
          extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
          swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
@@ -3406,7 +3515,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            {
              slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
              if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
-               goto free_contents_and_exit;
+               goto free_contents_and_exit_err;
 
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
              size += plt_count * sizeof (asymbol);
@@ -3421,9 +3530,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            }
        }
 
+      if (size == 0)
+       goto free_contents_and_exit;
       s = *ret = bfd_malloc (size);
       if (s == NULL)
-       goto free_contents_and_exit;
+       goto free_contents_and_exit_err;
 
       names = (char *) (s + count + plt_count + (resolv_vma != 0));
 
@@ -3669,7 +3780,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);
     }
 }
 
@@ -3748,7 +3859,23 @@ enum ppc_stub_type {
   ppc_stub_plt_branch,
   ppc_stub_plt_branch_r2off,
   ppc_stub_plt_call,
-  ppc_stub_plt_call_r2save
+  ppc_stub_plt_call_r2save,
+  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 {
@@ -3758,8 +3885,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;
@@ -3773,10 +3900,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;
 };
@@ -3840,6 +3963,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.
@@ -3874,41 +4001,40 @@ struct ppc_link_hash_table
   /* Hash table for function prologue tocsave.  */
   htab_t tocsave_htab;
 
-  /* Linker stub bfd.  */
-  bfd *stub_bfd;
-
-  /* Linker call-backs.  */
-  asection * (*add_stub_section) (const char *, asection *);
-  void (*layout_sections_again) (void);
-
-  /* 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.  */
+  /* Various options and other info passed from the linker.  */
+  struct ppc64_elf_params *params;
+
+  /* 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;
@@ -3926,29 +4052,14 @@ struct ppc_link_hash_table
   bfd_size_type got_reli_size;
 
   /* Statistics.  */
-  unsigned long stub_count[ppc_stub_plt_call_r2save];
+  unsigned long stub_count[ppc_stub_global_entry];
 
   /* Number of stubs against global syms.  */
   unsigned long stub_globals;
 
-  /* Alignment of PLT call stubs.  */
-  unsigned int plt_stub_align:4;
-
   /* Set if we're linking code with function descriptors.  */
   unsigned int opd_abi:1;
 
-  /* Set if PLT call stubs should load r11.  */
-  unsigned int plt_static_chain:1;
-
-  /* Set if PLT call stubs need a read-read barrier.  */
-  unsigned int plt_thread_safe:1;
-
-  /* Set if we should emit symbols for stubs.  */
-  unsigned int emit_stub_syms:1;
-
-  /* Set if __tls_get_addr optimization should not be done.  */
-  unsigned int no_tls_get_addr_opt:1;
-
   /* Support for multiple toc sections.  */
   unsigned int do_multi_toc:1;
   unsigned int multi_toc_needed:1;
@@ -3958,7 +4069,7 @@ struct ppc_link_hash_table
   /* Set on error.  */
   unsigned int stub_error:1;
 
-  /* Temp used by ppc64_elf_process_dot_syms.  */
+  /* Temp used by ppc64_elf_before_check_relocs.  */
   unsigned int twiddled_syms:1;
 
   /* Incremented every time we size stubs.  */
@@ -4027,13 +4138,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;
     }
 
@@ -4146,6 +4256,21 @@ tocsave_htab_eq (const void *p1, const void *p2)
   return e1->sec == e2->sec && e1->offset == e2->offset;
 }
 
+/* Destroy a ppc64 ELF linker hash table.  */
+
+static void
+ppc64_elf_link_hash_table_free (bfd *obfd)
+{
+  struct ppc_link_hash_table *htab;
+
+  htab = (struct ppc_link_hash_table *) obfd->link.hash;
+  if (htab->tocsave_htab)
+    htab_delete (htab->tocsave_htab);
+  bfd_hash_table_free (&htab->branch_hash_table);
+  bfd_hash_table_free (&htab->stub_hash_table);
+  _bfd_elf_link_hash_table_free (obfd);
+}
+
 /* Create a ppc64 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
@@ -4169,19 +4294,30 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
   /* Init the stub hash table too.  */
   if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc,
                            sizeof (struct ppc_stub_hash_entry)))
-    return NULL;
+    {
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
 
   /* And the branch hash table.  */
   if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc,
                            sizeof (struct ppc_branch_hash_entry)))
-    return NULL;
+    {
+      bfd_hash_table_free (&htab->stub_hash_table);
+      _bfd_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
 
   htab->tocsave_htab = htab_try_create (1024,
                                        tocsave_htab_hash,
                                        tocsave_htab_eq,
                                        NULL);
   if (htab->tocsave_htab == NULL)
-    return NULL;
+    {
+      ppc64_elf_link_hash_table_free (abfd);
+      return NULL;
+    }
+  htab->elf.root.hash_table_free = ppc64_elf_link_hash_table_free;
 
   /* Initializing two fields of the union is just cosmetic.  We really
      only care about glist, but when compiled on a 32-bit host the
@@ -4199,20 +4335,6 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
   return &htab->elf.root;
 }
 
-/* Free the derived linker hash table.  */
-
-static void
-ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
-{
-  struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash;
-
-  bfd_hash_table_free (&htab->stub_hash_table);
-  bfd_hash_table_free (&htab->branch_hash_table);
-  if (htab->tocsave_htab)
-    htab_delete (htab->tocsave_htab);
-  _bfd_elf_link_hash_table_free (hash);
-}
-
 /* Create sections for linker generated code.  */
 
 static bfd_boolean
@@ -4223,14 +4345,20 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
 
   htab = ppc_hash_table (info);
 
-  /* Create .sfpr for code to save and restore fp regs.  */
   flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
-                                                  flags);
-  if (htab->sfpr == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
-    return FALSE;
+  if (htab->params->save_restore_funcs)
+    {
+      /* Create .sfpr for code to save and restore fp regs.  */
+      htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+                                                      flags);
+      if (htab->sfpr == NULL
+         || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+       return FALSE;
+    }
+
+  if (bfd_link_relocatable (info))
+    return TRUE;
 
   /* Create .glink for lazy dynamic linking support.  */
   htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
@@ -4274,7 +4402,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
@@ -4292,23 +4420,19 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
 /* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
 
 bfd_boolean
-ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
+ppc64_elf_init_stub_bfd (struct bfd_link_info *info,
+                        struct ppc64_elf_params *params)
 {
   struct ppc_link_hash_table *htab;
 
-  elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64;
+  elf_elfheader (params->stub_bfd)->e_ident[EI_CLASS] = ELFCLASS64;
 
 /* Always hook our dynamic sections into the first bfd, which is the
    linker created stub bfd.  This ensures that the GOT header is at
    the start of the output TOC section.  */
   htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-  htab->stub_bfd = abfd;
-  htab->elf.dynobj = abfd;
-
-  if (info->relocatable)
-    return TRUE;
+  htab->elf.dynobj = params->stub_bfd;
+  htab->params = params;
 
   return create_linkage_sections (htab->elf.dynobj, info);
 }
@@ -4370,18 +4494,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;
     }
@@ -4389,7 +4513,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;
 
@@ -4413,35 +4537,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->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->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.  */
@@ -4454,9 +4575,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;
 }
 
@@ -4513,11 +4633,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;
@@ -4773,22 +4893,42 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
                           const char **name,
                           flagword *flags ATTRIBUTE_UNUSED,
                           asection **sec,
-                          bfd_vma *value ATTRIBUTE_UNUSED)
+                          bfd_vma *value)
 {
-  if ((ibfd->flags & DYNAMIC) == 0
-      && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
+      && (ibfd->flags & DYNAMIC) == 0
+      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
 
-  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+  if (*sec != NULL
+      && strcmp ((*sec)->name, ".opd") == 0)
     {
-      if ((ibfd->flags & DYNAMIC) == 0)
-       elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+      asection *code_sec;
+
+      if (!(ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
+           || ELF_ST_TYPE (isym->st_info) == STT_FUNC))
+       isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
+
+      /* 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 (!bfd_link_relocatable (info)
+         && (*sec)->reloc_count != 0
+         && opd_entry_value (*sec, *value, &code_sec, NULL,
+                             FALSE) != (bfd_vma) -1
+         && discarded_section (code_sec))
+       {
+         *sec = bfd_und_section_ptr;
+         isym->st_shndx = SHN_UNDEF;
+       }
     }
-  else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
-    ;
   else if (*sec != NULL
-          && strcmp ((*sec)->name, ".opd") == 0)
-    isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
+          && strcmp ((*sec)->name, ".toc") == 0
+          && ELF_ST_TYPE (isym->st_info) == STT_OBJECT)
+    {
+      struct ppc_link_hash_table *htab = ppc_hash_table (info);
+      if (htab != NULL)
+       htab->params->object_in_toc = 1;
+    }
 
   if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
     {
@@ -4886,7 +5026,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)
@@ -4922,13 +5062,53 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
   return TRUE;
 }
 
-/* Process list of dot-symbols we made in link_hash_newfunc.  */
+/* Set up opd section info and abiversion for IBFD, and process list
+   of dot-symbols we made in link_hash_newfunc.  */
 
 static bfd_boolean
-ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
+ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry **p, *eh;
+  asection *opd = bfd_get_section_by_name (ibfd, ".opd");
+
+  if (opd != NULL && opd->size != 0)
+    {
+      if (abiversion (ibfd) == 0)
+       set_abiversion (ibfd, 1);
+      else if (abiversion (ibfd) == 2)
+       {
+         info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
+                                   " version %d\n"),
+                                 ibfd, abiversion (ibfd));
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+
+      if ((ibfd->flags & DYNAMIC) == 0
+         && (opd->flags & SEC_RELOC) != 0
+         && opd->reloc_count != 0
+         && !bfd_is_abs_section (opd->output_section))
+       {
+         /* Garbage collection needs some extra help with .opd sections.
+            We don't want to necessarily keep everything referenced by
+            relocs in .opd, as that would keep all functions.  Instead,
+            if we reference an .opd symbol (a function descriptor), we
+            want to keep the function code symbol's section.  This is
+            easy for global symbols, but for local syms we need to keep
+            information about the associated function section.  */
+         bfd_size_type amt;
+         asection **opd_sym_map;
+
+         amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map);
+         opd_sym_map = bfd_zalloc (ibfd, amt);
+         if (opd_sym_map == NULL)
+           return FALSE;
+         ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map;
+         BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal);
+         ppc64_elf_section_data (opd)->sec_type = sec_opd;
+       }
+    }
 
   if (!is_ppc64_elf (info->output_bfd))
     return TRUE;
@@ -4936,21 +5116,29 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
   if (htab == NULL)
     return FALSE;
 
-  if (is_ppc64_elf (ibfd))
+  /* For input files without an explicit abiversion in e_flags
+     we should have flagged any with symbol st_other bits set
+     as ELFv1 and above flagged those with .opd as ELFv2.
+     Set the output abiversion if not yet set, and for any input
+     still ambiguous, take its abiversion from the output.
+     Differences in ABI are reported later.  */
+  if (abiversion (info->output_bfd) == 0)
+    set_abiversion (info->output_bfd, abiversion (ibfd));
+  else if (abiversion (ibfd) == 0)
+    set_abiversion (ibfd, abiversion (info->output_bfd));
+
+  p = &htab->dot_syms;
+  while ((eh = *p) != NULL)
     {
-      p = &htab->dot_syms;
-      while ((eh = *p) != NULL)
-       {
-         *p = NULL;
-         if (&eh->elf == htab->elf.hgot)
-           ;
-         else if (htab->elf.hgot == NULL
-                  && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
-           htab->elf.hgot = &eh->elf;
-         else if (!add_symbol_adjust (eh, info))
-           return FALSE;
-         p = &eh->u.next_dot_sym;
-       }
+      *p = NULL;
+      if (&eh->elf == htab->elf.hgot)
+       ;
+      else if (htab->elf.hgot == NULL
+              && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
+       htab->elf.hgot = &eh->elf;
+      else if (!add_symbol_adjust (eh, info))
+       return FALSE;
+      p = &eh->u.next_dot_sym;
     }
 
   /* Clear the list for non-ppc64 input files.  */
@@ -4962,7 +5150,7 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
     }
 
   /* We need to fix the undefs list for any syms we have twiddled to
-     undef_weak.  */
+     undefweak.  */
   if (htab->twiddled_syms)
     {
       bfd_link_repair_undef_list (&htab->elf.root);
@@ -5001,10 +5189,8 @@ ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
       && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0
       && is_ppc64_elf (sec->owner))
     {
-      asection *got = bfd_get_section_by_name (sec->owner, ".got");
-      if (got != NULL
-         && got->size >= elf_backend_got_header_size
-         && bfd_get_section_by_name (sec->owner, ".opd") != NULL)
+      if (abiversion (sec->owner) >= 2
+         || bfd_get_section_by_name (sec->owner, ".opd") != NULL)
        sec->has_toc_reloc = 1;
     }
   _bfd_elf_link_just_syms (sec, info);
@@ -5117,7 +5303,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.
@@ -5143,34 +5329,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   sym_hashes = elf_sym_hashes (abfd);
   sreloc = NULL;
   opd_sym_map = NULL;
-  if (strcmp (sec->name, ".opd") == 0)
-    {
-      /* Garbage collection needs some extra help with .opd sections.
-        We don't want to necessarily keep everything referenced by
-        relocs in .opd, as that would keep all functions.  Instead,
-        if we reference an .opd symbol (a function descriptor), we
-        want to keep the function code symbol's section.  This is
-        easy for global symbols, but for local syms we need to keep
-        information about the associated function section.  */
-      bfd_size_type amt;
-
-      if (abiversion (abfd) == 0)
-       set_abiversion (abfd, 1);
-      else if (abiversion (abfd) == 2)
-       {
-         info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"),
-                                 abiversion (abfd));
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
-      amt = sec->size * sizeof (*opd_sym_map) / 8;
-      opd_sym_map = bfd_zalloc (abfd, amt);
-      if (opd_sym_map == NULL)
-       return FALSE;
-      ppc64_elf_section_data (sec)->u.opd.func_sec = opd_sym_map;
-      BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal);
-      ppc64_elf_section_data (sec)->sec_type = sec_opd;
-    }
+  if (ppc64_elf_section_data (sec) != NULL
+      && ppc64_elf_section_data (sec)->sec_type == sec_opd)
+    opd_sym_map = ppc64_elf_section_data (sec)->u.opd.func_sec;
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
@@ -5180,7 +5341,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)
@@ -5223,28 +5384,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:
@@ -5271,7 +5412,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->executable)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -5344,7 +5485,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) == 2)
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
            {
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                return FALSE;
@@ -5356,33 +5497,35 @@ 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;
            }
-         break;
-
-         /* The following relocations don't need to propagate the
-            relocation if linking a shared object since they are
-            section relative.  */
-       case R_PPC64_SECTOFF:
+         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
+            relocation if linking a shared object since they are
+            section relative.  */
+       case R_PPC64_SECTOFF:
        case R_PPC64_SECTOFF_LO:
        case R_PPC64_SECTOFF_HI:
        case R_PPC64_SECTOFF_HA:
@@ -5407,6 +5550,22 @@ 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 (bfd_link_pic (info))
+           {
+             if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
+               ppc_howto_init ();
+             info->callbacks->einfo (_("%P: %H: %s reloc unsupported "
+                                       "in shared libraries and PIEs.\n"),
+                                     abfd, sec, rel->r_offset,
+                                     ppc64_elf_howto_table[r_type]->name);
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
          break;
 
        case R_PPC64_TOC16:
@@ -5420,6 +5579,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:
@@ -5469,24 +5632,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->executable)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dotlstoc;
 
@@ -5562,10 +5747,9 @@ 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))
            {
-             if (!info->executable)
-               info->flags |= DF_STATIC_TLS;
+             info->flags |= DF_STATIC_TLS;
              goto dodyn;
            }
          break;
@@ -5596,7 +5780,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
                  if (s != NULL && s != sec)
-                   opd_sym_map[rel->r_offset / 8] = s;
+                   opd_sym_map[OPD_NDX (rel->r_offset)] = s;
                }
            }
          /* Fall through.  */
@@ -5613,7 +5797,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) == 2
+         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
@@ -5627,16 +5811,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;
 
@@ -5666,18 +5846,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.
@@ -5787,21 +5967,14 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   iflags = elf_elfheader (ibfd)->e_flags;
   oflags = elf_elfheader (obfd)->e_flags;
 
-  if (!elf_flags_init (obfd) || oflags == 0)
-    {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = iflags;
-    }
-  else if (iflags == oflags || iflags == 0)
-    ;
-  else if (iflags & ~EF_PPC64_ABI)
+  if (iflags & ~EF_PPC64_ABI)
     {
       (*_bfd_error_handler)
        (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
-  else
+  else if (iflags != oflags && iflags != 0)
     {
       (*_bfd_error_handler)
        (_("%B: ABI version %ld is not compatible with ABI version %ld output"),
@@ -5840,7 +6013,8 @@ ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 }
 
 /* OFFSET in OPD_SEC specifies a function descriptor.  Return the address
-   of the code entry point, and its section.  */
+   of the code entry point, and its section, which must be in the same
+   object as OPD_SEC.  Returns (bfd_vma) -1 on error.  */
 
 static bfd_vma
 opd_entry_value (asection *opd_sec,
@@ -5867,6 +6041,10 @@ opd_entry_value (asection *opd_sec,
          ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
        }
 
+      /* PR 17512: file: 64b9dfbb.  */
+      if (offset + 7 >= opd_sec->size || offset + 7 < offset)
+       return (bfd_vma) -1;
+
       val = bfd_get_64 (opd_bfd, contents + offset);
       if (code_sec != NULL)
        {
@@ -5902,10 +6080,12 @@ opd_entry_value (asection *opd_sec,
   relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
   if (relocs == NULL)
     relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
+  /* PR 17512: file: df8e1fd6.  */
+  if (relocs == NULL)
+    return (bfd_vma) -1;
 
   /* Go find the opd reloc at the sym address.  */
   lo = relocs;
-  BFD_ASSERT (lo != NULL);
   hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */
   val = (bfd_vma) -1;
   while (lo < hi)
@@ -5923,32 +6103,10 @@ opd_entry_value (asection *opd_sec,
              && ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC)
            {
              unsigned long symndx = ELF64_R_SYM (look->r_info);
-             asection *sec;
-
-             if (symndx < symtab_hdr->sh_info
-                 || elf_sym_hashes (opd_bfd) == NULL)
-               {
-                 Elf_Internal_Sym *sym;
-
-                 sym = (Elf_Internal_Sym *) symtab_hdr->contents;
-                 if (sym == NULL)
-                   {
-                     size_t symcnt = symtab_hdr->sh_info;
-                     if (elf_sym_hashes (opd_bfd) == NULL)
-                       symcnt = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
-                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, symcnt,
-                                                 0, NULL, NULL, NULL);
-                     if (sym == NULL)
-                       break;
-                     symtab_hdr->contents = (bfd_byte *) sym;
-                   }
+             asection *sec = NULL;
 
-                 sym += symndx;
-                 val = sym->st_value;
-                 sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
-                 BFD_ASSERT ((sec->flags & SEC_MERGE) == 0);
-               }
-             else
+             if (symndx >= symtab_hdr->sh_info
+                 && elf_sym_hashes (opd_bfd) != NULL)
                {
                  struct elf_link_hash_entry **sym_hashes;
                  struct elf_link_hash_entry *rh;
@@ -5958,28 +6116,51 @@ 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 (rh->root.type != bfd_link_hash_defined
+                         && rh->root.type != bfd_link_hash_defweak)
+                       break;
+                     if (rh->root.u.def.section->owner == opd_bfd)
+                       {
+                         val = rh->root.u.def.value;
+                         sec = rh->root.u.def.section;
+                       }
+                   }
+               }
+
+             if (sec == NULL)
+               {
+                 Elf_Internal_Sym *sym;
+
+                 if (symndx < symtab_hdr->sh_info)
+                   {
+                     sym = (Elf_Internal_Sym *) symtab_hdr->contents;
+                     if (sym == NULL)
+                       {
+                         size_t symcnt = symtab_hdr->sh_info;
+                         sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr,
+                                                     symcnt, 0,
+                                                     NULL, NULL, NULL);
+                         if (sym == NULL)
+                           break;
+                         symtab_hdr->contents = (bfd_byte *) sym;
+                       }
+                     sym += symndx;
                    }
                  else
                    {
-                     /* Handle the odd case where we can be called
-                        during bfd_elf_link_add_symbols before the
-                        symbol hashes have been fully populated.  */
-                     Elf_Internal_Sym *sym;
-
-                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 1,
-                                                 symndx, NULL, NULL, NULL);
+                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr,
+                                                 1, symndx,
+                                                 NULL, NULL, NULL);
                      if (sym == NULL)
                        break;
-
-                     val = sym->st_value;
-                     sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
-                     free (sym);
                    }
+                 sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
+                 if (sec == NULL)
+                   break;
+                 BFD_ASSERT ((sec->flags & SEC_MERGE) == 0);
+                 val = sym->st_value;
                }
+
              val += look->r_addend;
              if (code_off != NULL)
                *code_off = val;
@@ -5990,7 +6171,7 @@ opd_entry_value (asection *opd_sec,
                  else
                    *code_sec = sec;
                }
-             if (sec != NULL && sec->output_section != NULL)
+             if (sec->output_section != NULL)
                val += sec->output_section->vma + sec->output_offset;
            }
          break;
@@ -6020,7 +6201,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
@@ -6144,6 +6341,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
   struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
   struct ppc_link_hash_entry *fdh;
+  struct bfd_elf_dynamic_list *d = info->dynamic_list;
 
   /* Dynamic linking info is on the func descriptor sym.  */
   fdh = defined_func_desc (eh);
@@ -6153,10 +6351,14 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
   if ((eh->elf.root.type == bfd_link_hash_defined
        || eh->elf.root.type == bfd_link_hash_defweak)
       && (eh->elf.ref_dynamic
-         || (!info->executable
-             && eh->elf.def_regular
+         || ((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
+             && (!bfd_link_executable (info)
+                 || info->export_dynamic
+                 || (eh->elf.dynamic
+                     && d != NULL
+                     && (*d->match) (&d->head, NULL, eh->elf.root.root.string)))
              && (strchr (eh->elf.root.root.string, ELF_VER_CHR) != NULL
                  || !bfd_hide_sym_by_version (info->version_info,
                                               eh->elf.root.root.string)))))
@@ -6262,7 +6464,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
        {
          rsec->gc_mark = 1;
 
-         rsec = opd->func_sec[(sym->st_value + rel->r_addend) / 8];
+         rsec = opd->func_sec[OPD_NDX (sym->st_value + rel->r_addend)];
        }
     }
 
@@ -6282,7 +6484,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)
@@ -6304,6 +6506,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);
@@ -6327,38 +6530,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:
@@ -6425,11 +6596,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)
@@ -6455,10 +6638,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;
@@ -6474,26 +6661,61 @@ 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, writing, TRUE, 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;
+             h->elf.non_elf = 0;
+             _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)
@@ -6732,7 +6954,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))
     {
@@ -6765,7 +6987,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
@@ -6804,6 +7026,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
@@ -6814,58 +7052,48 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info *info)
 {
   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
-      && htab->elf.hgot != NULL)
+  /* Provide any missing _save* and _rest* functions.  */
+  if (htab->sfpr != NULL)
+    {
+      unsigned int i;
+
+      htab->sfpr->size = 0;
+      for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+       if (!sfpr_define (info, &save_res_funcs[i], NULL))
+         return FALSE;
+      if (htab->sfpr->size == 0)
+       htab->sfpr->flags |= SEC_EXCLUDE;
+    }
+
+  if (bfd_link_relocatable (info))
+    return TRUE;
+
+  if (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);
     }
 
-  if (htab->sfpr == NULL)
-    /* We don't have any relocs.  */
-    return TRUE;
-
-  /* Provide any missing _save* and _rest* functions.  */
-  htab->sfpr->size = 0;
-  if (!info->relocatable)
-    for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
-      if (!sfpr_define (info, &funcs[i]))
-       return FALSE;
-
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
-  if (htab->sfpr->size == 0)
-    htab->sfpr->flags |= SEC_EXCLUDE;
-
   return TRUE;
 }
 
@@ -6920,13 +7148,27 @@ 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;
+         h->pointer_equality_needed = 0;
        }
       else if (abiversion (info->output_bfd) == 2)
        {
+         /* Taking a function's address in a read/write section
+            doesn't require us to define the function symbol in the
+            executable on a global entry stub.  A dynamic reloc can
+            be used instead.  */
+         if (h->pointer_equality_needed
+             && h->type != STT_GNU_IFUNC
+             && !readonly_dynrelocs (h))
+           {
+             h->pointer_equality_needed = 0;
+             h->non_got_ref = 0;
+           }
+
          /* After adjust_dynamic_symbol, non_got_ref set in the
             non-shared case means that we have allocated space in
             .dynbss for the symbol and thus dyn_relocs for this
@@ -6936,10 +7178,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             relocations against this symbol to the PLT entry.  Allow
             dynamic relocs if the reference is weak, and the dynamic
             relocs will not cause text relocation.  */
-         if (!h->ref_regular_nonweak
-             && h->non_got_ref
-             && h->type != STT_GNU_IFUNC
-             && !readonly_dynrelocs (h))
+         else if (!h->ref_regular_nonweak
+                  && h->non_got_ref
+                  && h->type != STT_GNU_IFUNC
+                  && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
 
          /* If making a plt entry, then we don't need copy relocs.  */
@@ -6967,7 +7209,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
@@ -6979,6 +7221,13 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->def_dynamic || !h->ref_regular || h->def_regular)
     return TRUE;
 
+  /* If -z nocopyreloc was given, don't generate them either.  */
+  if (info->nocopyreloc)
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
   /* If we didn't find any dynamic relocs in read-only sections, then
      we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
   if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
@@ -6987,6 +7236,16 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       return TRUE;
     }
 
+  /* Protected variables do not work with .dynbss.  The copy in
+     .dynbss won't be used by the shared library with the protected
+     definition for the variable.  Text relocations are preferable
+     to an incorrect program.  */
+  if (h->protected_def)
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
   if (h->plt.plist != NULL)
     {
       /* We should never get here, but unfortunately there are versions
@@ -7025,7 +7284,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   s = htab->dynbss;
 
-  return _bfd_elf_adjust_dynamic_copy (h, s);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
 /* If given a function descriptor symbol, hide both the function code
@@ -7310,7 +7569,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   opd = get_opd_info (sym_sec);
   if (opd != NULL && opd->adjust != NULL)
     {
-      long adjust = opd->adjust[eh->elf.root.u.def.value / 8];
+      long adjust = opd->adjust[OPD_NDX (eh->elf.root.u.def.value)];
       if (adjust == -1)
        {
          /* This entry has been deleted.  */
@@ -7369,7 +7628,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:
@@ -7413,14 +7672,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)))
@@ -7500,21 +7759,25 @@ dec_dynrel_count (bfd_vma r_info,
    applications.  */
 
 bfd_boolean
-ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
+ppc64_elf_edit_opd (struct bfd_link_info *info)
 {
   bfd *ibfd;
   bfd_boolean some_edited = FALSE;
   asection *need_pad = NULL;
+  struct ppc_link_hash_table *htab;
+
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       asection *sec;
       Elf_Internal_Rela *relstart, *rel, *relend;
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
-      bfd_vma offset;
       struct _opd_sec_data *opd;
-      bfd_boolean need_edit, add_aux_fields;
+      bfd_boolean need_edit, add_aux_fields, broken;
       bfd_size_type cnt_16b = 0;
 
       if (!is_ppc64_elf (ibfd))
@@ -7546,8 +7809,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
       /* First run through the relocs to check they are sane, and to
         determine whether we need to edit this opd section.  */
       need_edit = FALSE;
+      broken = FALSE;
       need_pad = sec;
-      offset = 0;
       relend = relstart + sec->reloc_count;
       for (rel = relstart; rel < relend; )
        {
@@ -7556,13 +7819,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
          asection *sym_sec;
          struct elf_link_hash_entry *h;
          Elf_Internal_Sym *sym;
+         bfd_vma offset;
 
-         /* .opd contains a regular array of 16 or 24 byte entries.  We're
+         /* .opd contains an array of 16 or 24 byte entries.  We're
             only interested in the reloc pointing to a function entry
             point.  */
-         if (rel->r_offset != offset
-             || rel + 1 >= relend
-             || (rel + 1)->r_offset != offset + 8)
+         offset = rel->r_offset;
+         if (rel + 1 == relend
+             || rel[1].r_offset != offset + 8)
            {
              /* If someone messes with .opd alignment then after a
                 "ld -r" we might have padding in the middle of .opd.
@@ -7572,7 +7836,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
            broken_opd:
              (*_bfd_error_handler)
                (_("%B: .opd is not a regular array of opd entries"), ibfd);
-             need_edit = FALSE;
+             broken = TRUE;
              break;
            }
 
@@ -7582,7 +7846,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
              (*_bfd_error_handler)
                (_("%B: unexpected reloc type %u in .opd section"),
                 ibfd, r_type);
-             need_edit = FALSE;
+             broken = TRUE;
              break;
            }
 
@@ -7603,7 +7867,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
              (*_bfd_error_handler)
                (_("%B: undefined sym `%s' in .opd section"),
                 ibfd, sym_name);
-             need_edit = FALSE;
+             broken = TRUE;
              break;
            }
 
@@ -7619,58 +7883,50 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
            need_edit = TRUE;
 
          rel += 2;
-         if (rel == relend
-             || (rel + 1 == relend && rel->r_offset == offset + 16))
+         if (rel + 1 == relend
+             || (rel + 2 < relend
+                 && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC))
+           ++rel;
+
+         if (rel == relend)
            {
              if (sec->size == offset + 24)
                {
                  need_pad = NULL;
                  break;
                }
-             if (rel == relend && sec->size == offset + 16)
+             if (sec->size == offset + 16)
                {
                  cnt_16b++;
                  break;
                }
              goto broken_opd;
            }
-
-         if (rel->r_offset == offset + 24)
-           offset += 24;
-         else if (rel->r_offset != offset + 16)
-           goto broken_opd;
          else if (rel + 1 < relend
                   && ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64
                   && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC)
            {
-             offset += 16;
-             cnt_16b++;
-           }
-         else if (rel + 2 < relend
-                  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_ADDR64
-                  && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC)
-           {
-             offset += 24;
-             rel += 1;
+             if (rel[0].r_offset == offset + 16)
+               cnt_16b++;
+             else if (rel[0].r_offset != offset + 24)
+               goto broken_opd;
            }
          else
            goto broken_opd;
        }
 
-      add_aux_fields = non_overlapping && cnt_16b > 0;
+      add_aux_fields = htab->params->non_overlapping_opd && cnt_16b > 0;
 
-      if (need_edit || add_aux_fields)
+      if (!broken && (need_edit || add_aux_fields))
        {
          Elf_Internal_Rela *write_rel;
          Elf_Internal_Shdr *rel_hdr;
          bfd_byte *rptr, *wptr;
          bfd_byte *new_contents;
-         bfd_boolean skip;
-         long opd_ent_size;
          bfd_size_type amt;
 
          new_contents = NULL;
-         amt = sec->size * sizeof (long) / 8;
+         amt = OPD_NDX (sec->size) * sizeof (long);
          opd = &ppc64_elf_section_data (sec)->u.opd;
          opd->adjust = bfd_zalloc (sec->owner, amt);
          if (opd->adjust == NULL)
@@ -7708,128 +7964,134 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
              new_contents = bfd_malloc (sec->size + cnt_16b * 8);
              if (new_contents == NULL)
                return FALSE;
-             need_pad = FALSE;
+             need_pad = NULL;
            }
          wptr = new_contents;
          rptr = sec->contents;
-
          write_rel = relstart;
-         skip = FALSE;
-         offset = 0;
-         opd_ent_size = 0;
-         for (rel = relstart; rel < relend; rel++)
+         for (rel = relstart; rel < relend; )
            {
              unsigned long r_symndx;
              asection *sym_sec;
              struct elf_link_hash_entry *h;
+             struct ppc_link_hash_entry *fdh = NULL;
              Elf_Internal_Sym *sym;
+             long opd_ent_size;
+             Elf_Internal_Rela *next_rel;
+             bfd_boolean skip;
 
              r_symndx = ELF64_R_SYM (rel->r_info);
              if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                              r_symndx, ibfd))
                goto error_ret;
 
-             if (rel->r_offset == offset)
+             next_rel = rel + 2;
+             if (next_rel + 1 == relend
+                 || (next_rel + 2 < relend
+                     && ELF64_R_TYPE (next_rel[2].r_info) == R_PPC64_TOC))
+               ++next_rel;
+
+             /* See if the .opd entry is full 24 byte or
+                16 byte (with fd_aux entry overlapped with next
+                fd_func).  */
+             opd_ent_size = 24;
+             if (next_rel == relend)
                {
-                 struct ppc_link_hash_entry *fdh = NULL;
-
-                 /* See if the .opd entry is full 24 byte or
-                    16 byte (with fd_aux entry overlapped with next
-                    fd_func).  */
-                 opd_ent_size = 24;
-                 if ((rel + 2 == relend && sec->size == offset + 16)
-                     || (rel + 3 < relend
-                         && rel[2].r_offset == offset + 16
-                         && rel[3].r_offset == offset + 24
-                         && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_ADDR64
-                         && ELF64_R_TYPE (rel[3].r_info) == R_PPC64_TOC))
+                 if (sec->size == rel->r_offset + 16)
                    opd_ent_size = 16;
+               }
+             else if (next_rel->r_offset == rel->r_offset + 16)
+               opd_ent_size = 16;
 
-                 if (h != NULL
-                     && h->root.root.string[0] == '.')
-                   {
-                     struct ppc_link_hash_table *htab;
-
-                     htab = ppc_hash_table (info);
-                     if (htab != NULL)
-                       fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
-                                         htab);
-                     if (fdh != NULL
-                         && fdh->elf.root.type != bfd_link_hash_defined
-                         && fdh->elf.root.type != bfd_link_hash_defweak)
-                       fdh = NULL;
-                   }
+             if (h != NULL
+                 && h->root.root.string[0] == '.')
+               {
+                 fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab);
+                 if (fdh != NULL
+                     && fdh->elf.root.type != bfd_link_hash_defined
+                     && fdh->elf.root.type != bfd_link_hash_defweak)
+                   fdh = NULL;
+               }
 
-                 skip = (sym_sec->owner != ibfd
-                         || sym_sec->output_section == bfd_abs_section_ptr);
-                 if (skip)
+             skip = (sym_sec->owner != ibfd
+                     || sym_sec->output_section == bfd_abs_section_ptr);
+             if (skip)
+               {
+                 if (fdh != NULL && sym_sec->owner == ibfd)
                    {
-                     if (fdh != NULL && sym_sec->owner == ibfd)
-                       {
-                         /* Arrange for the function descriptor sym
-                            to be dropped.  */
-                         fdh->elf.root.u.def.value = 0;
-                         fdh->elf.root.u.def.section = sym_sec;
-                       }
-                     opd->adjust[rel->r_offset / 8] = -1;
+                     /* Arrange for the function descriptor sym
+                        to be dropped.  */
+                     fdh->elf.root.u.def.value = 0;
+                     fdh->elf.root.u.def.section = sym_sec;
                    }
-                 else
-                   {
-                     /* We'll be keeping this opd entry.  */
+                 opd->adjust[OPD_NDX (rel->r_offset)] = -1;
 
-                     if (fdh != NULL)
-                       {
-                         /* Redefine the function descriptor symbol to
-                            this location in the opd section.  It is
-                            necessary to update the value here rather
-                            than using an array of adjustments as we do
-                            for local symbols, because various places
-                            in the generic ELF code use the value
-                            stored in u.def.value.  */
-                         fdh->elf.root.u.def.value = wptr - new_contents;
-                         fdh->adjust_done = 1;
-                       }
+                 if (NO_OPD_RELOCS || bfd_link_relocatable (info))
+                   rel = next_rel;
+                 else
+                   while (1)
+                     {
+                       if (!dec_dynrel_count (rel->r_info, sec, info,
+                                              NULL, h, sym))
+                         goto error_ret;
 
-                     /* Local syms are a bit tricky.  We could
-                        tweak them as they can be cached, but
-                        we'd need to look through the local syms
-                        for the function descriptor sym which we
-                        don't have at the moment.  So keep an
-                        array of adjustments.  */
-                     opd->adjust[rel->r_offset / 8]
-                       = (wptr - new_contents) - (rptr - sec->contents);
-
-                     if (wptr != rptr)
-                       memcpy (wptr, rptr, opd_ent_size);
-                     wptr += opd_ent_size;
-                     if (add_aux_fields && opd_ent_size == 16)
-                       {
-                         memset (wptr, '\0', 8);
-                         wptr += 8;
-                       }
-                   }
-                 rptr += opd_ent_size;
-                 offset += opd_ent_size;
-               }
+                       if (++rel == next_rel)
+                         break;
 
-             if (skip)
-               {
-                 if (!NO_OPD_RELOCS
-                     && !info->relocatable
-                     && !dec_dynrel_count (rel->r_info, sec, info,
-                                           NULL, h, sym))
-                   goto error_ret;
+                       r_symndx = ELF64_R_SYM (rel->r_info);
+                       if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                                       r_symndx, ibfd))
+                         goto error_ret;
+                     }
                }
              else
                {
+                 /* We'll be keeping this opd entry.  */
+                 long adjust;
+
+                 if (fdh != NULL)
+                   {
+                     /* Redefine the function descriptor symbol to
+                        this location in the opd section.  It is
+                        necessary to update the value here rather
+                        than using an array of adjustments as we do
+                        for local symbols, because various places
+                        in the generic ELF code use the value
+                        stored in u.def.value.  */
+                     fdh->elf.root.u.def.value = wptr - new_contents;
+                     fdh->adjust_done = 1;
+                   }
+
+                 /* Local syms are a bit tricky.  We could
+                    tweak them as they can be cached, but
+                    we'd need to look through the local syms
+                    for the function descriptor sym which we
+                    don't have at the moment.  So keep an
+                    array of adjustments.  */
+                 adjust = (wptr - new_contents) - (rptr - sec->contents);
+                 opd->adjust[OPD_NDX (rel->r_offset)] = adjust;
+
+                 if (wptr != rptr)
+                   memcpy (wptr, rptr, opd_ent_size);
+                 wptr += opd_ent_size;
+                 if (add_aux_fields && opd_ent_size == 16)
+                   {
+                     memset (wptr, '\0', 8);
+                     wptr += 8;
+                   }
+
                  /* We need to adjust any reloc offsets to point to the
-                    new opd entries.  While we're at it, we may as well
-                    remove redundant relocs.  */
-                 rel->r_offset += opd->adjust[(offset - opd_ent_size) / 8];
-                 if (write_rel != rel)
-                   memcpy (write_rel, rel, sizeof (*rel));
-                 ++write_rel;
+                    new opd entries.  */
+                 for ( ; rel != next_rel; ++rel)
+                   {
+                     rel->r_offset += adjust;
+                     if (write_rel != rel)
+                       memcpy (write_rel, rel, sizeof (*rel));
+                     ++write_rel;
+                   }
                }
+
+             rptr += opd_ent_size;
            }
 
          sec->size = wptr - new_contents;
@@ -7864,7 +8126,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 
   /* 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;
 
@@ -7902,9 +8164,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 /* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 asection *
-ppc64_elf_tls_setup (struct bfd_link_info *info,
-                    int no_tls_get_addr_opt,
-                    int *no_multi_toc)
+ppc64_elf_tls_setup (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
 
@@ -7915,10 +8175,10 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
   if (abiversion (info->output_bfd) == 1)
     htab->opd_abi = 1;
 
-  if (*no_multi_toc)
+  if (htab->params->no_multi_toc)
     htab->do_multi_toc = 0;
   else if (!htab->do_multi_toc)
-    *no_multi_toc = 1;
+    htab->params->no_multi_toc = 1;
 
   htab->tls_get_addr = ((struct ppc_link_hash_entry *)
                        elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
@@ -7929,7 +8189,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 (!no_tls_get_addr_opt)
+  if (htab->params->tls_get_addr_opt)
     {
       struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
 
@@ -7966,6 +8226,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
                  tga_fd->root.type = bfd_link_hash_indirect;
                  tga_fd->root.u.i.link = &opt_fd->root;
                  ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+                 opt_fd->forced_local = 0;
                  if (opt_fd->dynindx != -1)
                    {
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
@@ -7982,6 +8243,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
                      tga->root.type = bfd_link_hash_indirect;
                      tga->root.u.i.link = &opt->root;
                      ppc64_elf_copy_indirect_symbol (info, opt, tga);
+                     opt->forced_local = 0;
                      _bfd_elf_link_hash_hide_symbol (info, opt,
                                                      tga->forced_local);
                      htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
@@ -7996,10 +8258,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
                }
            }
        }
-      else
-       no_tls_get_addr_opt = TRUE;
+      else if (htab->params->tls_get_addr_opt < 0)
+       htab->params->tls_get_addr_opt = 0;
     }
-  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
   return _bfd_elf_tls_setup (info->output_bfd, info);
 }
 
@@ -8045,7 +8306,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);
@@ -8061,7 +8322,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
      and plt refcounts.  */
   toc_ref = NULL;
   for (pass = 0; pass < 2; ++pass)
-    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
       {
        Elf_Internal_Sym *locsyms = NULL;
        asection *toc = bfd_get_section_by_name (ibfd, ".toc");
@@ -8076,7 +8337,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
                                                    info->keep_memory);
              if (relstart == NULL)
-               return FALSE;
+               {
+                 free (toc_ref);
+                 return FALSE;
+               }
 
              relend = relstart + sec->reloc_count;
              for (rel = relstart; rel < relend; rel++)
@@ -8137,7 +8401,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;
@@ -8249,7 +8514,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      else
                        value = sym->st_value;
                      value += rel->r_addend;
-                     BFD_ASSERT (value < toc->size && value % 8 == 0);
+                     if (value % 8 != 0)
+                       continue;
+                     BFD_ASSERT (value < toc->size
+                                 && toc->output_offset % 8 == 0);
                      toc_ref_index = (value + toc->output_offset) / 8;
                      if (r_type == R_PPC64_TLS
                          || r_type == R_PPC64_TLSGD
@@ -8555,7 +8823,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
 
   htab->do_toc_opt = 1;
   toc_inf.global_toc_syms = TRUE;
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       asection *toc, *sec;
       Elf_Internal_Shdr *symtab_hdr;
@@ -8695,10 +8963,11 @@ 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;
 
-             if (!SYMBOL_CALLS_LOCAL (info, h))
+             if (!SYMBOL_REFERENCES_LOCAL (info, h))
                continue;
 
              if (h != NULL)
@@ -8784,7 +9053,10 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
          relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
                                                info->keep_memory);
          if (relstart == NULL)
-           goto error_ret;
+           {
+             free (used);
+             goto error_ret;
+           }
 
          /* Mark toc entries referenced as used.  */
          do
@@ -9230,7 +9502,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))
@@ -9281,71 +9553,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (htab == NULL)
     return FALSE;
 
-  if ((htab->elf.dynamic_sections_created
-       && h->dynindx != -1
-       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
-      || h->type == STT_GNU_IFUNC)
-    {
-      struct plt_entry *pent;
-      bfd_boolean doneone = FALSE;
-      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
-       if (pent->plt.refcount > 0)
-         {
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
-             {
-               s = htab->elf.iplt;
-               pent->plt.offset = s->size;
-               s->size += PLT_ENTRY_SIZE (htab);
-               s = htab->elf.irelplt;
-             }
-           else
-             {
-               /* If this is the first .plt entry, make room for the special
-                  first entry.  */
-               s = htab->elf.splt;
-               if (s->size == 0)
-                 s->size += PLT_INITIAL_ENTRY_SIZE (htab);
-
-               pent->plt.offset = s->size;
-
-               /* Make room for this entry.  */
-               s->size += PLT_ENTRY_SIZE (htab);
-
-               /* Make room for the .glink code.  */
-               s = htab->glink;
-               if (s->size == 0)
-                 s->size += GLINK_CALL_STUB_SIZE;
-               if (htab->opd_abi)
-                 {
-                   /* We need bigger stubs past index 32767.  */
-                   if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
-                     s->size += 4;
-                   s->size += 2*4;
-                 }
-               else
-                 s->size += 4;
-
-               /* We also need to make an entry in the .rela.plt section.  */
-               s = htab->elf.srelplt;
-             }
-           s->size += sizeof (Elf64_External_Rela);
-           doneone = TRUE;
-         }
-       else
-         pent->plt.offset = (bfd_vma) -1;
-      if (!doneone)
-       {
-         h->plt.plist = NULL;
-         h->needs_plt = 0;
-       }
-    }
-  else
-    {
-      h->plt.plist = NULL;
-      h->needs_plt = 0;
-    }
-
   eh = (struct ppc_link_hash_entry *) h;
   /* Run through the TLS GD got entries first if we're changing them
      to TPREL.  */
@@ -9415,100 +9622,165 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        allocate_got (h, info, gent);
       }
 
-  if (eh->dyn_relocs == NULL
-      || (!htab->elf.dynamic_sections_created
-         && (h->type != STT_GNU_IFUNC
-             || !htab->opd_abi)))
-    return TRUE;
-
-  /* In the shared -Bsymbolic case, discard space allocated for
-     dynamic pc-relative relocs against symbols which turn out to be
-     defined in regular objects.  For the normal shared case, discard
-     space for relocs that have become local due to symbol visibility
-     changes.  */
-
-  if (info->shared)
+  if (eh->dyn_relocs != NULL
+      && (htab->elf.dynamic_sections_created
+         || h->type == STT_GNU_IFUNC))
     {
-      /* 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
-        generated via assembly.  We want calls to protected symbols to
-        resolve directly to the function rather than going via the plt.
-        If people want function pointer comparisons to work as expected
-        then they should avoid writing weird assembly.  */
-      if (SYMBOL_CALLS_LOCAL (info, h))
+      /* In the shared -Bsymbolic case, discard space allocated for
+        dynamic pc-relative relocs against symbols which turn out to
+        be defined in regular objects.  For the normal shared case,
+        discard space for relocs that have become local due to symbol
+        visibility changes.  */
+
+      if (bfd_link_pic (info))
        {
-         struct elf_dyn_relocs **pp;
+         /* 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 generated via assembly.  We want calls to
+            protected symbols to resolve directly to the function
+            rather than going via the plt.  If people want function
+            pointer comparisons to work as expected then they should
+            avoid writing weird assembly.  */
+         if (SYMBOL_CALLS_LOCAL (info, h))
+           {
+             struct elf_dyn_relocs **pp;
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+               {
+                 p->count -= p->pc_count;
+                 p->pc_count = 0;
+                 if (p->count == 0)
+                   *pp = p->next;
+                 else
+                   pp = &p->next;
+               }
+           }
+
+         /* Also discard relocs on undefined weak syms with
+            non-default visibility.  */
+         if (eh->dyn_relocs != NULL
+             && h->root.type == bfd_link_hash_undefweak)
            {
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             if (p->count == 0)
-               *pp = p->next;
-             else
-               pp = &p->next;
+             if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+               eh->dyn_relocs = NULL;
+
+             /* Make sure this symbol is output as a dynamic symbol.
+                Undefined weak syms won't yet be marked as dynamic.  */
+             else if (h->dynindx == -1
+                      && !h->forced_local)
+               {
+                 if (! bfd_elf_link_record_dynamic_symbol (info, h))
+                   return FALSE;
+               }
            }
        }
-
-      /* Also discard relocs on undefined weak syms with non-default
-        visibility.  */
-      if (eh->dyn_relocs != NULL
-         && h->root.type == bfd_link_hash_undefweak)
+      else if (h->type == STT_GNU_IFUNC)
        {
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+         if (!h->non_got_ref)
            eh->dyn_relocs = NULL;
+       }
+      else if (ELIMINATE_COPY_RELOCS)
+       {
+         /* For the non-shared case, discard space for relocs against
+            symbols which turn out to need copy relocs or are not
+            dynamic.  */
 
-         /* Make sure this symbol is output as a dynamic symbol.
-            Undefined weak syms won't yet be marked as dynamic.  */
-         else if (h->dynindx == -1
-                  && !h->forced_local)
+         if (!h->non_got_ref
+             && !h->def_regular)
            {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
+             /* Make sure this symbol is output as a dynamic symbol.
+                Undefined weak syms won't yet be marked as dynamic.  */
+             if (h->dynindx == -1
+                 && !h->forced_local)
+               {
+                 if (! bfd_elf_link_record_dynamic_symbol (info, h))
+                   return FALSE;
+               }
+
+             /* If that succeeded, we know we'll be keeping all the
+                relocs.  */
+             if (h->dynindx != -1)
+               goto keep;
            }
+
+         eh->dyn_relocs = NULL;
+
+       keep: ;
+       }
+
+      /* Finally, allocate space.  */
+      for (p = eh->dyn_relocs; p != NULL; p = p->next)
+       {
+         asection *sreloc = elf_section_data (p->sec)->sreloc;
+         if (eh->elf.type == STT_GNU_IFUNC)
+           sreloc = htab->elf.irelplt;
+         sreloc->size += p->count * sizeof (Elf64_External_Rela);
        }
     }
-  else if (h->type == STT_GNU_IFUNC)
-    {
-      if (!h->non_got_ref)
-       eh->dyn_relocs = NULL;
-    }
-  else if (ELIMINATE_COPY_RELOCS)
+
+  if ((htab->elf.dynamic_sections_created
+       && h->dynindx != -1
+       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+      || h->type == STT_GNU_IFUNC)
     {
-      /* For the non-shared case, discard space for relocs against
-        symbols which turn out to need copy relocs or are not
-        dynamic.  */
+      struct plt_entry *pent;
+      bfd_boolean doneone = FALSE;
+      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+       if (pent->plt.refcount > 0)
+         {
+           if (!htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
+             {
+               s = htab->elf.iplt;
+               pent->plt.offset = s->size;
+               s->size += PLT_ENTRY_SIZE (htab);
+               s = htab->elf.irelplt;
+             }
+           else
+             {
+               /* If this is the first .plt entry, make room for the special
+                  first entry.  */
+               s = htab->elf.splt;
+               if (s->size == 0)
+                 s->size += PLT_INITIAL_ENTRY_SIZE (htab);
 
-      if (!h->non_got_ref
-         && !h->def_regular)
-       {
-         /* Make sure this symbol is output as a dynamic symbol.
-            Undefined weak syms won't yet be marked as dynamic.  */
-         if (h->dynindx == -1
-             && !h->forced_local)
-           {
-             if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
-           }
+               pent->plt.offset = s->size;
 
-         /* If that succeeded, we know we'll be keeping all the
-            relocs.  */
-         if (h->dynindx != -1)
-           goto keep;
-       }
+               /* Make room for this entry.  */
+               s->size += PLT_ENTRY_SIZE (htab);
 
-      eh->dyn_relocs = NULL;
+               /* Make room for the .glink code.  */
+               s = htab->glink;
+               if (s->size == 0)
+                 s->size += GLINK_CALL_STUB_SIZE;
+               if (htab->opd_abi)
+                 {
+                   /* We need bigger stubs past index 32767.  */
+                   if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+                     s->size += 4;
+                   s->size += 2*4;
+                 }
+               else
+                 s->size += 4;
 
-    keep: ;
+               /* We also need to make an entry in the .rela.plt section.  */
+               s = htab->elf.srelplt;
+             }
+           s->size += sizeof (Elf64_External_Rela);
+           doneone = TRUE;
+         }
+       else
+         pent->plt.offset = (bfd_vma) -1;
+      if (!doneone)
+       {
+         h->plt.plist = NULL;
+         h->needs_plt = 0;
+       }
     }
-
-  /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  else
     {
-      asection *sreloc = elf_section_data (p->sec)->sreloc;
-      if (eh->elf.type == STT_GNU_IFUNC)
-       sreloc = htab->elf.irelplt;
-      sreloc->size += p->count * sizeof (Elf64_External_Rela);
+      h->plt.plist = NULL;
+      h->needs_plt = 0;
     }
 
   return TRUE;
@@ -9545,7 +9817,13 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
     if (pent->plt.offset != (bfd_vma) -1
        && pent->addend == 0)
       {
+       /* For ELFv2, if this symbol is not defined in a regular file
+          and we are not generating a shared library or pie, then we
+          need to define the symbol in the executable on a call stub.
+          This is to avoid text relocations.  */
        s->size = (s->size + 15) & -16;
+       h->root.u.def.section = s;
+       h->root.u.def.value = s->size;
        s->size += 16;
        break;
       }
@@ -9595,7 +9873,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)
@@ -9607,7 +9885,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry **lgot_ents;
       struct got_entry **end_lgot_ents;
@@ -9687,7 +9965,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;
@@ -9725,11 +10003,11 @@ 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;
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry *ent;
 
@@ -9752,7 +10030,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);
@@ -9837,7 +10115,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
        return FALSE;
     }
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       if (!is_ppc64_elf (ibfd))
        continue;
@@ -9882,7 +10160,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;
@@ -9905,7 +10183,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            return FALSE;
        }
 
-      tls_opt = (!htab->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)
@@ -10077,17 +10355,20 @@ plt_stub_size (struct ppc_link_hash_table *htab,
   if (htab->opd_abi)
     {
       size += 4;
-      if (htab->plt_static_chain)
+      if (htab->params->plt_static_chain)
        size += 4;
-      if (htab->plt_thread_safe)
+      if (htab->params->plt_thread_safe
+         && htab->elf.dynamic_sections_created
+         && stub_entry->h != NULL
+         && stub_entry->h->elf.dynindx != -1)
        size += 8;
-      if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
+      if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
        size += 4;
     }
   if (stub_entry->h != NULL
       && (stub_entry->h == htab->tls_get_addr_fd
          || stub_entry->h == htab->tls_get_addr)
-      && !htab->no_tls_get_addr_opt)
+      && htab->params->tls_get_addr_opt)
     size += 13 * 4;
   return size;
 }
@@ -10099,12 +10380,12 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
              struct ppc_stub_hash_entry *stub_entry,
              bfd_vma plt_off)
 {
-  int stub_align = 1 << htab->plt_stub_align;
+  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 & -stub_align))
+      > ((stub_size - 1) & -stub_align))
     return stub_align - (stub_off & (stub_align - 1));
   return 0;
 }
@@ -10116,20 +10397,22 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                struct ppc_stub_hash_entry *stub_entry,
                bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
-  bfd *obfd = htab->stub_bfd;
+  bfd *obfd = htab->params->stub_bfd;
   bfd_boolean plt_load_toc = htab->opd_abi;
-  bfd_boolean plt_static_chain = htab->plt_static_chain;
-  bfd_boolean plt_thread_safe = htab->plt_thread_safe;
+  bfd_boolean plt_static_chain = htab->params->plt_static_chain;
+  bfd_boolean plt_thread_safe = (htab->params->plt_thread_safe
+                                && htab->elf.dynamic_sections_created
+                                && stub_entry->h != NULL
+                                && stub_entry->h->elf.dynindx != -1);
   bfd_boolean use_fake_dep = plt_thread_safe;
   bfd_vma cmp_branch_off = 0;
 
   if (!ALWAYS_USE_FAKE_DEP
       && plt_load_toc
       && plt_thread_safe
-      && !(stub_entry->h != NULL
-          && (stub_entry->h == htab->tls_get_addr_fd
-              || stub_entry->h == htab->tls_get_addr)
-          && !htab->no_tls_get_addr_opt))
+      && !((stub_entry->h == htab->tls_get_addr_fd
+           || stub_entry->h == htab->tls_get_addr)
+          && 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))
@@ -10142,7 +10425,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)
@@ -10150,8 +10433,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);
     }
@@ -10192,8 +10475,16 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       if (ALWAYS_EMIT_R2SAVE
          || stub_entry->stub_type == ppc_stub_plt_call_r2save)
        bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p),      p += 4;
-      bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p),    p += 4;
-      bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),     p += 4;
+      if (plt_load_toc)
+       {
+         bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4;
+         bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p),  p += 4;
+       }
+      else
+       {
+         bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4;
+         bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (offset), p),  p += 4;
+       }
       if (plt_load_toc
          && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
        {
@@ -10296,7 +10587,7 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
                         struct ppc_stub_hash_entry *stub_entry,
                         bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
-  bfd *obfd = htab->stub_bfd;
+  bfd *obfd = htab->params->stub_bfd;
 
   bfd_put_32 (obfd, LD_R11_0R3 + 0, p),                p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
@@ -10313,8 +10604,8 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   p = build_plt_stub (htab, stub_entry, p, offset, r);
   bfd_put_32 (obfd, BCTRL, p - 4);
 
-  bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p),        p += 4;
   bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p),    p += 4;
+  bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p),        p += 4;
   bfd_put_32 (obfd, MTLR_R11, p),              p += 4;
   bfd_put_32 (obfd, BLR, p),                   p += 4;
 
@@ -10356,7 +10647,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)
     {
@@ -10374,14 +10665,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;
 }
 
@@ -10408,8 +10699,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)
@@ -10425,33 +10716,39 @@ 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->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
+         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->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+             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->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
-         loc += 4;
          off -= size - 4;
        }
-      bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
+      bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
 
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
@@ -10464,10 +10761,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)
@@ -10476,16 +10773,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              unsigned long symndx;
              struct ppc_link_hash_entry *h;
 
-             hashes = elf_sym_hashes (htab->stub_bfd);
+             hashes = elf_sym_hashes (htab->params->stub_bfd);
              if (hashes == NULL)
                {
                  bfd_size_type hsize;
 
                  hsize = (htab->stub_globals + 1) * sizeof (*hashes);
-                 hashes = bfd_zalloc (htab->stub_bfd, hsize);
+                 hashes = bfd_zalloc (htab->params->stub_bfd, hsize);
                  if (hashes == NULL)
                    return FALSE;
-                 elf_sym_hashes (htab->stub_bfd) = hashes;
+                 elf_sym_hashes (htab->params->stub_bfd) = hashes;
                  htab->stub_globals = 1;
                }
              symndx = htab->stub_globals++;
@@ -10574,7 +10871,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)
        {
@@ -10588,14 +10885,13 @@ 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
-             && htab->opd_abi)
+         if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
            r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
          r[0].r_addend = dest;
@@ -10608,61 +10904,68 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            }
        }
 
-      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off
-         || !htab->opd_abi)
+      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
        {
          if (PPC_HA (off) != 0)
            {
              size = 16;
-             bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc);
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDIS_R12_R2 | PPC_HA (off), loc);
              loc += 4;
-             bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc);
+             bfd_put_32 (htab->params->stub_bfd,
+                         LD_R12_0R12 | PPC_LO (off), loc);
            }
          else
            {
              size = 12;
-             bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
+             bfd_put_32 (htab->params->stub_bfd,
+                         LD_R12_0R2 | PPC_LO (off), loc);
            }
        }
       else
        {
          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->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
+         bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
          loc += 4;
-         size = 20;
+         size = 16;
          if (PPC_HA (off) != 0)
            {
              size += 4;
-             bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc);
-             loc += 4;
-             bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc);
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDIS_R12_R2 | PPC_HA (off), loc);
              loc += 4;
+             bfd_put_32 (htab->params->stub_bfd,
+                         LD_R12_0R12 | PPC_LO (off), loc);
            }
          else
+           bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
+
+         if (PPC_HA (r2off) != 0)
            {
-             bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
+             size += 4;
              loc += 4;
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDIS_R2_R2 | PPC_HA (r2off), loc);
            }
-
-         if (PPC_HA (r2off) != 0)
+         if (PPC_LO (r2off) != 0)
            {
              size += 4;
-             bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
              loc += 4;
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDI_R2_R2 | PPC_LO (r2off), loc);
            }
-         bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
        }
       loc += 4;
-      bfd_put_32 (htab->stub_bfd, MTCTR_R12, loc);
+      bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, loc);
       loc += 4;
-      bfd_put_32 (htab->stub_bfd, BCTR, loc);
+      bfd_put_32 (htab->params->stub_bfd, BCTR, loc);
       break;
 
     case ppc_stub_plt_call:
@@ -10674,11 +10977,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.  */
@@ -10722,7 +11021,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)
        {
@@ -10736,26 +11035,27 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          return FALSE;
        }
 
-      if (htab->plt_stub_align != 0)
+      if (htab->params->plt_stub_align != 0)
        {
          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,
-                         (2
-                          + (PPC_HA (off) != 0)
-                          + (htab->plt_static_chain
-                             && PPC_HA (off + 16) == PPC_HA (off))));
+         r = get_relocs (stub_entry->group->stub_sec,
+                         ((PPC_HA (off) != 0)
+                          + (htab->opd_abi
+                             ? 2 + (htab->params->plt_static_chain
+                                    && PPC_HA (off + 16) == PPC_HA (off))
+                             : 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;
@@ -10763,21 +11063,24 @@ 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->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->emit_stub_syms)
+  if (htab->params->emit_stub_syms)
     {
       struct elf_link_hash_entry *h;
       size_t len1, len2;
@@ -10803,13 +11106,14 @@ 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;
          h->ref_regular_nonweak = 1;
          h->forced_local = 1;
          h->non_elf = 0;
+         h->root.linker_def = 1;
        }
     }
 
@@ -10837,6 +11141,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)
     {
@@ -10852,20 +11168,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->plt_stub_align)
+      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->plt_static_chain
+                  ? 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
@@ -10878,9 +11194,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.  */
@@ -10891,14 +11207,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;
        }
 
@@ -10908,7 +11226,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;
 
@@ -10943,16 +11262,16 @@ 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
-             || !htab->opd_abi)
+         if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
            {
              size = 12;
              if (PPC_HA (off) != 0)
@@ -10960,22 +11279,24 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            }
          else
            {
-             size = 20;
+             size = 16;
              if (PPC_HA (off) != 0)
                size += 4;
 
              if (PPC_HA (r2off) != 0)
                size += 4;
+             if (PPC_LO (r2off) != 0)
+               size += 4;
            }
        }
       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;
 }
 
@@ -10984,65 +11305,24 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
    0 when no stubs will be needed, and 1 on success.  */
 
 int
-ppc64_elf_setup_section_lists
-  (struct bfd_link_info *info,
-   asection *(*add_stub_section) (const char *, asection *),
-   void (*layout_sections_again) (void))
-{
-  bfd *input_bfd;
-  int top_id, top_index, id;
-  asection *section;
-  asection **input_list;
+ppc64_elf_setup_section_lists (struct bfd_link_info *info)
+{
+  unsigned int id;
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
     return -1;
-  /* Stash our params away.  */
-  htab->add_stub_section = add_stub_section;
-  htab->layout_sections_again = layout_sections_again;
-
-  /* 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;
 }
@@ -11093,6 +11373,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
@@ -11186,7 +11467,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
   elf_link_hash_traverse (&htab->elf, merge_global_got, info);
 
   /* And tlsld_got.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry *ent, *ent2;
 
@@ -11197,7 +11478,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       if (!ent->is_indirect
          && ent->got.offset != (bfd_vma) -1)
        {
-         for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next)
+         for (ibfd2 = ibfd->link.next; ibfd2 != NULL; ibfd2 = ibfd2->link.next)
            {
              if (!is_ppc64_elf (ibfd2))
                continue;
@@ -11219,7 +11500,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
   htab->elf.irelplt->size -= htab->got_reli_size;
   htab->got_reli_size = 0;
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       asection *got, *relgot;
 
@@ -11239,7 +11520,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 
   /* Now reallocate the got, local syms first.  We don't need to
      allocate section contents again since we never increase size.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry **lgot_ents;
       struct got_entry **end_lgot_ents;
@@ -11285,7 +11566,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;
@@ -11296,7 +11577,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 
   elf_link_hash_traverse (&htab->elf, reallocate_got, info);
 
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       struct got_entry *ent;
 
@@ -11310,7 +11591,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);
@@ -11320,7 +11601,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 
   done_something = htab->elf.irelplt->rawsize != htab->elf.irelplt->size;
   if (!done_something)
-    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
       {
        asection *got;
 
@@ -11337,7 +11618,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       }
 
   if (done_something)
-    (*htab->layout_sections_again) ();
+    (*htab->params->layout_sections_again) ();
 
   /* Set up for second pass over toc sections to recalculate elf_gp
      on input sections.  */
@@ -11473,7 +11754,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
                {
                  long adjust;
 
-                 adjust = opd->adjust[sym->st_value / 8];
+                 adjust = opd->adjust[OPD_NDX (sym_value)];
                  if (adjust == -1)
                    /* Assume deleted functions won't ever be called.  */
                    continue;
@@ -11590,15 +11871,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)
@@ -11622,7 +11901,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;
 }
 
@@ -11644,8 +11923,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;
          }
 
@@ -11653,14 +11932,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;
 }
@@ -11679,17 +11958,22 @@ 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;
+  stub14_group_size = stub_group_size >> 10;
   if (stub_group_size == 1)
     {
       /* Default values.  */
@@ -11706,10 +11990,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;
@@ -11717,6 +12005,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;
@@ -11726,14 +12015,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
@@ -11746,11 +12035,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);
 
@@ -11767,19 +12064,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[] =
@@ -11793,7 +12088,8 @@ static const unsigned char glink_eh_frame_cie[] =
   65,                                  /* RA reg.  */
   1,                                   /* Augmentation size.  */
   DW_EH_PE_pcrel | DW_EH_PE_sdata4,    /* FDE encoding.  */
-  DW_CFA_def_cfa, 1, 0                 /* def_cfa: r1 offset 0.  */
+  DW_CFA_def_cfa, 1, 0,                        /* def_cfa: r1 offset 0.  */
+  0, 0, 0, 0
 };
 
 /* Stripping output sections is normally done before dynamic section
@@ -11824,9 +12120,7 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec)
    instruction.  */
 
 bfd_boolean
-ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
-                     bfd_boolean plt_static_chain, int plt_thread_safe,
-                     int plt_stub_align)
+ppc64_elf_size_stubs (struct bfd_link_info *info)
 {
   bfd_size_type stub_group_size;
   bfd_boolean stubs_always_before_branch;
@@ -11835,13 +12129,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
   if (htab == NULL)
     return FALSE;
 
-  htab->plt_static_chain = plt_static_chain;
-  htab->plt_stub_align = plt_stub_align;
-  if (plt_thread_safe == -1 && !info->executable)
-    plt_thread_safe = 1;
+  if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
+    htab->params->plt_thread_safe = 1;
   if (!htab->opd_abi)
-    plt_thread_safe = 0;
-  else if (plt_thread_safe == -1)
+    htab->params->plt_thread_safe = 0;
+  else if (htab->params->plt_thread_safe == -1)
     {
       static const char *const thread_starter[] =
        {
@@ -11854,45 +12146,54 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
          /* libanl */
          "getaddrinfo_a",
          /* libgomp */
+         "GOMP_parallel",
          "GOMP_parallel_start",
+         "GOMP_parallel_loop_static",
          "GOMP_parallel_loop_static_start",
+         "GOMP_parallel_loop_dynamic",
          "GOMP_parallel_loop_dynamic_start",
+         "GOMP_parallel_loop_guided",
          "GOMP_parallel_loop_guided_start",
+         "GOMP_parallel_loop_runtime",
          "GOMP_parallel_loop_runtime_start",
+         "GOMP_parallel_sections",
          "GOMP_parallel_sections_start",
+         /* libgo */
+         "__go_go",
        };
       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],
                                    FALSE, FALSE, TRUE);
-         plt_thread_safe = h != NULL && h->ref_regular;
-         if (plt_thread_safe)
+         htab->params->plt_thread_safe = h != NULL && h->ref_regular;
+         if (htab->params->plt_thread_safe)
            break;
        }
     }
-  htab->plt_thread_safe = plt_thread_safe;
-  stubs_always_before_branch = group_size < 0;
-  if (group_size < 0)
-    stub_group_size = -group_size;
+  stubs_always_before_branch = htab->params->group_size < 0;
+  if (htab->params->group_size < 0)
+    stub_group_size = -htab->params->group_size;
   else
-    stub_group_size = group_size;
+    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;
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
-          input_bfd = input_bfd->link_next, bfd_indx++)
+          input_bfd = input_bfd->link.next, bfd_indx++)
        {
          Elf_Internal_Shdr *symtab_hdr;
          asection *section;
@@ -11987,7 +12288,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                  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)
@@ -12045,7 +12348,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 
                      if (hash == NULL && opd->adjust != NULL)
                        {
-                         long adjust = opd->adjust[sym_value / 8];
+                         long adjust = opd->adjust[OPD_NDX (sym_value)];
                          if (adjust == -1)
                            continue;
                          code_value += adjust;
@@ -12083,8 +12386,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                         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;
@@ -12124,7 +12427,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                    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);
@@ -12194,7 +12497,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 
       /* We may have added some stubs.  Find out the new size of the
         stub sections.  */
-      for (stub_sec = htab->stub_bfd->sections;
+      for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
@@ -12213,6 +12516,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 
       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)
        {
@@ -12226,11 +12533,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
        {
          size_t size = 0, align;
 
-         for (stub_sec = htab->stub_bfd->sections;
+         for (stub_sec = htab->params->stub_bfd->sections;
               stub_sec != NULL;
               stub_sec = stub_sec->next)
            if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-             size += 20;
+             size += 24;
          if (htab->glink != NULL && htab->glink->size != 0)
            size += 24;
          if (size != 0)
@@ -12243,15 +12550,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
          htab->glink_eh_frame->size = size;
        }
 
-      if (htab->plt_stub_align != 0)
-       for (stub_sec = htab->stub_bfd->sections;
+      if (htab->params->plt_stub_align != 0)
+       for (stub_sec = htab->params->stub_bfd->sections;
             stub_sec != NULL;
             stub_sec = stub_sec->next)
          if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-           stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
-                             & (-1 << htab->plt_stub_align));
+           stub_sec->size = ((stub_sec->size
+                              + (1 << htab->params->plt_stub_align) - 1)
+                             & -(1 << htab->params->plt_stub_align));
 
-      for (stub_sec = htab->stub_bfd->sections;
+      for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
@@ -12266,55 +12574,166 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
        break;
 
       /* Ask the linker to do its stuff.  */
-      (*htab->layout_sections_again) ();
+      (*htab->params->layout_sections_again) ();
     }
 
-  maybe_strip_output (info, htab->brlt);
-  if (htab->glink_eh_frame != NULL)
-    maybe_strip_output (info, htab->glink_eh_frame);
-
-  return TRUE;
-}
-
-/* Called after we have determined section placement.  If sections
-   move, we'll be called again.  Provide a value for TOCstart.  */
-
-bfd_vma
-ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
-{
-  asection *s;
-  bfd_vma TOCstart;
-
-  /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
-     order.  The TOC starts where the first of these sections starts.  */
-  s = bfd_get_section_by_name (obfd, ".got");
-  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
-    s = bfd_get_section_by_name (obfd, ".toc");
-  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
-    s = bfd_get_section_by_name (obfd, ".tocbss");
-  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
-    s = bfd_get_section_by_name (obfd, ".plt");
-  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0)
     {
-      /* This may happen for
-        o  references to TOC base (SYM@toc / TOC[tc0]) without a
-        .toc directive
-        o  bad linker script
-        o --gc-sections and empty TOC sections
+      bfd_vma val;
+      bfd_byte *p, *last_fde;
+      size_t last_fde_len, size, align, pad;
+      asection *stub_sec;
 
-        FIXME: Warn user?  */
+      p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
+      if (p == NULL)
+       return FALSE;
+      htab->glink_eh_frame->contents = p;
+      last_fde = p;
 
-      /* Look for a likely section.  We probably won't even be
-        using TOCstart.  */
-      for (s = obfd->sections; s != NULL; s = s->next)
-       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY
-                        | SEC_EXCLUDE))
-           == (SEC_ALLOC | SEC_SMALL_DATA))
-         break;
-      if (s == NULL)
-       for (s = obfd->sections; s != NULL; s = s->next)
-         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE))
-             == (SEC_ALLOC | SEC_SMALL_DATA))
+      memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
+      /* CIE length (rewrite in case little-endian).  */
+      last_fde_len = sizeof (glink_eh_frame_cie) - 4;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
+      p += sizeof (glink_eh_frame_cie);
+
+      for (stub_sec = htab->params->stub_bfd->sections;
+          stub_sec != NULL;
+          stub_sec = stub_sec->next)
+       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+         {
+           last_fde = p;
+           last_fde_len = 20;
+           /* FDE length.  */
+           bfd_put_32 (htab->elf.dynobj, 20, p);
+           p += 4;
+           /* CIE pointer.  */
+           val = p - htab->glink_eh_frame->contents;
+           bfd_put_32 (htab->elf.dynobj, val, p);
+           p += 4;
+           /* Offset to stub section, written later.  */
+           p += 4;
+           /* stub section size.  */
+           bfd_put_32 (htab->elf.dynobj, stub_sec->size, p);
+           p += 4;
+           /* Augmentation.  */
+           p += 1;
+           /* Pad.  */
+           p += 7;
+         }
+      if (htab->glink != NULL && htab->glink->size != 0)
+       {
+         last_fde = p;
+         last_fde_len = 20;
+         /* FDE length.  */
+         bfd_put_32 (htab->elf.dynobj, 20, p);
+         p += 4;
+         /* CIE pointer.  */
+         val = p - htab->glink_eh_frame->contents;
+         bfd_put_32 (htab->elf.dynobj, val, p);
+         p += 4;
+         /* Offset to .glink, written later.  */
+         p += 4;
+         /* .glink size.  */
+         bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p);
+         p += 4;
+         /* Augmentation.  */
+         p += 1;
+
+         *p++ = DW_CFA_advance_loc + 1;
+         *p++ = DW_CFA_register;
+         *p++ = 65;
+         *p++ = htab->opd_abi ? 12 : 0;
+         *p++ = DW_CFA_advance_loc + 4;
+         *p++ = DW_CFA_restore_extended;
+         *p++ = 65;
+       }
+      /* Subsume any padding into the last FDE if user .eh_frame
+        sections are aligned more than glink_eh_frame.  Otherwise any
+        zero padding will be seen as a terminator.  */
+      size = p - htab->glink_eh_frame->contents;
+      align = 1;
+      align <<= htab->glink_eh_frame->output_section->alignment_power;
+      align -= 1;
+      pad = ((size + align) & ~align) - size;
+      htab->glink_eh_frame->size = size + pad;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
+    }
+
+  maybe_strip_output (info, htab->brlt);
+  if (htab->glink_eh_frame != NULL)
+    maybe_strip_output (info, htab->glink_eh_frame);
+
+  return TRUE;
+}
+
+/* Called after we have determined section placement.  If sections
+   move, we'll be called again.  Provide a value for TOCstart.  */
+
+bfd_vma
+ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
+{
+  asection *s;
+  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.  */
+  s = bfd_get_section_by_name (obfd, ".got");
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
+    s = bfd_get_section_by_name (obfd, ".toc");
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
+    s = bfd_get_section_by_name (obfd, ".tocbss");
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
+    s = bfd_get_section_by_name (obfd, ".plt");
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
+    {
+      /* This may happen for
+        o  references to TOC base (SYM@toc / TOC[tc0]) without a
+        .toc directive
+        o  bad linker script
+        o --gc-sections and empty TOC sections
+
+        FIXME: Warn user?  */
+
+      /* Look for a likely section.  We probably won't even be
+        using TOCstart.  */
+      for (s = obfd->sections; s != NULL; s = s->next)
+       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY
+                        | SEC_EXCLUDE))
+           == (SEC_ALLOC | SEC_SMALL_DATA))
+         break;
+      if (s == NULL)
+       for (s = obfd->sections; s != NULL; s = s->next)
+         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE))
+             == (SEC_ALLOC | SEC_SMALL_DATA))
            break;
       if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
@@ -12331,17 +12750,29 @@ 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 && is_ppc64_elf (obfd))
+  if (info != NULL && s != NULL)
     {
       struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-      if (htab != NULL
-         && htab->elf.hgot != NULL)
+      if (htab != NULL)
+       {
+         if (htab->elf.hgot != NULL)
+           {
+             htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust;
+             htab->elf.hgot->root.u.def.section = s;
+           }
+       }
+      else
        {
-         htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
-         htab->elf.hgot->root.u.def.section = s;
+         struct bfd_link_hash_entry *bh = NULL;
+         _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
+                                           s, TOC_BASE_OFF - adjust,
+                                           NULL, FALSE, FALSE, &bh);
        }
     }
   return TOCstart;
@@ -12381,13 +12812,6 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
        asection *plt;
        bfd_vma off;
 
-       /* For ELFv2, if this symbol is not defined in a regular file
-          and we are not generating a shared library or pie, then we
-          need to define the symbol in the executable on a call stub.
-          This is to avoid text relocations.  */
-       h->root.u.def.section = s;
-       h->root.u.def.value = s->size;
-       s->size += 16;
        p = s->contents + h->root.u.def.value;
        plt = htab->elf.splt;
        if (!htab->elf.dynamic_sections_created
@@ -12405,6 +12829,33 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
            htab->stub_error = TRUE;
          }
 
+       htab->stub_count[ppc_stub_global_entry - 1] += 1;
+       if (htab->params->emit_stub_syms)
+         {
+           size_t len = strlen (h->root.root.string);
+           char *name = bfd_malloc (sizeof "12345678.global_entry." + len);
+
+           if (name == NULL)
+             return FALSE;
+
+           sprintf (name, "%08x.global_entry.%s", s->id, h->root.root.string);
+           h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
+           if (h == NULL)
+             return FALSE;
+           if (h->root.type == bfd_link_hash_new)
+             {
+               h->root.type = bfd_link_hash_defined;
+               h->root.u.def.section = s;
+               h->root.u.def.value = p - s->contents;
+               h->ref_regular = 1;
+               h->def_regular = 1;
+               h->ref_regular_nonweak = 1;
+               h->forced_local = 1;
+               h->non_elf = 0;
+               h->root.linker_def = 1;
+             }
+         }
+
        if (PPC_HA (off) != 0)
          {
            bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p);
@@ -12425,11 +12876,11 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
    hash table.  This function is called via gldelf64ppc_finish.  */
 
 bfd_boolean
-ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
-                      struct bfd_link_info *info,
+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;
@@ -12437,16 +12888,14 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
   if (htab == NULL)
     return FALSE;
 
-  htab->emit_stub_syms = emit_stub_syms;
-
   /* Allocate memory to hold the linker stubs.  */
-  for (stub_sec = htab->stub_bfd->sections;
+  for (stub_sec = htab->params->stub_bfd->sections;
        stub_sec != NULL;
        stub_sec = stub_sec->next)
     if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
        && stub_sec->size != 0)
       {
-       stub_sec->contents = bfd_zalloc (htab->stub_bfd, stub_sec->size);
+       stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
        if (stub_sec->contents == NULL)
          return FALSE;
        /* We want to check that built size is the same as calculated
@@ -12461,7 +12910,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       bfd_vma plt0;
 
       /* Build the .glink plt call stub.  */
-      if (htab->emit_stub_syms)
+      if (htab->params->emit_stub_syms)
        {
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
@@ -12478,6 +12927,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
              h->ref_regular_nonweak = 1;
              h->forced_local = 1;
              h->non_elf = 0;
+             h->root.linker_def = 1;
            }
        }
       plt0 = (htab->elf.splt->output_section->vma
@@ -12583,13 +13033,10 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
 
       /* Build .glink global entry stubs.  */
       if (htab->glink->size > htab->glink->rawsize)
-       {
-         htab->glink->size = (htab->glink->rawsize + 15) & -16;
-         elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
-       }
+       elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
     }
 
-  if (htab->brlt->size != 0)
+  if (htab->brlt != NULL && htab->brlt->size != 0)
     {
       htab->brlt->contents = bfd_zalloc (htab->brlt->owner,
                                         htab->brlt->size);
@@ -12604,132 +13051,39 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
        return FALSE;
     }
 
-  if (htab->glink_eh_frame != NULL
-      && htab->glink_eh_frame->size != 0)
-    {
-      bfd_vma val;
-      bfd_byte *last_fde;
-      size_t last_fde_len, size, align, pad;
-
-      p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
-      if (p == NULL)
-       return FALSE;
-      htab->glink_eh_frame->contents = p;
-      last_fde = p;
-
-      htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
-
-      memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
-      /* CIE length (rewrite in case little-endian).  */
-      last_fde_len = sizeof (glink_eh_frame_cie) - 4;
-      bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
-      p += sizeof (glink_eh_frame_cie);
+  /* Build the stubs as directed by the stub hash table.  */
+  bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
-      for (stub_sec = htab->stub_bfd->sections;
-          stub_sec != NULL;
-          stub_sec = stub_sec->next)
-       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+  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)
          {
-           last_fde = p;
-           last_fde_len = 16;
-           /* FDE length.  */
-           bfd_put_32 (htab->elf.dynobj, 16, p);
-           p += 4;
-           /* CIE pointer.  */
-           val = p - htab->glink_eh_frame->contents;
-           bfd_put_32 (htab->elf.dynobj, val, p);
-           p += 4;
-           /* Offset to stub section.  */
-           val = (stub_sec->output_section->vma
-                  + stub_sec->output_offset);
-           val -= (htab->glink_eh_frame->output_section->vma
-                   + htab->glink_eh_frame->output_offset);
-           val -= p - htab->glink_eh_frame->contents;
-           if (val + 0x80000000 > 0xffffffff)
-             {
-               info->callbacks->einfo
-                 (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
-                  stub_sec->name);
+           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;
-             }
-           bfd_put_32 (htab->elf.dynobj, val, p);
-           p += 4;
-           /* stub section size.  */
-           bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p);
-           p += 4;
-           /* Augmentation.  */
-           p += 1;
-           /* Pad.  */
-           p += 3;
          }
-      if (htab->glink != NULL && htab->glink->size != 0)
-       {
-         last_fde = p;
-         last_fde_len = 20;
-         /* FDE length.  */
-         bfd_put_32 (htab->elf.dynobj, 20, p);
-         p += 4;
-         /* CIE pointer.  */
-         val = p - htab->glink_eh_frame->contents;
-         bfd_put_32 (htab->elf.dynobj, val, p);
-         p += 4;
-         /* Offset to .glink.  */
-         val = (htab->glink->output_section->vma
-                + htab->glink->output_offset
-                + 8);
-         val -= (htab->glink_eh_frame->output_section->vma
-                 + htab->glink_eh_frame->output_offset);
-         val -= p - htab->glink_eh_frame->contents;
-         if (val + 0x80000000 > 0xffffffff)
-           {
-             info->callbacks->einfo
-               (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
-                htab->glink->name);
-             return FALSE;
-           }
-         bfd_put_32 (htab->elf.dynobj, val, p);
-         p += 4;
-         /* .glink size.  */
-         bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p);
-         p += 4;
-         /* Augmentation.  */
-         p += 1;
-
-         *p++ = DW_CFA_advance_loc + 1;
-         *p++ = DW_CFA_register;
-         *p++ = 65;
-         *p++ = 12;
-         *p++ = DW_CFA_advance_loc + 4;
-         *p++ = DW_CFA_restore_extended;
-         *p++ = 65;
-       }
-      /* Subsume any padding into the last FDE if user .eh_frame
-        sections are aligned more than glink_eh_frame.  Otherwise any
-        zero padding will be seen as a terminator.  */
-      size = p - htab->glink_eh_frame->contents;
-      align = 1;
-      align <<= htab->glink_eh_frame->output_section->alignment_power;
-      align -= 1;
-      pad = ((size + align) & ~align) - size;
-      htab->glink_eh_frame->size = size + pad;
-      bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
-    }
-
-  /* Build the stubs as directed by the stub hash table.  */
-  bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
+       stub_sec->size += htab->sfpr->size;
+      }
 
   if (htab->relbrlt != NULL)
     htab->relbrlt->reloc_count = 0;
 
-  if (htab->plt_stub_align != 0)
-    for (stub_sec = htab->stub_bfd->sections;
+  if (htab->params->plt_stub_align != 0)
+    for (stub_sec = htab->params->stub_bfd->sections;
         stub_sec != NULL;
         stub_sec = stub_sec->next)
       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
-       stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
-                         & (-1 << htab->plt_stub_align));
+       stub_sec->size = ((stub_sec->size
+                          + (1 << htab->params->plt_stub_align) - 1)
+                         & -(1 << htab->params->plt_stub_align));
 
-  for (stub_sec = htab->stub_bfd->sections;
+  for (stub_sec = htab->params->stub_bfd->sections;
        stub_sec != NULL;
        stub_sec = stub_sec->next)
     if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
@@ -12739,6 +13093,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
          break;
       }
 
+  /* Note that the glink_eh_frame check here is not only testing that
+     the generated size matched the calculated size but also that
+     bfd_elf_discard_info didn't make any changes to the section.  */
   if (stub_sec != NULL
       || (htab->glink_eh_frame != NULL
          && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
@@ -12762,7 +13119,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
                         "  long branch  %lu\n"
                         "  long toc adj %lu\n"
                         "  plt call     %lu\n"
-                        "  plt call toc %lu"),
+                        "  plt call toc %lu\n"
+                        "  global entry %lu"),
               stub_sec_count,
               stub_sec_count == 1 ? "" : "s",
               htab->stub_count[ppc_stub_long_branch - 1],
@@ -12770,7 +13128,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
               htab->stub_count[ppc_stub_plt_branch - 1],
               htab->stub_count[ppc_stub_plt_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_call - 1],
-              htab->stub_count[ppc_stub_plt_call_r2save - 1]);
+              htab->stub_count[ppc_stub_plt_call_r2save - 1],
+              htab->stub_count[ppc_stub_global_entry - 1]);
     }
   return TRUE;
 }
@@ -12863,6 +13222,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;
@@ -12883,7 +13243,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
     return FALSE;
 
   /* Don't relocate stub sections.  */
-  if (input_section->owner == htab->stub_bfd)
+  if (input_section->owner == htab->params->stub_bfd)
     return TRUE;
 
   BFD_ASSERT (is_ppc64_elf (input_bfd));
@@ -12894,9 +13254,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;
@@ -12920,7 +13280,12 @@ 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);
@@ -12929,10 +13294,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;
@@ -12954,7 +13319,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          opd = get_opd_info (sec);
          if (opd != NULL && opd->adjust != NULL)
            {
-             long adjust = opd->adjust[(sym->st_value + rel->r_addend) / 8];
+             long adjust = opd->adjust[OPD_NDX (sym->st_value
+                                                + rel->r_addend)];
              if (adjust == -1)
                relocation = 0;
              else
@@ -12973,10 +13339,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
       else
        {
+         bfd_boolean ignored;
+
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h_elf, sec, relocation,
-                                  unresolved_reloc, warned);
+                                  unresolved_reloc, warned, ignored);
          sym_name = h_elf->root.root.string;
          sym_type = h_elf->type;
          if (sec != NULL
@@ -13010,18 +13378,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;
        }
@@ -13177,10 +13558,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)
                {
@@ -13188,8 +13571,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);
@@ -13215,8 +13597,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);
@@ -13275,12 +13656,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                              htab->tls_get_addr,
                                              htab->tls_get_addr_fd))
                offset = rel[1].r_offset;
+             /* We read the low GOT_TLS (or TOC16) insn because we
+                need to keep the destination reg.  It may be
+                something other than the usual r3, and moved to r3
+                before the call by intervening code.  */
+             insn1 = bfd_get_32 (output_bfd,
+                                 contents + rel->r_offset - d_offset);
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
-                 insn1 = bfd_get_32 (output_bfd,
-                                     contents + rel->r_offset - d_offset);
-                 insn1 &= (1 << 26) - (1 << 2);
+                 insn1 &= (0x1f << 21) | (0x1f << 16);
                  insn1 |= 58 << 26;    /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
                  if (offset != (bfd_vma) -1)
@@ -13295,7 +13680,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              else
                {
                  /* LE */
-                 insn1 = 0x3c6d0000;   /* addis 3,13,0 */
+                 insn1 &= 0x1f << 21;
+                 insn1 |= 0x3c0d0000;  /* addis r,13,0 */
                  insn2 = 0x38630000;   /* addi 3,3,0 */
                  if (tls_gd == 0)
                    {
@@ -13350,8 +13736,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;
@@ -13395,10 +13780,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;
 
@@ -13440,8 +13822,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  insn2 = NOP;
                }
              bfd_put_32 (output_bfd, insn2, contents + offset);
-             rel--;
-             continue;
+             goto again;
            }
          break;
 
@@ -13482,6 +13863,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
@@ -13490,7 +13917,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)
@@ -13502,15 +13932,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;
@@ -13602,7 +14032,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          if (h != NULL
                              && (h == htab->tls_get_addr_fd
                                  || h == htab->tls_get_addr)
-                             && !htab->no_tls_get_addr_opt)
+                             && htab->params->tls_get_addr_opt)
                            {
                              /* Special stub used, leave nop alone.  */
                            }
@@ -13658,10 +14088,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (!can_plt_call)
                {
-                 info->callbacks->einfo
-                   (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
-                      "recompile with -fPIC"),
-                    input_bfd, input_section, rel->r_offset, sym_name);
+                 if (stub_entry->stub_type == ppc_stub_plt_call
+                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+                   info->callbacks->einfo
+                     (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
+                        "recompile with -fPIC\n"),
+                      input_bfd, input_section, rel->r_offset, sym_name);
+                 else
+                   info->callbacks->einfo
+                     (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
+                        "(-mcmodel=small toc adjust stub)\n"),
+                      input_bfd, input_section, rel->r_offset, sym_name);
 
                  bfd_set_error (bfd_error_bad_value);
                  ret = FALSE;
@@ -13715,9 +14152,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;
 
@@ -13766,7 +14212,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;
        }
@@ -13782,7 +14228,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:
@@ -13791,7 +14237,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
@@ -13851,10 +14298,10 @@ 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
-                           && SYMBOL_CALLS_LOCAL (info, &h->elf)))
+                       || (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
                         locally, or the symbol was forced to be local
@@ -13912,7 +14359,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)
@@ -13966,7 +14413,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      {
                        outrel.r_addend += relocation;
                        if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
-                         outrel.r_addend -= htab->elf.tls_sec->vma;
+                         {
+                           if (htab->elf.tls_sec == NULL)
+                             outrel.r_addend = 0;
+                           else
+                             outrel.r_addend -= htab->elf.tls_sec->vma;
+                         }
                      }
                    loc = relgot->contents;
                    loc += (relgot->reloc_count++
@@ -13983,9 +14435,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      relocation = 1;
                    else if (tls_type != 0)
                      {
-                       relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
-                       if (tls_type == (TLS_TLS | TLS_TPREL))
-                         relocation += DTP_OFFSET - TP_OFFSET;
+                       if (htab->elf.tls_sec == NULL)
+                         relocation = 0;
+                       else
+                         {
+                           relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
+                           if (tls_type == (TLS_TLS | TLS_TPREL))
+                             relocation += DTP_OFFSET - TP_OFFSET;
+                         }
 
                        if (tls_type == (TLS_TLS | TLS_GD))
                          {
@@ -14004,7 +14461,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;
 
@@ -14015,41 +14472,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;
@@ -14064,7 +14534,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.  */
@@ -14082,6 +14552,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:
@@ -14118,8 +14589,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                bfd_put_32 (output_bfd, insn, p);
              break;
            }
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
-         if (info->shared)
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         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.  */
@@ -14138,7 +14610,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_DTPREL16_HIGHERA:
        case R_PPC64_DTPREL16_HIGHEST:
        case R_PPC64_DTPREL16_HIGHESTA:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         break;
+
+       case R_PPC64_ADDR64_LOCAL:
+         addend += PPC64_LOCAL_ENTRY_OFFSET (h != NULL
+                                             ? h->elf.other
+                                             : sym->st_other);
          break;
 
        case R_PPC64_DTPMOD64:
@@ -14147,11 +14626,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          goto dodyn;
 
        case R_PPC64_TPREL64:
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          goto dodyn;
 
        case R_PPC64_DTPREL64:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          /* Fall thru */
 
          /* Relocations that may need to be propagated if this is a
@@ -14187,19 +14668,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)))
@@ -14239,7 +14720,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
+             else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                {
@@ -14407,7 +14888,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
@@ -14477,12 +14958,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
 
       /* Do any further special processing.  */
+      howto = ppc64_elf_howto_table[(int) r_type];
       switch (r_type)
        {
        default:
          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:
@@ -14538,24 +15021,28 @@ 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,
-                ppc64_elf_howto_table[r_type]->name,
+                howto->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
              ret = FALSE;
-             continue;
+             goto copy_reloc;
            }
          break;
        }
@@ -14572,23 +15059,68 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          info->callbacks->einfo
            (_("%P: %H: unresolvable %s against `%T'\n"),
             input_bfd, input_section, rel->r_offset,
-            ppc64_elf_howto_table[(int) r_type]->name,
+            howto->name,
             h->elf.root.root.string);
          ret = FALSE;
        }
 
-      r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
-                                   input_bfd,
-                                   input_section,
-                                   contents,
-                                   rel->r_offset,
-                                   relocation,
-                                   addend);
+      /* 16-bit fields in insns mostly have signed values, but a
+        few insns have 16-bit unsigned values.  Really, we should
+        have different reloc types.  */
+      if (howto->complain_on_overflow != complain_overflow_dont
+         && howto->dst_mask == 0xffff
+         && (input_section->flags & SEC_CODE) != 0)
+       {
+         enum complain_overflow complain = complain_overflow_signed;
+
+         insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+         if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+           complain = complain_overflow_bitfield;
+         else if (howto->rightshift == 0
+                  ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+                     || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+                     || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+                  : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+                     || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+                     || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+           complain = complain_overflow_unsigned;
+         if (howto->complain_on_overflow != complain)
+           {
+             alt_howto = *howto;
+             alt_howto.complain_on_overflow = complain;
+             howto = &alt_howto;
+           }
+       }
+
+      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)
        {
          char *more_info = NULL;
-         const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
+         const char *reloc_name = howto->name;
 
          if (reloc_dest != DEST_NORMAL)
            {
@@ -14604,26 +15136,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          if (r == bfd_reloc_overflow)
            {
-             if (warned)
-               continue;
-             if (h != NULL
-                 && h->elf.root.type == bfd_link_hash_undefweak
-                 && ppc64_elf_howto_table[r_type]->pc_relative)
-               {
-                 /* Assume this is a call protected by other code that
-                    detects the symbol is undefined.  If this is the case,
-                    we can safely ignore the overflow.  If not, the
-                    program is hosed anyway, and a little warning isn't
-                    going to help.  */
-
-                 continue;
-               }
-
-             if (!((*info->callbacks->reloc_overflow)
-                   (info, &h->elf.root, sym_name,
-                    reloc_name, orig_rel.r_addend,
-                    input_bfd, input_section, rel->r_offset)))
-               return FALSE;
+             /* On code like "if (foo) foo();" don't report overflow
+                on a branch to zero when foo is undefined.  */
+             if (!warned
+                 && (reloc_dest == DEST_STUB
+                     || !(h != NULL
+                          && (h->elf.root.type == bfd_link_hash_undefweak
+                              || h->elf.root.type == bfd_link_hash_undefined)
+                          && is_branch_reloc (r_type))))
+               info->callbacks->reloc_overflow (info, &h->elf.root,
+                                                sym_name, reloc_name,
+                                                orig_rel.r_addend,
+                                                input_bfd, input_section,
+                                                rel->r_offset);
            }
          else
            {
@@ -14636,6 +15161,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
@@ -14643,7 +15191,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);
@@ -14678,10 +15226,10 @@ 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[value / 8];
+  adjust = opd->adjust[OPD_NDX (value)];
   if (adjust == -1)
     return 2;
 
@@ -14969,18 +15517,86 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                       NULL))
     return FALSE;
 
-
   if (htab->glink_eh_frame != NULL
-      && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
-      && !_bfd_elf_write_section_eh_frame (output_bfd, info,
-                                          htab->glink_eh_frame,
-                                          htab->glink_eh_frame->contents))
-    return FALSE;
+      && htab->glink_eh_frame->size != 0)
+    {
+      bfd_vma val;
+      bfd_byte *p;
+      asection *stub_sec;
+
+      p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie);
+      for (stub_sec = htab->params->stub_bfd->sections;
+          stub_sec != NULL;
+          stub_sec = stub_sec->next)
+       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+         {
+           /* FDE length.  */
+           p += 4;
+           /* CIE pointer.  */
+           p += 4;
+           /* Offset to stub section.  */
+           val = (stub_sec->output_section->vma
+                  + stub_sec->output_offset);
+           val -= (htab->glink_eh_frame->output_section->vma
+                   + htab->glink_eh_frame->output_offset
+                   + (p - htab->glink_eh_frame->contents));
+           if (val + 0x80000000 > 0xffffffff)
+             {
+               info->callbacks->einfo
+                 (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
+                  stub_sec->name);
+               return FALSE;
+             }
+           bfd_put_32 (dynobj, val, p);
+           p += 4;
+           /* stub section size.  */
+           p += 4;
+           /* Augmentation.  */
+           p += 1;
+           /* Pad.  */
+           p += 7;
+         }
+      if (htab->glink != NULL && htab->glink->size != 0)
+       {
+         /* FDE length.  */
+         p += 4;
+         /* CIE pointer.  */
+         p += 4;
+         /* Offset to .glink.  */
+         val = (htab->glink->output_section->vma
+                + htab->glink->output_offset
+                + 8);
+         val -= (htab->glink_eh_frame->output_section->vma
+                 + htab->glink_eh_frame->output_offset
+                 + (p - htab->glink_eh_frame->contents));
+         if (val + 0x80000000 > 0xffffffff)
+           {
+             info->callbacks->einfo
+               (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
+                htab->glink->name);
+             return FALSE;
+           }
+         bfd_put_32 (dynobj, val, p);
+         p += 4;
+         /* .glink size.  */
+         p += 4;
+         /* Augmentation.  */
+         p += 1;
+         /* Ops.  */
+         p += 7;
+       }
+
+      if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
+         && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+                                              htab->glink_eh_frame,
+                                              htab->glink_eh_frame->contents))
+       return FALSE;
+    }
 
   /* We need to handle writing out multiple GOT sections ourselves,
      since we didn't add them to DYNOBJ.  We know dynobj is the first
      bfd.  */
-  while ((dynobj = dynobj->link_next) != NULL)
+  while ((dynobj = dynobj->link.next) != NULL)
     {
       asection *s;
 
@@ -15016,7 +15632,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 #undef  TARGET_LITTLE_NAME
 
 #undef  TARGET_BIG_SYM
-#define TARGET_BIG_SYM bfd_elf64_powerpc_freebsd_vec
+#define TARGET_BIG_SYM powerpc_elf64_fbsd_vec
 #undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME "elf64-powerpc-freebsd"
 
This page took 0.099894 seconds and 4 git commands to generate.