Automatic date update in version.in
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 90c2cc05d61ce8c606f131457531f5e7fb3dd51d..ae3903289a90b6e00e9b642b85101bc90c35f3d1 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright (C) 1999-2015 Free Software Foundation, Inc.
+   Copyright (C) 1999-2017 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.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
    Largely rewritten by Alan Modra.
@@ -72,9 +72,11 @@ static bfd_vma opd_entry_value
 #define elf_backend_plt_alignment 3
 #define elf_backend_plt_not_loaded 1
 #define elf_backend_got_header_size 8
 #define elf_backend_plt_alignment 3
 #define elf_backend_plt_not_loaded 1
 #define elf_backend_got_header_size 8
+#define elf_backend_want_dynrelro 1
 #define elf_backend_can_gc_sections 1
 #define elf_backend_can_refcount 1
 #define elf_backend_rela_normal 1
 #define elf_backend_can_gc_sections 1
 #define elf_backend_can_refcount 1
 #define elf_backend_rela_normal 1
+#define elf_backend_dtrel_excludes_plt 1
 #define elf_backend_default_execstack 0
 
 #define bfd_elf64_mkobject                   ppc64_elf_mkobject
 #define elf_backend_default_execstack 0
 
 #define bfd_elf64_mkobject                   ppc64_elf_mkobject
@@ -86,12 +88,13 @@ static bfd_vma opd_entry_value
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_get_synthetic_symtab       ppc64_elf_get_synthetic_symtab
 #define bfd_elf64_bfd_link_just_syms         ppc64_elf_link_just_syms
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_get_synthetic_symtab       ppc64_elf_get_synthetic_symtab
 #define bfd_elf64_bfd_link_just_syms         ppc64_elf_link_just_syms
+#define bfd_elf64_bfd_gc_sections            ppc64_elf_gc_sections
 
 #define elf_backend_object_p                 ppc64_elf_object_p
 #define elf_backend_grok_prstatus            ppc64_elf_grok_prstatus
 #define elf_backend_grok_psinfo                      ppc64_elf_grok_psinfo
 #define elf_backend_write_core_note          ppc64_elf_write_core_note
 
 #define elf_backend_object_p                 ppc64_elf_object_p
 #define elf_backend_grok_prstatus            ppc64_elf_grok_prstatus
 #define elf_backend_grok_psinfo                      ppc64_elf_grok_psinfo
 #define elf_backend_write_core_note          ppc64_elf_write_core_note
-#define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
+#define elf_backend_create_dynamic_sections   _bfd_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_before_check_relocs
 #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_before_check_relocs
@@ -117,6 +120,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections         ppc64_elf_special_sections
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections         ppc64_elf_special_sections
 #define elf_backend_merge_symbol_attribute    ppc64_elf_merge_symbol_attribute
+#define elf_backend_merge_symbol             ppc64_elf_merge_symbol
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -138,6 +142,8 @@ static bfd_vma opd_entry_value
 
 /* TOC base pointers offset from start of TOC.  */
 #define TOC_BASE_OFF   0x8000
 
 /* 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
 
 /* Offset of tp and dtp pointers from start of TLS block.  */
 #define TP_OFFSET      0x7000
@@ -171,8 +177,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_0R2      0xe8420000      /* ld    %r2,xxx+0(%r2)  */
 
 #define LD_R2_0R1      0xe8410000      /* ld    %r2,0(%r1)      */
+#define LD_R2_0R12     0xe84c0000      /* ld    %r2,0(%r12)     */
+#define ADD_R2_R2_R12  0x7c426214      /* add   %r2,%r2,%r12    */
 
 
-#define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha     */
+#define LIS_R2         0x3c400000      /* lis %r2,xxx@ha         */
+#define ADDIS_R2_R12   0x3c4c0000      /* addis %r2,%r12,xxx@ha  */
+#define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha  */
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,xxx@ha */
 #define LD_R12_0R12    0xe98c0000      /* ld    %r12,xxx@l(%r12) */
 
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,xxx@ha */
 #define LD_R12_0R12    0xe98c0000      /* ld    %r12,xxx@l(%r12) */
 
@@ -236,6 +246,10 @@ static bfd_vma opd_entry_value
 #define NO_OPD_RELOCS 0
 #endif
 
 #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)
 {
 static inline int
 abiversion (bfd *abfd)
 {
@@ -677,7 +691,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTREL32",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         "R_PPC64_PLTREL32",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -2016,6 +2030,36 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
         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 */
+
+  /* A split-field reloc for addpcis, non-relative (gas internal use only).  */
+  HOWTO (R_PPC64_16DX_HA,      /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_ha_reloc,    /* special_function */
+        "R_PPC64_16DX_HA",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1fffc1,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Like R_PPC64_ADDR16_HI, but no overflow.  */
   HOWTO (R_PPC64_ADDR16_HIGH,  /* type */
         16,                    /* rightshift */
   /* Like R_PPC64_ADDR16_HI, but no overflow.  */
   HOWTO (R_PPC64_ADDR16_HIGH,  /* type */
         16,                    /* rightshift */
@@ -2106,6 +2150,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
         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 */
   /* Like ADDR64, but use local entry point of function.  */
   HOWTO (R_PPC64_ADDR64_LOCAL, /* type */
         0,                     /* rightshift */
@@ -2161,13 +2220,10 @@ ppc_howto_init (void)
 {
   unsigned int i, type;
 
 {
   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;
     {
       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];
     }
 }
       ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i];
     }
 }
@@ -2409,6 +2465,12 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_HI16_S_PCREL:               r = R_PPC64_REL16_HA;
       break;
       break;
     case BFD_RELOC_HI16_S_PCREL:               r = R_PPC64_REL16_HA;
       break;
+    case BFD_RELOC_PPC_16DX_HA:                        r = R_PPC64_16DX_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;
     case BFD_RELOC_PPC64_ADDR64_LOCAL:         r = R_PPC64_ADDR64_LOCAL;
       break;
     case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
@@ -2426,9 +2488,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
 {
   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];
     if (ppc64_elf_howto_raw[i].name != NULL
        && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0)
       return &ppc64_elf_howto_raw[i];
@@ -2439,7 +2499,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
 static void
-ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
                         Elf_Internal_Rela *dst)
 {
   unsigned int type;
                         Elf_Internal_Rela *dst)
 {
   unsigned int type;
@@ -2449,11 +2509,11 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
     ppc_howto_init ();
 
   type = ELF64_R_TYPE (dst->r_info);
     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);
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%B: invalid relocation type %d"),
+                         abfd, (int) type);
       type = R_PPC64_NONE;
     }
   cache_ptr->howto = ppc64_elf_howto_table[type];
       type = R_PPC64_NONE;
     }
   cache_ptr->howto = ppc64_elf_howto_table[type];
@@ -2466,6 +2526,11 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                    void *data, asection *input_section,
                    bfd *output_bfd, char **error_message)
 {
                    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.  */
   /* If this is a relocatable link (output_bfd test tells us), just
      call the generic function.  Any adjustment will be done at final
      link time.  */
@@ -2477,7 +2542,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;
      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
 }
 
 static bfd_reloc_status_type
@@ -2505,6 +2592,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
       elf_symbol_type *elfsym = (elf_symbol_type *) symbol;
 
       if (symbol->section->owner != abfd
       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;
          && abiversion (symbol->section->owner) >= 2)
        {
          unsigned int i;
@@ -2822,12 +2910,15 @@ ppc64_elf_mkobject (bfd *abfd)
 }
 
 /* Fix bad default arch selected for a 64 bit input bfd when the
 }
 
 /* Fix bad default arch selected for a 64 bit input bfd when the
-   default is 32 bit.  */
+   default is 32 bit.  Also select arch based on apuinfo.  */
 
 static bfd_boolean
 ppc64_elf_object_p (bfd *abfd)
 {
 
 static bfd_boolean
 ppc64_elf_object_p (bfd *abfd)
 {
-  if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32)
+  if (!abfd->arch_info->the_default)
+    return TRUE;
+
+  if (abfd->arch_info->bits_per_word == 32)
     {
       Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
 
     {
       Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
 
@@ -2838,7 +2929,7 @@ ppc64_elf_object_p (bfd *abfd)
          BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
        }
     }
          BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
        }
     }
-  return TRUE;
+  return _bfd_elf_ppc_set_arch (abfd);
 }
 
 /* Support for core dump NOTE sections.  */
 }
 
 /* Support for core dump NOTE sections.  */
@@ -3016,6 +3107,7 @@ get_opd_info (asection * sec)
 \f
 /* Parameters for the qsort hook.  */
 static bfd_boolean synthetic_relocatable;
 \f
 /* Parameters for the qsort hook.  */
 static bfd_boolean synthetic_relocatable;
+static asection *synthetic_opd;
 
 /* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
 
 
 /* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
 
@@ -3032,12 +3124,15 @@ compare_symbols (const void *ap, const void *bp)
     return 1;
 
   /* then .opd symbols.  */
     return 1;
 
   /* then .opd symbols.  */
-  if (strcmp (a->section->name, ".opd") == 0
-      && strcmp (b->section->name, ".opd") != 0)
-    return -1;
-  if (strcmp (a->section->name, ".opd") != 0
-      && strcmp (b->section->name, ".opd") == 0)
-    return 1;
+  if (synthetic_opd != NULL)
+    {
+      if (strcmp (a->section->name, ".opd") == 0
+         && strcmp (b->section->name, ".opd") != 0)
+       return -1;
+      if (strcmp (a->section->name, ".opd") != 0
+         && strcmp (b->section->name, ".opd") == 0)
+       return 1;
+    }
 
   /* then other code symbols.  */
   if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
 
   /* then other code symbols.  */
   if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
@@ -3093,17 +3188,17 @@ compare_symbols (const void *ap, const void *bp)
   if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
     return 1;
 
   if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
     return 1;
 
-  return 0;
+  return a > b;
 }
 
 /* Search SYMS for a symbol of the given VALUE.  */
 
 static asymbol *
 }
 
 /* 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;
 
 {
   long mid;
 
-  if (id == -1)
+  if (id == (unsigned) -1)
     {
       while (lo < hi)
        {
     {
       while (lo < hi)
        {
@@ -3146,7 +3241,8 @@ section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
 }
 
 /* Create synthetic symbols, effectively restoring "dot-symbol" function
 }
 
 /* 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,
 
 static long
 ppc64_elf_get_synthetic_symtab (bfd *abfd,
@@ -3195,6 +3291,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
     memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
   synthetic_relocatable = relocatable;
     memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
   synthetic_relocatable = relocatable;
+  synthetic_opd = opd;
   qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
   if (!relocatable && symcount > 1)
   qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
   if (!relocatable && symcount > 1)
@@ -3211,7 +3308,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
     }
 
   i = 0;
     }
 
   i = 0;
-  if (strcmp (syms[i]->section->name, ".opd") == 0)
+  /* Note that here and in compare_symbols we can't compare opd and
+     sym->section directly.  With separate debug info files, the
+     symbols will be extracted from the debug file while abfd passed
+     to this function is the real binary.  */
+  if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
     ++i;
   codesecsym = i;
 
     ++i;
   codesecsym = i;
 
@@ -3227,9 +3328,10 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       break;
   secsymend = i;
 
       break;
   secsymend = i;
 
-  for (; i < symcount; ++i)
-    if (strcmp (syms[i]->section->name, ".opd") != 0)
-      break;
+  if (opd != NULL)
+    for (; i < symcount; ++i)
+      if (strcmp (syms[i]->section->name, ".opd") != 0)
+       break;
   opdsymend = i;
 
   for (; i < symcount; ++i)
   opdsymend = i;
 
   for (; i < symcount; ++i)
@@ -3289,6 +3391,8 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            }
        }
 
            }
        }
 
+      if (size == 0)
+       goto done;
       s = *ret = bfd_malloc (size);
       if (s == NULL)
        {
       s = *ret = bfd_malloc (size);
       if (s == NULL)
        {
@@ -3349,10 +3453,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
       if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents))
        {
 
       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);
        free_contents_and_exit:
          if (contents)
            free (contents);
-         count = -1;
          goto done;
        }
 
          goto done;
        }
 
@@ -3383,7 +3488,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))
          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;
 
          extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
          swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
@@ -3445,7 +3550,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))
            {
              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);
 
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
              size += plt_count * sizeof (asymbol);
@@ -3460,9 +3565,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
            }
        }
 
            }
        }
 
+      if (size == 0)
+       goto free_contents_and_exit;
       s = *ret = bfd_malloc (size);
       if (s == NULL)
       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));
 
 
       names = (char *) (s + count + plt_count + (resolv_vma != 0));
 
@@ -3708,7 +3815,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
     case R_PPC64_TPREL64:
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
     case R_PPC64_TPREL64:
-      return !info->executable;
+      return !bfd_link_executable (info);
     }
 }
 
     }
 }
 
@@ -3788,7 +3895,22 @@ enum ppc_stub_type {
   ppc_stub_plt_branch_r2off,
   ppc_stub_plt_call,
   ppc_stub_plt_call_r2save,
   ppc_stub_plt_branch_r2off,
   ppc_stub_plt_call,
   ppc_stub_plt_call_r2save,
-  ppc_stub_global_entry
+  ppc_stub_global_entry,
+  ppc_stub_save_res
+};
+
+/* Information on stub grouping.  */
+struct map_stub
+{
+  /* The stub section.  */
+  asection *stub_sec;
+  /* This is the section to which stubs in the group will be attached.  */
+  asection *link_sec;
+  /* Next group.  */
+  struct map_stub *next;
+  /* Whether to emit a copy of register save/restore functions in this
+     group.  */
+  int needs_save_res;
 };
 
 struct ppc_stub_hash_entry {
 };
 
 struct ppc_stub_hash_entry {
@@ -3798,8 +3920,8 @@ struct ppc_stub_hash_entry {
 
   enum ppc_stub_type stub_type;
 
 
   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;
 
   /* Offset within stub_sec of the beginning of this stub.  */
   bfd_vma stub_offset;
@@ -3813,10 +3935,6 @@ struct ppc_stub_hash_entry {
   struct ppc_link_hash_entry *h;
   struct plt_entry *plt_ent;
 
   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;
 };
   /* Symbol st_other.  */
   unsigned char other;
 };
@@ -3864,6 +3982,9 @@ struct ppc_link_hash_entry
   /* Track dynamic relocs copied for this symbol.  */
   struct elf_dyn_relocs *dyn_relocs;
 
   /* Track dynamic relocs copied for this symbol.  */
   struct elf_dyn_relocs *dyn_relocs;
 
+  /* Chain of aliases referring to a weakdef.  */
+  struct ppc_link_hash_entry *weakref;
+
   /* Link between function code and descriptor symbols.  */
   struct ppc_link_hash_entry *oh;
 
   /* Link between function code and descriptor symbols.  */
   struct ppc_link_hash_entry *oh;
 
@@ -3877,8 +3998,9 @@ struct ppc_link_hash_entry
      should be set for all globals defined in any opd/toc section.  */
   unsigned int adjust_done:1;
 
      should be set for all globals defined in any opd/toc section.  */
   unsigned int adjust_done:1;
 
-  /* 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
 
   /* Contexts in which symbol is used in the GOT (or TOC).
      TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
@@ -3917,37 +4039,38 @@ struct ppc_link_hash_table
   /* Various options and other info passed from the linker.  */
   struct ppc64_elf_params *params;
 
   /* Various options and other info passed from the linker.  */
   struct ppc64_elf_params *params;
 
-  /* Array to keep track of which stub sections have been created, and
-     information on stub grouping.  */
-  struct map_stub {
-    /* This is the section to which stubs in the group will be attached.  */
-    asection *link_sec;
-    /* The stub section.  */
-    asection *stub_sec;
-    /* Along with elf_gp, specifies the TOC pointer used in this group.  */
+  /* The size of sec_info below.  */
+  unsigned int sec_info_arr_size;
+
+  /* Per-section array of extra section info.  Done this way rather
+     than as part of ppc64_elf_section_data so we have the info for
+     non-ppc64 sections.  */
+  struct
+  {
+    /* Along with elf_gp, specifies the TOC pointer used by this section.  */
     bfd_vma toc_off;
     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;
 
 
   /* 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;
 
   /* 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.  */
   /* Shortcuts to get to dynamic linker sections.  */
-  asection *dynbss;
-  asection *relbss;
   asection *glink;
   asection *sfpr;
   asection *brlt;
   asection *glink;
   asection *sfpr;
   asection *brlt;
@@ -3979,8 +4102,13 @@ struct ppc_link_hash_table
   /* Set on error.  */
   unsigned int stub_error:1;
 
   /* Set on error.  */
   unsigned int stub_error:1;
 
-  /* Temp used by ppc64_elf_before_check_relocs.  */
-  unsigned int twiddled_syms:1;
+  /* Whether func_desc_adjust needs to be run over symbols.  */
+  unsigned int need_func_desc_adj:1;
+
+  /* Whether there exist local gnu indirect function resolvers,
+     referenced by dynamic relocations.  */
+  unsigned int local_ifunc_resolver:1;
+  unsigned int maybe_local_ifunc_resolver:1;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
@@ -4048,13 +4176,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;
       /* 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->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;
     }
 
       eh->other = 0;
     }
 
@@ -4156,7 +4283,7 @@ static hashval_t
 tocsave_htab_hash (const void *p)
 {
   const struct tocsave_entry *e = (const struct tocsave_entry *) p;
 tocsave_htab_hash (const void *p)
 {
   const struct tocsave_entry *e = (const struct tocsave_entry *) p;
-  return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
+  return ((bfd_vma) (intptr_t) e->sec ^ e->offset) >> 3;
 }
 
 static int
 }
 
 static int
@@ -4256,14 +4383,20 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
 
   htab = ppc_hash_table (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);
   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",
 
   /* Create .glink for lazy dynamic linking support.  */
   htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
@@ -4307,7 +4440,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
       || ! 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
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
@@ -4336,14 +4469,9 @@ ppc64_elf_init_stub_bfd (struct bfd_link_info *info,
    linker created stub bfd.  This ensures that the GOT header is at
    the start of the output TOC section.  */
   htab = ppc_hash_table (info);
    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->elf.dynobj = params->stub_bfd;
   htab->params = params;
 
   htab->elf.dynobj = params->stub_bfd;
   htab->params = params;
 
-  if (info->relocatable)
-    return TRUE;
-
   return create_linkage_sections (htab->elf.dynobj, info);
 }
 
   return create_linkage_sections (htab->elf.dynobj, info);
 }
 
@@ -4404,18 +4532,20 @@ ppc_get_stub_entry (const asection *input_section,
                    struct ppc_link_hash_table *htab)
 {
   struct ppc_stub_hash_entry *stub_entry;
                    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.  */
 
   /* 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 (group == NULL)
+    return NULL;
 
   if (h != NULL && h->u.stub_cache != NULL
       && h->u.stub_cache->h == h
 
   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;
     }
     {
       stub_entry = h->u.stub_cache;
     }
@@ -4423,7 +4553,7 @@ ppc_get_stub_entry (const asection *input_section,
     {
       char *stub_name;
 
     {
       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;
 
       if (stub_name == NULL)
        return NULL;
 
@@ -4447,35 +4577,32 @@ ppc_add_stub (const char *stub_name,
              struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
              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;
 
   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)
     {
   if (stub_sec == NULL)
     {
-      stub_sec = htab->stub_group[link_sec->id].stub_sec;
-      if (stub_sec == NULL)
-       {
-         size_t namelen;
-         bfd_size_type len;
-         char *s_name;
+      size_t namelen;
+      bfd_size_type len;
+      char *s_name;
 
 
-         namelen = strlen (link_sec->name);
-         len = namelen + sizeof (STUB_SUFFIX);
-         s_name = bfd_alloc (htab->params->stub_bfd, len);
-         if (s_name == NULL)
-           return NULL;
+      namelen = strlen (link_sec->name);
+      len = namelen + sizeof (STUB_SUFFIX);
+      s_name = bfd_alloc (htab->params->stub_bfd, len);
+      if (s_name == NULL)
+       return NULL;
 
 
-         memcpy (s_name, link_sec->name, namelen);
-         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
-         stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
-         if (stub_sec == NULL)
-           return NULL;
-         htab->stub_group[link_sec->id].stub_sec = stub_sec;
-       }
-      htab->stub_group[section->id].stub_sec = stub_sec;
+      memcpy (s_name, link_sec->name, namelen);
+      memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+      stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
+      if (stub_sec == NULL)
+       return NULL;
+      group->stub_sec = stub_sec;
     }
 
   /* Enter this entry into the linker stub hash table.  */
     }
 
   /* Enter this entry into the linker stub hash table.  */
@@ -4483,14 +4610,14 @@ ppc_add_stub (const char *stub_name,
                                     TRUE, FALSE);
   if (stub_entry == NULL)
     {
                                     TRUE, FALSE);
   if (stub_entry == NULL)
     {
+      /* xgettext:c-format */
       info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
                              section->owner, stub_name);
       return NULL;
     }
 
       info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
                              section->owner, stub_name);
       return NULL;
     }
 
-  stub_entry->stub_sec = stub_sec;
+  stub_entry->group = group;
   stub_entry->stub_offset = 0;
   stub_entry->stub_offset = 0;
-  stub_entry->id_sec = link_sec;
   return stub_entry;
 }
 
   return stub_entry;
 }
 
@@ -4532,31 +4659,6 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Create the dynamic sections, and set up shortcuts.  */
-
-static bfd_boolean
-ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
-{
-  struct ppc_link_hash_table *htab;
-
-  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
-    return FALSE;
-
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
-  htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
-  if (!info->shared)
-    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))
-    abort ();
-
-  return TRUE;
-}
-
 /* Follow indirect and warning symbol links.  */
 
 static inline struct bfd_link_hash_entry *
 /* Follow indirect and warning symbol links.  */
 
 static inline struct bfd_link_hash_entry *
@@ -4641,12 +4743,52 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
        && edir->elf.dynamic_adjusted))
     edir->elf.non_got_ref |= eind->elf.non_got_ref;
 
        && edir->elf.dynamic_adjusted))
     edir->elf.non_got_ref |= eind->elf.non_got_ref;
 
-  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
+  if (edir->elf.versioned != versioned_hidden)
+    edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
   edir->elf.ref_regular |= eind->elf.ref_regular;
   edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
   edir->elf.needs_plt |= eind->elf.needs_plt;
   edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
 
   edir->elf.ref_regular |= eind->elf.ref_regular;
   edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
   edir->elf.needs_plt |= eind->elf.needs_plt;
   edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
 
+  /* If we were called to copy over info for a weak sym, don't copy
+     dyn_relocs, plt/got info, or dynindx.  We used to copy dyn_relocs
+     in order to simplify readonly_dynrelocs and save a field in the
+     symbol hash entry, but that means dyn_relocs can't be used in any
+     tests about a specific symbol, or affect other symbol flags which
+     are then tested.
+     Chain weakdefs so we can get from the weakdef back to an alias.
+     The list is circular so that we don't need to use u.weakdef as
+     well as this list to look at all aliases.  */
+  if (eind->elf.root.type != bfd_link_hash_indirect)
+    {
+      struct ppc_link_hash_entry *cur, *add, *next;
+
+      add = eind;
+      do
+       {
+         cur = edir->weakref;
+         if (cur != NULL)
+           {
+             do
+               {
+                 /* We can be called twice for the same symbols.
+                    Don't make multiple loops.  */
+                 if (cur == add)
+                   return;
+                 cur = cur->weakref;
+               } while (cur != edir);
+           }
+         next = add->weakref;
+         if (cur != add)
+           {
+             add->weakref = edir->weakref != NULL ? edir->weakref : edir;
+             edir->weakref = add;
+           }
+         add = next;
+       } while (add != NULL && add != eind);
+      return;
+    }
+
   /* Copy over any dynamic relocs we may have on the indirect sym.  */
   if (eind->dyn_relocs != NULL)
     {
   /* Copy over any dynamic relocs we may have on the indirect sym.  */
   if (eind->dyn_relocs != NULL)
     {
@@ -4679,16 +4821,6 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
       eind->dyn_relocs = NULL;
     }
 
       eind->dyn_relocs = NULL;
     }
 
-  /* If we were called to copy over info for a weak sym, that's all.
-     You might think dyn_relocs need not be copied over;  After all,
-     both syms will be dynamic or both non-dynamic so we're just
-     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS
-     code in ppc64_elf_adjust_dynamic_symbol needs to check for
-     dyn_relocs in read-only sections, and it does so on what is the
-     DIR sym here.  */
-  if (eind->elf.root.type != bfd_link_hash_indirect)
-    return;
-
   /* Copy over got entries that we may have already seen to the
      symbol which just became indirect.  */
   if (eind->elf.got.glist != NULL)
   /* Copy over got entries that we may have already seen to the
      symbol which just became indirect.  */
   if (eind->elf.got.glist != NULL)
@@ -4759,32 +4891,29 @@ lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
       fh->oh = fdh;
     }
 
       fh->oh = fdh;
     }
 
-  return ppc_follow_link (fdh);
+  fdh = ppc_follow_link (fdh);
+  fdh->is_func_descriptor = 1;
+  fdh->oh = fh;
+  return fdh;
 }
 
 }
 
-/* Make a fake function descriptor sym for the code sym FH.  */
+/* Make a fake function descriptor sym for the undefined code sym FH.  */
 
 static struct ppc_link_hash_entry *
 make_fdh (struct bfd_link_info *info,
          struct ppc_link_hash_entry *fh)
 {
 
 static struct ppc_link_hash_entry *
 make_fdh (struct bfd_link_info *info,
          struct ppc_link_hash_entry *fh)
 {
-  bfd *abfd;
-  asymbol *newsym;
-  struct bfd_link_hash_entry *bh;
+  bfd *abfd = fh->elf.root.u.undef.abfd;
+  struct bfd_link_hash_entry *bh = NULL;
   struct ppc_link_hash_entry *fdh;
   struct ppc_link_hash_entry *fdh;
-
-  abfd = fh->elf.root.u.undef.abfd;
-  newsym = bfd_make_empty_symbol (abfd);
-  newsym->name = fh->elf.root.root.string + 1;
-  newsym->section = bfd_und_section_ptr;
-  newsym->value = 0;
-  newsym->flags = BSF_WEAK;
-
-  bh = NULL;
-  if (!_bfd_generic_link_add_one_symbol (info, abfd, newsym->name,
-                                        newsym->flags, newsym->section,
-                                        newsym->value, NULL, FALSE, FALSE,
-                                        &bh))
+  flagword flags = (fh->elf.root.type == bfd_link_hash_undefweak
+                   ? BSF_WEAK
+                   : BSF_GLOBAL);
+
+  if (!_bfd_generic_link_add_one_symbol (info, abfd,
+                                        fh->elf.root.root.string + 1,
+                                        flags, bfd_und_section_ptr, 0,
+                                        NULL, FALSE, FALSE, &bh))
     return NULL;
 
   fdh = (struct ppc_link_hash_entry *) bh;
     return NULL;
 
   fdh = (struct ppc_link_hash_entry *) bh;
@@ -4809,11 +4938,10 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
                           asection **sec,
                           bfd_vma *value)
 {
                           asection **sec,
                           bfd_vma *value)
 {
-  if ((ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
-       || ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
+  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
       && (ibfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
       && (ibfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
 
   if (*sec != NULL
       && strcmp ((*sec)->name, ".opd") == 0)
 
   if (*sec != NULL
       && strcmp ((*sec)->name, ".opd") == 0)
@@ -4826,7 +4954,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
 
       /* If the symbol is a function defined in .opd, and the function
         code is in a discarded group, let it appear to be undefined.  */
 
       /* If the symbol is a function defined in .opd, and the function
         code is in a discarded group, let it appear to be undefined.  */
-      if (!info->relocatable
+      if (!bfd_link_relocatable (info)
          && (*sec)->reloc_count != 0
          && opd_entry_value (*sec, *value, &code_sec, NULL,
                              FALSE) != (bfd_vma) -1
          && (*sec)->reloc_count != 0
          && opd_entry_value (*sec, *value, &code_sec, NULL,
                              FALSE) != (bfd_vma) -1
@@ -4874,6 +5002,22 @@ ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
                | ELF_ST_VISIBILITY (h->other));
 }
 
                | ELF_ST_VISIBILITY (h->other));
 }
 
+/* Hook called on merging a symbol.  We use this to clear "fake" since
+   we now have a real symbol.  */
+
+static bfd_boolean
+ppc64_elf_merge_symbol (struct elf_link_hash_entry *h,
+                       const Elf_Internal_Sym *isym ATTRIBUTE_UNUSED,
+                       asection **psec ATTRIBUTE_UNUSED,
+                       bfd_boolean newdef ATTRIBUTE_UNUSED,
+                       bfd_boolean olddef ATTRIBUTE_UNUSED,
+                       bfd *oldbfd ATTRIBUTE_UNUSED,
+                       const asection *oldsec ATTRIBUTE_UNUSED)
+{
+  ((struct ppc_link_hash_entry *) h)->fake = 0;
+  return TRUE;
+}
+
 /* This function makes an old ABI object reference to ".bar" cause the
    inclusion of a new ABI object archive that defines "bar".
    NAME is a symbol defined in an archive.  Return a symbol in the hash
 /* This function makes an old ABI object reference to ".bar" cause the
    inclusion of a new ABI object archive that defines "bar".
    NAME is a symbol defined in an archive.  Return a symbol in the hash
@@ -4892,8 +5036,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
   if (h != NULL
       /* Don't return this sym if it is a fake function descriptor
         created by add_symbol_adjust.  */
   if (h != NULL
       /* Don't return this sym if it is a fake function descriptor
         created by add_symbol_adjust.  */
-      && !(h->root.type == bfd_link_hash_undefweak
-          && ((struct ppc_link_hash_entry *) h)->fake))
+      && !((struct ppc_link_hash_entry *) h)->fake)
     return h;
 
   if (name[0] == '.')
     return h;
 
   if (name[0] == '.')
@@ -4925,12 +5068,12 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry *fdh;
 
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry *fdh;
 
-  if (eh->elf.root.type == bfd_link_hash_indirect)
-    return TRUE;
-
   if (eh->elf.root.type == bfd_link_hash_warning)
     eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
 
   if (eh->elf.root.type == bfd_link_hash_warning)
     eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
 
+  if (eh->elf.root.type == bfd_link_hash_indirect)
+    return TRUE;
+
   if (eh->elf.root.root.string[0] != '.')
     abort ();
 
   if (eh->elf.root.root.string[0] != '.')
     abort ();
 
@@ -4939,38 +5082,49 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
     return FALSE;
 
   fdh = lookup_fdh (eh, htab);
     return FALSE;
 
   fdh = lookup_fdh (eh, htab);
-  if (fdh == NULL)
-    {
-      if (!info->relocatable
-         && (eh->elf.root.type == bfd_link_hash_undefined
-             || eh->elf.root.type == bfd_link_hash_undefweak)
-         && eh->elf.ref_regular)
-       {
-         /* Make an undefweak function descriptor sym, which is enough to
-            pull in an --as-needed shared lib, but won't cause link
-            errors.  Archives are handled elsewhere.  */
-         fdh = make_fdh (info, eh);
-         if (fdh == NULL)
-           return FALSE;
-         fdh->elf.ref_regular = 1;
-       }
+  if (fdh == NULL
+      && !bfd_link_relocatable (info)
+      && (eh->elf.root.type == bfd_link_hash_undefined
+         || eh->elf.root.type == bfd_link_hash_undefweak)
+      && eh->elf.ref_regular)
+    {
+      /* Make an undefined function descriptor sym, in order to
+        pull in an --as-needed shared lib.  Archives are handled
+        elsewhere.  */
+      fdh = make_fdh (info, eh);
+      if (fdh == NULL)
+       return FALSE;
     }
     }
-  else
+
+  if (fdh != NULL)
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
+
+      /* Make both descriptor and entry symbol have the most
+        constraining visibility of either symbol.  */
       if (entry_vis < descr_vis)
        fdh->elf.other += entry_vis - descr_vis;
       else if (entry_vis > descr_vis)
        eh->elf.other += descr_vis - entry_vis;
 
       if (entry_vis < descr_vis)
        fdh->elf.other += entry_vis - descr_vis;
       else if (entry_vis > descr_vis)
        eh->elf.other += descr_vis - entry_vis;
 
-      if ((fdh->elf.root.type == bfd_link_hash_defined
-          || fdh->elf.root.type == bfd_link_hash_defweak)
-         && eh->elf.root.type == bfd_link_hash_undefined)
-       {
-         eh->elf.root.type = bfd_link_hash_undefweak;
-         eh->was_undefined = 1;
-         htab->twiddled_syms = 1;
+      /* Propagate reference flags from entry symbol to function
+        descriptor symbol.  */
+      fdh->elf.root.non_ir_ref |= eh->elf.root.non_ir_ref;
+      fdh->elf.ref_regular |= eh->elf.ref_regular;
+      fdh->elf.ref_regular_nonweak |= eh->elf.ref_regular_nonweak;
+
+      if (!fdh->elf.forced_local
+         && fdh->elf.dynindx == -1
+         && fdh->elf.versioned != versioned_hidden
+         && (bfd_link_dll (info)
+             || fdh->elf.def_dynamic
+             || fdh->elf.ref_dynamic)
+         && (eh->elf.ref_regular
+             || eh->elf.def_regular))
+       {
+         if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
+           return FALSE;
        }
     }
 
        }
     }
 
@@ -4991,8 +5145,9 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
     {
       if (abiversion (ibfd) == 0)
        set_abiversion (ibfd, 1);
     {
       if (abiversion (ibfd) == 0)
        set_abiversion (ibfd, 1);
-      else if (abiversion (ibfd) == 2)
+      else if (abiversion (ibfd) >= 2)
        {
        {
+         /* xgettext:c-format */
          info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
                                    " version %d\n"),
                                  ibfd, abiversion (ibfd));
          info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
                                    " version %d\n"),
                                  ibfd, abiversion (ibfd));
@@ -5051,26 +5206,14 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
       else if (htab->elf.hgot == NULL
               && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
        htab->elf.hgot = &eh->elf;
       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.  */
-  p = &htab->dot_syms;
-  while ((eh = *p) != NULL)
-    {
-      *p = NULL;
+      else if (abiversion (ibfd) <= 1)
+       {
+         htab->need_func_desc_adj = 1;
+         if (!add_symbol_adjust (eh, info))
+           return FALSE;
+       }
       p = &eh->u.next_dot_sym;
     }
       p = &eh->u.next_dot_sym;
     }
-
-  /* We need to fix the undefs list for any syms we have twiddled to
-     undef_weak.  */
-  if (htab->twiddled_syms)
-    {
-      bfd_link_repair_undef_list (&htab->elf.root);
-      htab->twiddled_syms = 0;
-    }
   return TRUE;
 }
 
   return TRUE;
 }
 
@@ -5218,7 +5361,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   asection **opd_sym_map;
   struct elf_link_hash_entry *tga, *dottga;
 
   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.
     return TRUE;
 
   /* Don't do anything special with non-loaded, non-alloced sections.
@@ -5256,19 +5399,24 @@ 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;
       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)
        h = NULL;
       else
        {
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
        {
+         struct ppc_link_hash_entry *eh;
+
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
+         eh = (struct ppc_link_hash_entry *) h;
 
          /* PR15323, ref flags aren't set for references in the same
             object.  */
          h->root.non_ir_ref = 1;
 
          /* PR15323, ref flags aren't set for references in the same
             object.  */
          h->root.non_ir_ref = 1;
+         if (eh->is_func && eh->oh != NULL)
+           eh->oh->elf.root.non_ir_ref = 1;
 
          if (h == htab->elf.hgot)
            sec->has_toc_reloc = 1;
 
          if (h == htab->elf.hgot)
            sec->has_toc_reloc = 1;
@@ -5299,28 +5447,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                return FALSE;
            }
        }
                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:
       switch (r_type)
        {
        case R_PPC64_TLSGD:
@@ -5347,7 +5475,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:
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -5359,7 +5487,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
-         /* Fall thru */
+         /* Fall through */
 
        case R_PPC64_GOT16:
        case R_PPC64_GOT16_DS:
 
        case R_PPC64_GOT16:
        case R_PPC64_GOT16_DS:
@@ -5420,7 +5548,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.  */
 
          /* We may also need a plt entry if the symbol turns out to be
             an ifunc.  */
-         if (h != NULL && !info->shared && abiversion (abfd) != 1)
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
            {
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                return FALSE;
            {
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                return FALSE;
@@ -5432,27 +5560,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_PLT16_LO:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
        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;
              h->needs_plt = 1;
              if (h->root.root.string[0] == '.'
                  && h->root.root.string[1] != '\0')
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             plt_list = &h->plt.plist;
+           }
+         if (plt_list == NULL)
+           {
+             /* It does not make sense to have a procedure linkage
+                table entry for a non-ifunc local symbol.  */
+             info->callbacks->einfo
+               /* xgettext:c-format */
+               (_("%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
          break;
 
          /* The following relocations don't need to propagate the
@@ -5483,15 +5614,17 @@ 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_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:
          break;
 
          /* Not supported as a dynamic relocation.  */
        case R_PPC64_ADDR64_LOCAL:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                ppc_howto_init ();
            {
              if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                ppc_howto_init ();
-             info->callbacks->einfo (_("%P: %H: %s reloc unsupported "
+             /* xgettext:c-format */
+             info->callbacks->einfo (_("%H: %s reloc unsupported "
                                        "in shared libraries and PIEs.\n"),
                                      abfd, sec, rel->r_offset,
                                      ppc64_elf_howto_table[r_type]->name);
                                        "in shared libraries and PIEs.\n"),
                                      abfd, sec, rel->r_offset,
                                      ppc64_elf_howto_table[r_type]->name);
@@ -5504,6 +5637,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TOC16_DS:
          htab->do_multi_toc = 1;
          ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
        case R_PPC64_TOC16_DS:
          htab->do_multi_toc = 1;
          ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
+         /* Fall through.  */
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_HI:
        case R_PPC64_TOC16_HA:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_HI:
        case R_PPC64_TOC16_HA:
@@ -5511,6 +5645,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          sec->has_toc_reloc = 1;
          break;
 
          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:
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
        case R_PPC64_GNU_VTINHERIT:
@@ -5560,24 +5698,46 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          /* Fall through.  */
 
        case R_PPC64_REL24:
          /* 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;
              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)
              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;
 
          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;
        case R_PPC64_TPREL64:
          tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dotlstoc;
 
            info->flags |= DF_STATIC_TLS;
          goto dotlstoc;
 
@@ -5653,7 +5813,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              info->flags |= DF_STATIC_TLS;
              goto dodyn;
            {
              info->flags |= DF_STATIC_TLS;
              goto dodyn;
@@ -5666,14 +5826,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
            {
              if (h != NULL)
              && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
            {
              if (h != NULL)
-               {
-                 if (h->root.root.string[0] == '.'
-                     && h->root.root.string[1] != 0
-                     && lookup_fdh ((struct ppc_link_hash_entry *) h, htab))
-                   ;
-                 else
-                   ((struct ppc_link_hash_entry *) h)->is_func = 1;
-               }
+               ((struct ppc_link_hash_entry *) h)->is_func = 1;
              else
                {
                  asection *s;
              else
                {
                  asection *s;
@@ -5703,7 +5856,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:
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_ADDR16_LO:
        case R_PPC64_ADDR16_LO_DS:
-         if (h != NULL && !info->shared && abiversion (abfd) != 1
+         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
              && rel->r_addend == 0)
            {
              /* We may need a .plt entry if this reloc refers to a
              && rel->r_addend == 0)
            {
              /* We may need a .plt entry if this reloc refers to a
@@ -5717,16 +5870,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_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:
        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;
 
            /* We may need a copy reloc.  */
            h->non_got_ref = 1;
 
@@ -5756,18 +5905,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:
             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
               && (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))
                  && 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.
                  && ifunc != NULL))
            {
              /* We must copy these reloc types into the output file.
@@ -5861,8 +6010,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
    object file when linking.  */
 
 static bfd_boolean
    object file when linking.  */
 
 static bfd_boolean
-ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
 {
+  bfd *obfd = info->output_bfd;
   unsigned long iflags, oflags;
 
   if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
   unsigned long iflags, oflags;
 
   if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
@@ -5871,7 +6021,7 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
     return TRUE;
 
   if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
     return TRUE;
 
-  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+  if (!_bfd_generic_verify_endian_match (ibfd, info))
     return FALSE;
 
   iflags = elf_elfheader (ibfd)->e_flags;
     return FALSE;
 
   iflags = elf_elfheader (ibfd)->e_flags;
@@ -5879,22 +6029,26 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   if (iflags & ~EF_PPC64_ABI)
     {
 
   if (iflags & ~EF_PPC64_ABI)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
+       /* xgettext:c-format */
        (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
   else if (iflags != oflags && iflags != 0)
     {
        (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
   else if (iflags != oflags && iflags != 0)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
+       /* xgettext:c-format */
        (_("%B: ABI version %ld is not compatible with ABI version %ld output"),
         ibfd, iflags, oflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
 
        (_("%B: ABI version %ld is not compatible with ABI version %ld output"),
         ibfd, iflags, oflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
 
+  _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  _bfd_elf_merge_object_attributes (ibfd, info);
 
   return TRUE;
 }
 
   return TRUE;
 }
@@ -5909,7 +6063,6 @@ ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr)
     {
       FILE *file = ptr;
 
     {
       FILE *file = ptr;
 
-      /* xgettext:c-format */
       fprintf (file, _("private flags = 0x%lx:"),
               elf_elfheader (abfd)->e_flags);
 
       fprintf (file, _("private flags = 0x%lx:"),
               elf_elfheader (abfd)->e_flags);
 
@@ -6026,14 +6179,13 @@ opd_entry_value (asection *opd_sec,
                  if (rh != NULL)
                    {
                      rh = elf_follow_link (rh);
                  if (rh != NULL)
                    {
                      rh = elf_follow_link (rh);
-                     BFD_ASSERT (rh->root.type == bfd_link_hash_defined
-                                 || rh->root.type == bfd_link_hash_defweak);
-                     val = rh->root.u.def.value;
-                     sec = rh->root.u.def.section;
-                     if (sec->owner != opd_bfd)
+                     if (rh->root.type != bfd_link_hash_defined
+                         && rh->root.type != bfd_link_hash_defweak)
+                       break;
+                     if (rh->root.u.def.section->owner == opd_bfd)
                        {
                        {
-                         sec = NULL;
-                         val = (bfd_vma) -1;
+                         val = rh->root.u.def.value;
+                         sec = rh->root.u.def.section;
                        }
                    }
                }
                        }
                    }
                }
@@ -6112,7 +6264,23 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
 
   if (strcmp (sym->section->name, ".opd") == 0)
     {
 
   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
                           &sec, code_off, TRUE) == (bfd_vma) -1)
        return 0;
       /* An old ABI binary with dot-syms has a size of 24 on the .opd
@@ -6185,15 +6353,32 @@ defined_func_desc (struct ppc_link_hash_entry *fh)
   return NULL;
 }
 
   return NULL;
 }
 
-/* Mark all our entry sym sections, both opd and code section.  */
+static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *);
 
 
-static void
-ppc64_elf_gc_keep (struct bfd_link_info *info)
+/* Garbage collect sections, after first dealing with dot-symbols.  */
+
+static bfd_boolean
+ppc64_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
-  struct bfd_sym_chain *sym;
 
 
-  if (htab == NULL)
+  if (htab != NULL && htab->need_func_desc_adj)
+    {
+      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+      htab->need_func_desc_adj = 0;
+    }
+  return bfd_elf_gc_sections (abfd, info);
+}
+
+/* Mark all our entry sym sections, both opd and code section.  */
+
+static void
+ppc64_elf_gc_keep (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  struct bfd_sym_chain *sym;
+
+  if (htab == NULL)
     return;
 
   for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
     return;
 
   for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
@@ -6249,12 +6434,13 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
          || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
          || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
-             && (!info->executable
+             && (!bfd_link_executable (info)
+                 || info->gc_keep_exported
                  || info->export_dynamic
                  || (eh->elf.dynamic
                      && d != NULL
                      && (*d->match) (&d->head, NULL, eh->elf.root.root.string)))
                  || 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
+             && (eh->elf.versioned >= versioned
                  || !bfd_hide_sym_by_version (info->version_info,
                                               eh->elf.root.root.string)))))
     {
                  || !bfd_hide_sym_by_version (info->version_info,
                                               eh->elf.root.root.string)))))
     {
@@ -6319,7 +6505,15 @@ ppc64_elf_gc_mark_hook (asection *sec,
              eh = (struct ppc_link_hash_entry *) h;
              fdh = defined_func_desc (eh);
              if (fdh != NULL)
              eh = (struct ppc_link_hash_entry *) h;
              fdh = defined_func_desc (eh);
              if (fdh != NULL)
-               eh = fdh;
+               {
+                 /* -mcall-aixdesc code references the dot-symbol on
+                    a call reloc.  Mark the function descriptor too
+                    against garbage collection.  */
+                 fdh->elf.mark = 1;
+                 if (fdh->elf.u.weakdef != NULL)
+                   fdh->elf.u.weakdef->mark = 1;
+                 eh = fdh;
+               }
 
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
 
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
@@ -6379,7 +6573,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;
 
   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)
     return TRUE;
 
   if ((sec->flags & SEC_ALLOC) == 0)
@@ -6401,6 +6595,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;
       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);
       unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -6424,38 +6619,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:
       switch (r_type)
        {
        case R_PPC64_GOT_TLSLD16:
@@ -6522,11 +6685,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:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
+         plt_list = NULL;
          if (h != 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;
 
            {
              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)
                if (ent->addend == rel->r_addend)
                  break;
              if (ent != NULL && ent->plt.refcount > 0)
@@ -6552,10 +6727,14 @@ struct sfpr_def_parms
   bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
 };
 
   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
 
 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;
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   unsigned int i;
@@ -6571,26 +6750,61 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
 
   for (i = parm->lo; i <= parm->hi; i++)
     {
 
   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';
 
       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;
                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)
            }
        }
       if (writing)
@@ -6778,7 +6992,6 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct plt_entry *ent;
   struct ppc_link_hash_entry *fh;
   struct ppc_link_hash_entry *fdh;
   bfd_boolean force_local;
   struct ppc_link_hash_entry *fh;
   struct ppc_link_hash_entry *fdh;
   bfd_boolean force_local;
@@ -6787,18 +7000,29 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
   if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  if (!fh->is_func)
+    return TRUE;
+
+  if (fh->elf.root.root.string[0] != '.'
+      || fh->elf.root.root.string[1] == '\0')
+    return TRUE;
+
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
     return FALSE;
 
+  /* Find the corresponding function descriptor symbol.  */
+  fdh = lookup_fdh (fh, htab);
+
   /* Resolve undefined references to dot-symbols as the value
      in the function descriptor, if we have one in a regular object.
      This is to satisfy cases like ".quad .foo".  Calls to functions
      in dynamic objects are handled elsewhere.  */
   /* Resolve undefined references to dot-symbols as the value
      in the function descriptor, if we have one in a regular object.
      This is to satisfy cases like ".quad .foo".  Calls to functions
      in dynamic objects are handled elsewhere.  */
-  if (fh->elf.root.type == bfd_link_hash_undefweak
-      && fh->was_undefined
-      && (fdh = defined_func_desc (fh)) != NULL
+  if ((fh->elf.root.type == bfd_link_hash_undefined
+       || fh->elf.root.type == bfd_link_hash_undefweak)
+      && (fdh->elf.root.type == bfd_link_hash_defined
+         || fdh->elf.root.type == bfd_link_hash_defweak)
       && get_opd_info (fdh->elf.root.u.def.section) != NULL
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
       && get_opd_info (fdh->elf.root.u.def.section) != NULL
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
@@ -6811,25 +7035,20 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       fh->elf.def_dynamic = fdh->elf.def_dynamic;
     }
 
       fh->elf.def_dynamic = fdh->elf.def_dynamic;
     }
 
-  /* If this is a function code symbol, transfer dynamic linking
-     information to the function descriptor symbol.  */
-  if (!fh->is_func)
-    return TRUE;
-
-  for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
-    if (ent->plt.refcount > 0)
-      break;
-  if (ent == NULL
-      || fh->elf.root.root.string[0] != '.'
-      || fh->elf.root.root.string[1] == '\0')
-    return TRUE;
+  if (!fh->elf.dynamic)
+    {
+      struct plt_entry *ent;
 
 
-  /* Find the corresponding function descriptor symbol.  Create it
-     as undefined if necessary.  */
+      for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
+       if (ent->plt.refcount > 0)
+         break;
+      if (ent == NULL)
+       return TRUE;
+    }
 
 
-  fdh = lookup_fdh (fh, htab);
+  /* Create a descriptor as undefined if necessary.  */
   if (fdh == NULL
   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))
     {
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
@@ -6838,51 +7057,30 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
        return FALSE;
     }
 
        return FALSE;
     }
 
-  /* Fake function descriptors are made undefweak.  If the function
-     code symbol is strong undefined, make the fake sym the same.
-     If the function code symbol is defined, then force the fake
-     descriptor local;  We can't support overriding of symbols in a
-     shared library on a fake descriptor.  */
-
+  /* We can't support overriding of symbols on a fake descriptor.  */
   if (fdh != NULL
       && fdh->fake
   if (fdh != NULL
       && fdh->fake
-      && fdh->elf.root.type == bfd_link_hash_undefweak)
-    {
-      if (fh->elf.root.type == bfd_link_hash_undefined)
-       {
-         fdh->elf.root.type = bfd_link_hash_undefined;
-         bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
-       }
-      else if (fh->elf.root.type == bfd_link_hash_defined
-              || fh->elf.root.type == bfd_link_hash_defweak)
-       {
-         _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
-       }
-    }
+      && (fh->elf.root.type == bfd_link_hash_defined
+         || fh->elf.root.type == bfd_link_hash_defweak))
+    _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
 
 
-  if (fdh != NULL
-      && !fdh->elf.forced_local
-      && (!info->executable
-         || fdh->elf.def_dynamic
-         || fdh->elf.ref_dynamic
-         || (fdh->elf.root.type == bfd_link_hash_undefweak
-             && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
-    {
-      if (fdh->elf.dynindx == -1)
-       if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
-         return FALSE;
+  /* Transfer dynamic linking information to the function descriptor.  */
+  if (fdh != NULL)
+    {
       fdh->elf.ref_regular |= fh->elf.ref_regular;
       fdh->elf.ref_dynamic |= fh->elf.ref_dynamic;
       fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak;
       fdh->elf.non_got_ref |= fh->elf.non_got_ref;
       fdh->elf.ref_regular |= fh->elf.ref_regular;
       fdh->elf.ref_dynamic |= fh->elf.ref_dynamic;
       fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak;
       fdh->elf.non_got_ref |= fh->elf.non_got_ref;
-      if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
-       {
-         move_plt_plist (fh, fdh);
-         fdh->elf.needs_plt = 1;
-       }
-      fdh->is_func_descriptor = 1;
-      fdh->oh = fh;
-      fh->oh = fdh;
+      fdh->elf.dynamic |= fh->elf.dynamic;
+      fdh->elf.needs_plt |= (fh->elf.needs_plt
+                            || fh->elf.type == STT_FUNC
+                            || fh->elf.type == STT_GNU_IFUNC);
+      move_plt_plist (fh, fdh);
+
+      if (!fdh->elf.forced_local
+         && fh->elf.dynindx != -1)
+       if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
+         return FALSE;
     }
 
   /* Now that the info is on the function descriptor, clear the
     }
 
   /* Now that the info is on the function descriptor, clear the
@@ -6901,6 +7099,22 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
   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
 /* 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
@@ -6911,62 +7125,57 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
                            struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
                            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;
 
 
   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.  */
     {
       _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->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);
     }
 
       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 (htab->params->save_restore_funcs)
-    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;
+  if (htab->need_func_desc_adj)
+    {
+      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+      htab->need_func_desc_adj = 0;
+    }
 
   return TRUE;
 }
 
 
   return TRUE;
 }
 
-/* Return true if we have dynamic relocs that apply to read-only sections.  */
+/* Return true if we have dynamic relocs against H that apply to
+   read-only sections.  */
 
 static bfd_boolean
 readonly_dynrelocs (struct elf_link_hash_entry *h)
 
 static bfd_boolean
 readonly_dynrelocs (struct elf_link_hash_entry *h)
@@ -6985,6 +7194,58 @@ readonly_dynrelocs (struct elf_link_hash_entry *h)
   return FALSE;
 }
 
   return FALSE;
 }
 
+/* Return true if we have dynamic relocs against H or any of its weak
+   aliases, that apply to read-only sections.  */
+
+static bfd_boolean
+alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
+{
+  struct ppc_link_hash_entry *eh;
+
+  eh = (struct ppc_link_hash_entry *) h;
+  do
+    {
+      if (readonly_dynrelocs (&eh->elf))
+       return TRUE;
+      eh = eh->weakref;
+    } while (eh != NULL && &eh->elf != h);
+
+  return FALSE;
+}
+
+/* Return whether EH has pc-relative dynamic relocs.  */
+
+static bfd_boolean
+pc_dynrelocs (struct ppc_link_hash_entry *eh)
+{
+  struct elf_dyn_relocs *p;
+
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    if (p->pc_count != 0)
+      return TRUE;
+  return FALSE;
+}
+
+/* Return true if a global entry stub will be created for H.  Valid
+   for ELFv2 before plt entries have been allocated.  */
+
+static bfd_boolean
+global_entry_stub (struct elf_link_hash_entry *h)
+{
+  struct plt_entry *pent;
+
+  if (!h->pointer_equality_needed
+      || h->def_regular)
+    return FALSE;
+
+  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+    if (pent->plt.refcount > 0
+       && pent->addend == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
@@ -6996,7 +7257,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h)
 {
   struct ppc_link_hash_table *htab;
                                 struct elf_link_hash_entry *h)
 {
   struct ppc_link_hash_table *htab;
-  asection *s;
+  asection *s, *srel;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
@@ -7017,41 +7278,32 @@ 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->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;
        }
        {
          h->plt.plist = NULL;
          h->needs_plt = 0;
          h->pointer_equality_needed = 0;
        }
-      else if (abiversion (info->output_bfd) == 2)
+      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
        {
          /* 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))
+            be used instead.  The reason we prefer a few more dynamic
+            relocs is that calling via a global entry stub costs a
+            few more instructions, and pointer_equality_needed causes
+            extra work in ld.so when resolving these symbols.  */
+         if (global_entry_stub (h)
+             && !alias_readonly_dynrelocs (h))
            {
              h->pointer_equality_needed = 0;
            {
              h->pointer_equality_needed = 0;
+             /* After adjust_dynamic_symbol, non_got_ref set in
+                the non-pic case means that dyn_relocs for this
+                symbol should be discarded.  */
              h->non_got_ref = 0;
            }
 
              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
-            symbol should be discarded.
-            If we get here we know we are making a PLT entry for this
-            symbol, and in an executable we'd normally resolve
-            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.  */
-         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.  */
          return TRUE;
        }
          /* If making a plt entry, then we don't need copy relocs.  */
          return TRUE;
        }
@@ -7077,7 +7329,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.  */
      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
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -7086,29 +7338,20 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     return TRUE;
 
   /* Don't generate a copy reloc for symbols defined in the executable.  */
     return TRUE;
 
   /* Don't generate a copy reloc for symbols defined in the executable.  */
-  if (!h->def_dynamic || !h->ref_regular || h->def_regular)
-    return TRUE;
+  if (!h->def_dynamic || !h->ref_regular || h->def_regular
 
 
-  /* If -z nocopyreloc was given, don't generate them either.  */
-  if (info->nocopyreloc)
-    {
-      h->non_got_ref = 0;
-      return TRUE;
-    }
+      /* If -z nocopyreloc was given, don't generate them either.  */
+      || info->nocopyreloc
 
 
-  /* 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))
-    {
-      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.  */
+      || (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
 
 
-  /* 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)
+      /* 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.  */
+      || h->protected_def)
     {
       h->non_got_ref = 0;
       return TRUE;
     {
       h->non_got_ref = 0;
       return TRUE;
@@ -7144,14 +7387,22 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      to copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
      .rela.bss section we are going to use.  */
      to copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
      .rela.bss section we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+    {
+      s = htab->elf.sdynrelro;
+      srel = htab->elf.sreldynrelro;
+    }
+  else
+    {
+      s = htab->elf.sdynbss;
+      srel = htab->elf.srelbss;
+    }
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
   if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
-      htab->relbss->size += sizeof (Elf64_External_Rela);
+      srel->size += sizeof (Elf64_External_Rela);
       h->needs_copy = 1;
     }
 
       h->needs_copy = 1;
     }
 
-  s = htab->dynbss;
-
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
@@ -7173,7 +7424,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
       if (fh == NULL)
        {
          const char *p, *q;
       if (fh == NULL)
        {
          const char *p, *q;
-         struct ppc_link_hash_table *htab;
+         struct elf_link_hash_table *htab = elf_hash_table (info);
          char save;
 
          /* We aren't supposed to use alloca in BFD because on
          char save;
 
          /* We aren't supposed to use alloca in BFD because on
@@ -7188,12 +7439,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
          p = eh->elf.root.root.string - 1;
          save = *p;
          *(char *) p = '.';
          p = eh->elf.root.root.string - 1;
          save = *p;
          *(char *) p = '.';
-         htab = ppc_hash_table (info);
-         if (htab == NULL)
-           return;
-
          fh = (struct ppc_link_hash_entry *)
          fh = (struct ppc_link_hash_entry *)
-           elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
+           elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE);
          *(char *) p = save;
 
          /* Unfortunately, if it so happens that the string we were
          *(char *) p = save;
 
          /* Unfortunately, if it so happens that the string we were
@@ -7207,7 +7454,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
                --q, --p;
              if (q < eh->elf.root.root.string && *p == '.')
                fh = (struct ppc_link_hash_entry *)
                --q, --p;
              if (q < eh->elf.root.root.string && *p == '.')
                fh = (struct ppc_link_hash_entry *)
-                 elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
+                 elf_link_hash_lookup (htab, p, FALSE, FALSE, FALSE);
            }
          if (fh != NULL)
            {
            }
          if (fh != NULL)
            {
@@ -7384,7 +7631,7 @@ tocsave_find (struct ppc_link_hash_table *htab,
     return NULL;
   if (ent.sec == NULL || ent.sec->output_section == NULL)
     {
     return NULL;
   if (ent.sec == NULL || ent.sec->output_section == NULL)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
       return NULL;
     }
        (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
       return NULL;
     }
@@ -7496,7 +7743,7 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_TPREL16_HIGHERA:
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
     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:
        return TRUE;
 
     case R_PPC64_TPREL64:
@@ -7540,14 +7787,14 @@ dec_dynrel_count (bfd_vma r_info,
        return FALSE;
     }
 
        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
        && (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)))
          && h != NULL
          && (h->root.type == bfd_link_hash_defweak
              || !h->def_regular)))
@@ -7614,6 +7861,7 @@ dec_dynrel_count (bfd_vma r_info,
        }
     }
 
        }
     }
 
+  /* xgettext:c-format */
   info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
                          sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
   info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
                          sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
@@ -7702,7 +7950,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                 something silly in .opd with the assembler.  No .opd
                 optimization for them!  */
            broken_opd:
                 something silly in .opd with the assembler.  No .opd
                 optimization for them!  */
            broken_opd:
-             (*_bfd_error_handler)
+             _bfd_error_handler
                (_("%B: .opd is not a regular array of opd entries"), ibfd);
              broken = TRUE;
              break;
                (_("%B: .opd is not a regular array of opd entries"), ibfd);
              broken = TRUE;
              break;
@@ -7711,7 +7959,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
          if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
              || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
            {
          if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
              || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
            {
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: unexpected reloc type %u in .opd section"),
                 ibfd, r_type);
              broken = TRUE;
                (_("%B: unexpected reloc type %u in .opd section"),
                 ibfd, r_type);
              broken = TRUE;
@@ -7732,7 +7981,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
                                             sym_sec);
 
                sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
                                             sym_sec);
 
-             (*_bfd_error_handler)
+             _bfd_error_handler
+               /* xgettext:c-format */
                (_("%B: undefined sym `%s' in .opd section"),
                 ibfd, sym_name);
              broken = TRUE;
                (_("%B: undefined sym `%s' in .opd section"),
                 ibfd, sym_name);
              broken = TRUE;
@@ -7874,11 +8124,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
              if (h != NULL
                  && h->root.root.string[0] == '.')
                {
              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;
+                 fdh = ((struct ppc_link_hash_entry *) h)->oh;
+                 if (fdh != NULL)
+                   {
+                     fdh = ppc_follow_link (fdh);
+                     if (fdh->elf.root.type != bfd_link_hash_defined
+                         && fdh->elf.root.type != bfd_link_hash_defweak)
+                       fdh = NULL;
+                   }
                }
 
              skip = (sym_sec->owner != ibfd
                }
 
              skip = (sym_sec->owner != ibfd
@@ -7894,7 +8147,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                    }
                  opd->adjust[OPD_NDX (rel->r_offset)] = -1;
 
                    }
                  opd->adjust[OPD_NDX (rel->r_offset)] = -1;
 
-                 if (NO_OPD_RELOCS || info->relocatable)
+                 if (NO_OPD_RELOCS || bfd_link_relocatable (info))
                    rel = next_rel;
                  else
                    while (1)
                    rel = next_rel;
                  else
                    while (1)
@@ -7994,7 +8247,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
 
   /* If we are doing a final link and the last .opd entry is just 16 byte
      long, add a 8 byte padding after it.  */
 
   /* If 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;
 
     {
       bfd_byte *p;
 
@@ -8057,7 +8310,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));
   htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
                           elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                                                 FALSE, FALSE, TRUE));
-  if (!htab->params->no_tls_get_addr_opt)
+  if (htab->params->tls_get_addr_opt)
     {
       struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
 
     {
       struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
 
@@ -8094,6 +8347,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);
                  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->mark = 1;
                  if (opt_fd->dynindx != -1)
                    {
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
                  if (opt_fd->dynindx != -1)
                    {
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
@@ -8110,6 +8364,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);
                      tga->root.type = bfd_link_hash_indirect;
                      tga->root.u.i.link = &opt->root;
                      ppc64_elf_copy_indirect_symbol (info, opt, tga);
+                     opt->mark = 1;
                      _bfd_elf_link_hash_hide_symbol (info, opt,
                                                      tga->forced_local);
                      htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
                      _bfd_elf_link_hash_hide_symbol (info, opt,
                                                      tga->forced_local);
                      htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
@@ -8124,8 +8379,8 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
                }
            }
        }
                }
            }
        }
-      else
-       htab->params->no_tls_get_addr_opt = TRUE;
+      else if (htab->params->tls_get_addr_opt < 0)
+       htab->params->tls_get_addr_opt = 0;
     }
   return _bfd_elf_tls_setup (info->output_bfd, info);
 }
     }
   return _bfd_elf_tls_setup (info->output_bfd, info);
 }
@@ -8172,7 +8427,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
   unsigned char *toc_ref;
   int pass;
 
   unsigned char *toc_ref;
   int pass;
 
-  if (info->relocatable || !info->executable)
+  if (!bfd_link_executable (info))
     return TRUE;
 
   htab = ppc_hash_table (info);
     return TRUE;
 
   htab = ppc_hash_table (info);
@@ -8267,7 +8522,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      if (h != NULL
                          && h->root.type == bfd_link_hash_undefweak)
                        ok_tprel = TRUE;
                      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;
                        {
                          value += sym_sec->output_offset;
                          value += sym_sec->output_section->vma;
@@ -8306,7 +8562,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    case R_PPC64_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                    case R_PPC64_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC64_GOT_TLSLD16_HI:
                    case R_PPC64_GOT_TLSLD16_HA:
 
                    case R_PPC64_GOT_TLSLD16_HI:
                    case R_PPC64_GOT_TLSLD16_HA:
@@ -8326,7 +8582,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    case R_PPC64_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                    case R_PPC64_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
-                     /* Fall thru */
+                     /* Fall through. */
 
                    case R_PPC64_GOT_TLSGD16_HI:
                    case R_PPC64_GOT_TLSGD16_HA:
 
                    case R_PPC64_GOT_TLSGD16_HI:
                    case R_PPC64_GOT_TLSGD16_HA:
@@ -8357,7 +8613,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    case R_PPC64_TLSGD:
                    case R_PPC64_TLSLD:
                      found_tls_get_addr_arg = 1;
                    case R_PPC64_TLSGD:
                    case R_PPC64_TLSLD:
                      found_tls_get_addr_arg = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC64_TLS:
                    case R_PPC64_TOC16:
 
                    case R_PPC64_TLS:
                    case R_PPC64_TOC16:
@@ -8489,6 +8745,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
                         the entire optimization.  */
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
                         the entire optimization.  */
+                     /* xgettext:c-format */
                      info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
                                                "TLS optimization disabled\n"),
                                              ibfd, sec, rel->r_offset);
                      info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
                                                "TLS optimization disabled\n"),
                                              ibfd, sec, rel->r_offset);
@@ -8633,7 +8890,7 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 
       if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0)
        {
 
       if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0)
        {
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%s defined on removed toc entry"), eh->elf.root.root.string);
          do
            ++i;
            (_("%s defined on removed toc entry"), eh->elf.root.root.string);
          do
            ++i;
@@ -8650,12 +8907,14 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc.  */
+/* Return TRUE iff INSN with a relocation of R_TYPE is one we expect
+   on a _LO variety toc/got reloc.  */
 
 static bfd_boolean
 
 static bfd_boolean
-ok_lo_toc_insn (unsigned int insn)
+ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
 {
 {
-  return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+  return ((insn & (0x3f << 26)) == 12u << 26 /* addic */
+         || (insn & (0x3f << 26)) == 14u << 26 /* addi */
          || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
          || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
          || (insn & (0x3f << 26)) == 36u << 26 /* stw */
          || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
          || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
          || (insn & (0x3f << 26)) == 36u << 26 /* stw */
@@ -8669,11 +8928,20 @@ ok_lo_toc_insn (unsigned int insn)
          || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
          || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
          || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
          || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
          || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
          || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
-         || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
-             && (insn & 3) != 1)
-         || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
-             && ((insn & 3) == 0 || (insn & 3) == 3))
-         || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+         || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
+         || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+             /* Exclude lfqu by testing reloc.  If relocs are ever
+                defined for the reduced D field in psq_lu then those
+                will need testing too.  */
+             && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
+         || ((insn & (0x3f << 26)) == 58u << 26 /* ld,lwa */
+             && (insn & 1) == 0)
+         || (insn & (0x3f << 26)) == 60u << 26 /* stfq */
+         || ((insn & (0x3f << 26)) == 61u << 26 /* lxv,stx{v,sd,ssp},stfdp */
+             /* Exclude stfqu.  psq_stu as above for psq_lu.  */
+             && r_type != R_PPC64_TOC16_LO && r_type != R_PPC64_GOT16_LO)
+         || ((insn & (0x3f << 26)) == 62u << 26 /* std,stq */
+             && (insn & 1) == 0));
 }
 
 /* Examine all relocs referencing .toc sections in order to remove
 }
 
 /* Examine all relocs referencing .toc sections in order to remove
@@ -8828,6 +9096,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                goto error_ret;
 
              if (sym_sec == NULL
                goto error_ret;
 
              if (sym_sec == NULL
+                 || sym_sec->output_section == NULL
                  || discarded_section (sym_sec))
                continue;
 
                  || discarded_section (sym_sec))
                continue;
 
@@ -8977,7 +9246,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                        }
                      insn = bfd_get_32 (ibfd, buf);
                      if (insn_check == check_lo
                        }
                      insn = bfd_get_32 (ibfd, buf);
                      if (insn_check == check_lo
-                         ? !ok_lo_toc_insn (insn)
+                         ? !ok_lo_toc_insn (insn, r_type)
                          : ((insn & ((0x3f << 26) | 0x1f << 16))
                             != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
                        {
                          : ((insn & ((0x3f << 26) | 0x1f << 16))
                             != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
                        {
@@ -8986,7 +9255,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                          ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
                          sprintf (str, "%#08x", insn);
                          info->callbacks->einfo
                          ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
                          sprintf (str, "%#08x", insn);
                          info->callbacks->einfo
-                           (_("%P: %H: toc optimization is not supported for"
+                           /* xgettext:c-format */
+                           (_("%H: toc optimization is not supported for"
                               " %s instruction.\n"),
                             ibfd, sec, rel->r_offset & ~3, str);
                        }
                               " %s instruction.\n"),
                             ibfd, sec, rel->r_offset & ~3, str);
                        }
@@ -9049,7 +9319,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                            }
                          if ((opc & (0x3f << 2)) == (58u << 2))
                            break;
                            }
                          if ((opc & (0x3f << 2)) == (58u << 2))
                            break;
-                         /* Fall thru */
+                         /* Fall through.  */
 
                        default:
                          /* Wrong sort of reloc, or not a ld.  We may
 
                        default:
                          /* Wrong sort of reloc, or not a ld.  We may
@@ -9214,7 +9484,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                          if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                            ppc_howto_init ();
                          info->callbacks->einfo
                          if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                            ppc_howto_init ();
                          info->callbacks->einfo
-                           (_("%P: %H: %s references "
+                           /* xgettext:c-format */
+                           (_("%H: %s references "
                               "optimized away TOC entry\n"),
                             ibfd, sec, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name);
                               "optimized away TOC entry\n"),
                             ibfd, sec, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name);
@@ -9256,7 +9527,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
                    {
                      if (local_toc_syms)
                  if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
                    {
                      if (local_toc_syms)
-                       (*_bfd_error_handler)
+                       _bfd_error_handler
                          (_("%s defined on removed toc entry"),
                           bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
                      do
                          (_("%s defined on removed toc entry"),
                           bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
                      do
@@ -9349,7 +9620,6 @@ allocate_got (struct elf_link_hash_entry *h,
              struct got_entry *gent)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
              struct got_entry *gent)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
-  bfd_boolean dyn;
   struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
   int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
                 ? 16 : 8);
   struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
   int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
                 ? 16 : 8);
@@ -9360,14 +9630,15 @@ allocate_got (struct elf_link_hash_entry *h,
   gent->got.offset = got->size;
   got->size += entsize;
 
   gent->got.offset = got->size;
   got->size += entsize;
 
-  dyn = htab->elf.dynamic_sections_created;
   if (h->type == STT_GNU_IFUNC)
     {
       htab->elf.irelplt->size += rentsize;
       htab->got_reli_size += rentsize;
     }
   if (h->type == STT_GNU_IFUNC)
     {
       htab->elf.irelplt->size += rentsize;
       htab->got_reli_size += rentsize;
     }
-  else if ((info->shared
-           || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+  else if ((bfd_link_pic (info)
+           || (htab->elf.dynamic_sections_created
+               && h->dynindx != -1
+               && !SYMBOL_REFERENCES_LOCAL (info, h)))
           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
               || h->root.type != bfd_link_hash_undefweak))
     {
           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
               || h->root.type != bfd_link_hash_undefweak))
     {
@@ -9396,6 +9667,23 @@ merge_got_entries (struct got_entry **pent)
          }
 }
 
          }
 }
 
+/* If H is undefined weak, make it dynamic if that makes sense.  */
+
+static bfd_boolean
+ensure_undefweak_dynamic (struct bfd_link_info *info,
+                         struct elf_link_hash_entry *h)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  if (htab->dynamic_sections_created
+      && h->root.type == bfd_link_hash_undefweak
+      && h->dynindx == -1
+      && !h->forced_local
+      && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+    return bfd_elf_link_record_dynamic_symbol (info, h);
+  return TRUE;
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
@@ -9406,7 +9694,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct ppc_link_hash_table *htab;
   asection *s;
   struct ppc_link_hash_entry *eh;
   struct ppc_link_hash_table *htab;
   asection *s;
   struct ppc_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
   struct got_entry **pgent, *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
   struct got_entry **pgent, *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
@@ -9417,71 +9704,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (htab == NULL)
     return FALSE;
 
   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.  */
   eh = (struct ppc_link_hash_entry *) h;
   /* Run through the TLS GD got entries first if we're changing them
      to TPREL.  */
@@ -9534,16 +9756,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     if (!gent->is_indirect)
       {
        /* Make sure this symbol is output as a dynamic symbol.
     if (!gent->is_indirect)
       {
        /* Make sure this symbol is output as a dynamic symbol.
-          Undefined weak syms won't yet be marked as dynamic,
-          nor will all TLS symbols.  */
-       if (h->dynindx == -1
-           && !h->forced_local
-           && h->type != STT_GNU_IFUNC
-           && htab->elf.dynamic_sections_created)
-         {
-           if (! bfd_elf_link_record_dynamic_symbol (info, h))
-             return FALSE;
-         }
+          Undefined weak syms won't yet be marked as dynamic.  */
+       if (!ensure_undefweak_dynamic (info, h))
+         return FALSE;
 
        if (!is_ppc64_elf (gent->owner))
          abort ();
 
        if (!is_ppc64_elf (gent->owner))
          abort ();
@@ -9551,99 +9766,171 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        allocate_got (h, info, gent);
       }
 
        allocate_got (h, info, gent);
       }
 
-  if (eh->dyn_relocs == NULL
-      || (!htab->elf.dynamic_sections_created
-         && h->type != STT_GNU_IFUNC))
-    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 (!htab->elf.dynamic_sections_created
+      && h->type != STT_GNU_IFUNC)
+    eh->dyn_relocs = NULL;
 
 
-  if (info->shared)
+  if (eh->dyn_relocs != NULL)
     {
     {
-      /* 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 *p, **pp;
+
+      /* 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))
+           {
+             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;
+               }
+           }
 
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+         /* 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 (!ensure_undefweak_dynamic (info, h))
+               return FALSE;
            }
        }
            }
        }
+      else if (h->type == STT_GNU_IFUNC)
+       {
+         /* A plt entry is always created when making direct calls to
+            an ifunc, even when building a static executable, but
+            that doesn't cover all cases.  We may have only an ifunc
+            initialised function pointer for a given ifunc symbol.
+
+            For ELFv2, dynamic relocations are not required when
+            generating a global entry PLT stub.  */
+         if (abiversion (info->output_bfd) >= 2)
+           {
+             if (global_entry_stub (h))
+               eh->dyn_relocs = NULL;
+           }
+
+         /* For ELFv1 we have function descriptors.  Descriptors need
+            to be treated like PLT entries and thus have dynamic
+            relocations.  One exception is when the function
+            descriptor is copied into .dynbss (which should only
+            happen with ancient versions of gcc).  */
+         else if (h->needs_copy)
+           eh->dyn_relocs = NULL;
+       }
+      else if (ELIMINATE_COPY_RELOCS)
+       {
+         /* For the non-pic case, discard space for relocs against
+            symbols which turn out to need copy relocs or are not
+            dynamic.  */
+         if (!h->non_got_ref
+             && !h->def_regular)
+           {
+             /* Make sure this symbol is output as a dynamic symbol.
+                Undefined weak syms won't yet be marked as dynamic.  */
+             if (!ensure_undefweak_dynamic (info, h))
+               return FALSE;
+
+             if (h->dynindx == -1)
+               eh->dyn_relocs = NULL;
+           }
+         else
+           eh->dyn_relocs = NULL;
+       }
+
+      /* 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);
+       }
+    }
+
+  if ((htab->elf.dynamic_sections_created
+       && h->dynindx != -1)
+      || 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);
 
 
-      /* Also discard relocs on undefined weak syms with non-default
-        visibility.  */
-      if (eh->dyn_relocs != NULL
-         && h->root.type == bfd_link_hash_undefweak)
-       {
-         if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-           eh->dyn_relocs = NULL;
+               pent->plt.offset = s->size;
 
 
-         /* 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;
-           }
-       }
-    }
-  else if (h->type == STT_GNU_IFUNC)
-    {
-      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 room for this entry.  */
+               s->size += PLT_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;
-           }
+               /* 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;
 
 
-         /* If that succeeded, we know we'll be keeping all the
-            relocs.  */
-         if (h->dynindx != -1)
-           goto 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;
        }
        }
-
-      eh->dyn_relocs = NULL;
-
-    keep: ;
     }
     }
-
-  /* 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;
     }
 
   return TRUE;
@@ -9685,6 +9972,7 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
           need to define the symbol in the executable on a call stub.
           This is to avoid text relocations.  */
        s->size = (s->size + 15) & -16;
           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.type = bfd_link_hash_defined;
        h->root.u.def.section = s;
        h->root.u.def.value = s->size;
        s->size += 16;
        h->root.u.def.section = s;
        h->root.u.def.value = s->size;
        s->size += 16;
@@ -9736,7 +10024,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 (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)
        {
          s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
@@ -9828,7 +10116,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        htab->elf.irelplt->size += rel_size;
                        htab->got_reli_size += rel_size;
                      }
                        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;
                      {
                        asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                        srel->size += rel_size;
@@ -9866,7 +10154,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->glink != NULL)
     htab->glink->rawsize = htab->glink->size;
 
   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;
     elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info);
 
   first_tlsld = NULL;
@@ -9893,7 +10181,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              ent->got.offset = s->size;
              ent->owner = ibfd;
              s->size += 16;
              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);
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += sizeof (Elf64_External_Rela);
@@ -9919,7 +10207,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
               || s == htab->elf.splt
               || s == htab->elf.iplt
               || s == htab->glink
               || s == htab->elf.splt
               || s == htab->elf.iplt
               || s == htab->glink
-              || s == htab->dynbss)
+              || s == htab->elf.sdynbss
+              || s == htab->elf.sdynrelro)
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
        {
          /* Strip this section if we don't need it; see the
             comment below.  */
@@ -9972,7 +10261,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
         but this way if it does we get a R_PPC64_NONE reloc in .rela
         sections instead of garbage.
         We also rely on the section contents being zero when writing
         but this way if it does we get a R_PPC64_NONE reloc in .rela
         sections instead of garbage.
         We also rely on the section contents being zero when writing
-        the GOT.  */
+        the GOT and .dynrelro.  */
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
        return FALSE;
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
        return FALSE;
@@ -10023,7 +10312,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
 #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;
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
@@ -10046,7 +10335,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            return FALSE;
        }
 
            return FALSE;
        }
 
-      tls_opt = (!htab->params->no_tls_get_addr_opt
+      tls_opt = (htab->params->tls_get_addr_opt
                 && htab->tls_get_addr_fd != NULL
                 && htab->tls_get_addr_fd->elf.plt.plist != NULL);
       if (tls_opt || !htab->opd_abi)
                 && htab->tls_get_addr_fd != NULL
                 && htab->tls_get_addr_fd->elf.plt.plist != NULL);
       if (tls_opt || !htab->opd_abi)
@@ -10231,7 +10520,7 @@ plt_stub_size (struct ppc_link_hash_table *htab,
   if (stub_entry->h != NULL
       && (stub_entry->h == htab->tls_get_addr_fd
          || stub_entry->h == htab->tls_get_addr)
   if (stub_entry->h != NULL
       && (stub_entry->h == htab->tls_get_addr_fd
          || stub_entry->h == htab->tls_get_addr)
-      && !htab->params->no_tls_get_addr_opt)
+      && htab->params->tls_get_addr_opt)
     size += 13 * 4;
   return size;
 }
     size += 13 * 4;
   return size;
 }
@@ -10245,7 +10534,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
 {
   int stub_align = 1 << htab->params->plt_stub_align;
   unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
 {
   int stub_align = 1 << htab->params->plt_stub_align;
   unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
-  bfd_vma stub_off = stub_entry->stub_sec->size;
+  bfd_vma stub_off = stub_entry->group->stub_sec->size;
 
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
 
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
@@ -10275,7 +10564,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       && plt_thread_safe
       && !((stub_entry->h == htab->tls_get_addr_fd
            || stub_entry->h == htab->tls_get_addr)
       && plt_thread_safe
       && !((stub_entry->h == htab->tls_get_addr_fd
            || stub_entry->h == htab->tls_get_addr)
-          && !htab->params->no_tls_get_addr_opt))
+          && htab->params->tls_get_addr_opt))
     {
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
       bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
     {
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
       bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
@@ -10288,7 +10577,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       to = (glinkoff
            + htab->glink->output_offset
            + htab->glink->output_section->vma);
       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)
              + 4 * (ALWAYS_EMIT_R2SAVE
                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
              + 4 * (PPC_HA (offset) != 0)
@@ -10296,8 +10585,8 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                     != PPC_HA (offset))
              + 4 * (plt_static_chain != 0)
              + 20
                     != 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);
     }
       cmp_branch_off = to - from;
       use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
     }
@@ -10510,7 +10799,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);
           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)
     {
 
   if (r2off == 0)
     {
@@ -10528,14 +10817,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);
          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))
        }
       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 = 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;
 }
 
   return r2off;
 }
 
@@ -10562,8 +10851,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.  */
     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)
 
   htab->stub_count[stub_entry->stub_type - 1] += 1;
   switch (stub_entry->stub_type)
@@ -10579,31 +10868,36 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       /* And this is where we are coming from.  */
       off -= (stub_entry->stub_offset
 
       /* 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);
 
 
       size = 4;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
-         if (r2off == 0)
+         if (r2off == (bfd_vma) -1)
            {
              htab->stub_error = TRUE;
              return FALSE;
            }
          bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
          loc += 4;
            {
              htab->stub_error = TRUE;
              return FALSE;
            }
          bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
          loc += 4;
-         size = 12;
+         size = 8;
          if (PPC_HA (r2off) != 0)
            {
          if (PPC_HA (r2off) != 0)
            {
-             size = 16;
              bfd_put_32 (htab->params->stub_bfd,
                          ADDIS_R2_R2 | PPC_HA (r2off), loc);
              loc += 4;
              bfd_put_32 (htab->params->stub_bfd,
                          ADDIS_R2_R2 | PPC_HA (r2off), loc);
              loc += 4;
+             size += 4;
+           }
+         if (PPC_LO (r2off) != 0)
+           {
+             bfd_put_32 (htab->params->stub_bfd,
+                         ADDI_R2_R2 | PPC_LO (r2off), loc);
+             loc += 4;
+             size += 4;
            }
            }
-         bfd_put_32 (htab->params->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
-         loc += 4;
          off -= size - 4;
        }
       bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
          off -= size - 4;
        }
       bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
@@ -10619,10 +10913,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
 
       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;
          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)
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
          r->r_addend = dest;
          if (stub_entry->h != NULL)
@@ -10729,7 +11023,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       off = (dest
             - elf_gp (htab->brlt->output_section->owner)
 
       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)
        {
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
@@ -10743,10 +11037,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
 
       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;
          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)
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
          if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
@@ -10784,7 +11078,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
-         if (r2off == 0 && htab->opd_abi)
+         if (r2off == (bfd_vma) -1)
            {
              htab->stub_error = TRUE;
              return FALSE;
            {
              htab->stub_error = TRUE;
              return FALSE;
@@ -10835,15 +11129,11 @@ 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
          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.  */
-         if (fh->elf.root.type == bfd_link_hash_undefined)
+            we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.  */
+         if (fh->elf.root.type == bfd_link_hash_undefined
+             && (stub_entry->h->elf.root.type == bfd_link_hash_defined
+                 || stub_entry->h->elf.root.type == bfd_link_hash_defweak))
            fh->elf.root.type = bfd_link_hash_undefweak;
            fh->elf.root.type = bfd_link_hash_undefweak;
-         /* Stop undo_symbol_twiddle changing it back to undefined.  */
-         fh->was_undefined = 0;
        }
 
       /* Now build the stub.  */
        }
 
       /* Now build the stub.  */
@@ -10879,15 +11169,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                   * sizeof (Elf64_External_Rela)));
          bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
          stub_entry->plt_ent->plt.offset |= 1;
                   * sizeof (Elf64_External_Rela)));
          bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
          stub_entry->plt_ent->plt.offset |= 1;
+         htab->local_ifunc_resolver = 1;
        }
 
       off = (dest
             - elf_gp (plt->output_section->owner)
        }
 
       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)
        {
          info->callbacks->einfo
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: linkage table error against `%T'\n"),
             stub_entry->h != NULL
             ? stub_entry->h->elf.root.root.string
            (_("%P: linkage table error against `%T'\n"),
             stub_entry->h != NULL
             ? stub_entry->h->elf.root.root.string
@@ -10901,15 +11193,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        {
          unsigned pad = plt_stub_pad (htab, stub_entry, off);
 
        {
          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)
        {
          loc += pad;
        }
 
       r = NULL;
       if (info->emitrelocations)
        {
-         r = get_relocs (stub_entry->stub_sec,
+         r = get_relocs (stub_entry->group->stub_sec,
                          ((PPC_HA (off) != 0)
                           + (htab->opd_abi
                              ? 2 + (htab->params->plt_static_chain
                          ((PPC_HA (off) != 0)
                           + (htab->opd_abi
                              ? 2 + (htab->params->plt_static_chain
@@ -10917,7 +11209,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                              : 1)));
          if (r == NULL)
            return FALSE;
                              : 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;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
          r[0].r_addend = dest;
@@ -10925,19 +11217,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
              || stub_entry->h == htab->tls_get_addr)
       if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
              || stub_entry->h == htab->tls_get_addr)
-         && !htab->params->no_tls_get_addr_opt)
+         && htab->params->tls_get_addr_opt)
        p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
       else
        p = build_plt_stub (htab, stub_entry, loc, off, r);
       size = p - loc;
       break;
 
        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;
     }
 
     default:
       BFD_FAIL ();
       return FALSE;
     }
 
-  stub_entry->stub_sec->size += size;
+  stub_entry->group->stub_sec->size += size;
 
   if (htab->params->emit_stub_syms)
     {
 
   if (htab->params->emit_stub_syms)
     {
@@ -10965,7 +11260,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (h->root.type == bfd_link_hash_new)
        {
          h->root.type = bfd_link_hash_defined;
       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->root.u.def.value = stub_entry->stub_offset;
          h->ref_regular = 1;
          h->def_regular = 1;
@@ -11000,6 +11295,18 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   if (htab == NULL)
     return FALSE;
 
   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)
     {
   if (stub_entry->stub_type == ppc_stub_plt_call
       || stub_entry->stub_type == ppc_stub_plt_call_r2save)
     {
@@ -11015,20 +11322,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)
       off += (plt->output_offset
              + plt->output_section->vma
              - elf_gp (plt->output_section->owner)
-             - htab->stub_group[stub_entry->id_sec->id].toc_off);
+             - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
 
       size = plt_stub_size (htab, stub_entry, off);
       if (htab->params->plt_stub_align)
        size += plt_stub_pad (htab, stub_entry, off);
       if (info->emitrelocations)
        {
 
       size = plt_stub_size (htab, stub_entry, off);
       if (htab->params->plt_stub_align)
        size += plt_stub_pad (htab, stub_entry, off);
       if (info->emitrelocations)
        {
-         stub_entry->stub_sec->reloc_count
+         stub_entry->group->stub_sec->reloc_count
            += ((PPC_HA (off) != 0)
                + (htab->opd_abi
                   ? 2 + (htab->params->plt_static_chain
                          && PPC_HA (off + 16) == PPC_HA (off))
                   : 1));
            += ((PPC_HA (off) != 0)
                + (htab->opd_abi
                   ? 2 + (htab->params->plt_static_chain
                          && PPC_HA (off + 16) == PPC_HA (off))
                   : 1));
-         stub_entry->stub_sec->flags |= SEC_RELOC;
+         stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
     }
   else
        }
     }
   else
@@ -11041,9 +11348,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->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.  */
 
       /* Reset the stub type from the plt variant in case we now
         can reach with a shorter stub.  */
@@ -11054,14 +11361,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 (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;
            }
            {
              htab->stub_error = TRUE;
              return FALSE;
            }
-         size = 12;
+         size = 8;
          if (PPC_HA (r2off) != 0)
          if (PPC_HA (r2off) != 0)
-           size = 16;
+           size += 4;
+         if (PPC_LO (r2off) != 0)
+           size += 4;
          off -= size - 4;
        }
 
          off -= size - 4;
        }
 
@@ -11071,7 +11380,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
         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;
 
        {
          struct ppc_branch_hash_entry *br_entry;
 
@@ -11106,12 +11416,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                 + htab->brlt->output_offset
                 + htab->brlt->output_section->vma
                 - elf_gp (htab->brlt->output_section->owner)
                 + htab->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)
            {
 
          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)
            }
 
          if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
@@ -11134,12 +11445,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
       else if (info->emitrelocations)
        {
        }
       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;
 }
 
   return TRUE;
 }
 
@@ -11150,57 +11461,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 int
 ppc64_elf_setup_section_lists (struct bfd_link_info *info)
 {
 int
 ppc64_elf_setup_section_lists (struct bfd_link_info *info)
 {
-  bfd *input_bfd;
-  int top_id, top_index, id;
-  asection *section;
-  asection **input_list;
+  unsigned int id;
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
     return -1;
 
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
     return -1;
 
-  /* Find the top input section id.  */
-  for (input_bfd = info->input_bfds, top_id = 3;
-       input_bfd != NULL;
-       input_bfd = input_bfd->link.next)
-    {
-      for (section = input_bfd->sections;
-          section != NULL;
-          section = section->next)
-       {
-         if (top_id < section->id)
-           top_id = section->id;
-       }
-    }
-
-  htab->top_id = top_id;
-  amt = sizeof (struct map_stub) * (top_id + 1);
-  htab->stub_group = bfd_zmalloc (amt);
-  if (htab->stub_group == NULL)
+  htab->sec_info_arr_size = bfd_get_next_section_id ();
+  amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size);
+  htab->sec_info = bfd_zmalloc (amt);
+  if (htab->sec_info == NULL)
     return -1;
 
   /* Set toc_off for com, und, abs and ind sections.  */
   for (id = 0; id < 3; id++)
     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;
 }
 
   return 1;
 }
@@ -11251,6 +11527,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;
          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
        }
 
       /* toc_curr is the base address of this toc group.  Set elf_gp
@@ -11443,7 +11720,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  htab->elf.irelplt->size += rel_size;
                  htab->got_reli_size += rel_size;
                }
                  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;
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += rel_size;
@@ -11468,7 +11745,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;
          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);
            {
              asection *srel = ppc64_elf_tdata (ibfd)->relgot;
              srel->size += sizeof (Elf64_External_Rela);
@@ -11631,7 +11908,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
                {
                  long adjust;
 
                {
                  long adjust;
 
-                 adjust = opd->adjust[OPD_NDX (sym->st_value)];
+                 adjust = opd->adjust[OPD_NDX (sym_value)];
                  if (adjust == -1)
                    /* Assume deleted functions won't ever be called.  */
                    continue;
                  if (adjust == -1)
                    /* Assume deleted functions won't ever be called.  */
                    continue;
@@ -11748,15 +12025,13 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
     return FALSE;
 
   if ((isec->output_section->flags & SEC_CODE) != 0
     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.  */
       /* 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)
     }
 
   if (htab->multi_toc_needed)
@@ -11780,7 +12055,7 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
        htab->toc_curr = elf_gp (isec->owner);
     }
 
        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;
 }
 
   return TRUE;
 }
 
@@ -11802,8 +12077,8 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
        if (i->has_toc_reloc)
          {
            if (toc_off == 0)
        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;
          }
 
              return FALSE;
          }
 
@@ -11811,14 +12086,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)
            {
        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)
              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;
 }
     }
   return TRUE;
 }
@@ -11837,37 +12112,38 @@ 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.  */
 
    _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)
 {
                bfd_size_type stub_group_size,
                bfd_boolean stubs_always_before_branch)
 {
-  asection **list;
-  bfd_size_type stub14_group_size;
+  struct ppc_link_hash_table *htab;
+  asection *osec;
   bfd_boolean suppress_size_errors;
 
   bfd_boolean suppress_size_errors;
 
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   suppress_size_errors = FALSE;
   suppress_size_errors = FALSE;
-  stub14_group_size = stub_group_size >> 10;
   if (stub_group_size == 1)
     {
       /* Default values.  */
       if (stubs_always_before_branch)
   if (stub_group_size == 1)
     {
       /* Default values.  */
       if (stubs_always_before_branch)
-       {
-         stub_group_size = 0x1e00000;
-         stub14_group_size = 0x7800;
-       }
+       stub_group_size = 0x1e00000;
       else
       else
-       {
-         stub_group_size = 0x1c00000;
-         stub14_group_size = 0x7000;
-       }
+       stub_group_size = 0x1c00000;
       suppress_size_errors = TRUE;
     }
 
       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;
       while (tail != NULL)
        {
          asection *curr;
@@ -11875,44 +12151,57 @@ group_sections (struct ppc_link_hash_table *htab,
          bfd_size_type total;
          bfd_boolean big_sec;
          bfd_vma curr_toc;
          bfd_size_type total;
          bfd_boolean big_sec;
          bfd_vma curr_toc;
+         struct map_stub *group;
+         bfd_size_type group_size;
 
          curr = tail;
          total = tail->size;
 
          curr = tail;
          total = tail->size;
-         big_sec = total > (ppc64_elf_section_data (tail) != NULL
-                            && ppc64_elf_section_data (tail)->has_14bit_branch
-                            ? stub14_group_size : stub_group_size);
+         group_size = (ppc64_elf_section_data (tail) != NULL
+                       && ppc64_elf_section_data (tail)->has_14bit_branch
+                       ? stub_group_size >> 10 : stub_group_size);
+
+         big_sec = total > group_size;
          if (big_sec && !suppress_size_errors)
          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;
+           /* xgettext:c-format */
+           _bfd_error_handler (_("%B section %A exceeds stub group size"),
+                               tail->owner, tail);
+         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
                 && ((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)
+                       ? (group_size = stub_group_size >> 10) : group_size))
+                && htab->sec_info[prev->id].toc_off == curr_toc)
            curr = prev;
 
          /* OK, the size from the start of CURR to the end is less
            curr = prev;
 
          /* OK, the size from the start of CURR to the end is less
-            than stub_group_size and thus can be handled by one stub
+            than group_size and thus can be handled by one stub
             section.  (or the tail section is itself larger than
             section.  (or the tail section is itself larger than
-            stub_group_size, in which case we may be toast.)  We
-            should really be keeping track of the total size of stubs
-            added here, as stubs contribute to the final output
-            section size.  That's a little tricky, and this way will
-            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_size, in which case we may be toast.)  We should
+            really be keeping track of the total size of stubs added
+            here, as stubs contribute to the final output section
+            size.  That's a little tricky, and this way will 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
            {
          do
            {
-             prev = PREV_SEC (tail);
+             prev = htab->sec_info[tail->id].u.list;
              /* Set up this stub group.  */
              /* 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);
 
            }
          while (tail != curr && (tail = prev) != NULL);
 
-         /* But wait, there's more!  Input sections up to stub_group_size
+         /* But wait, there's more!  Input sections up to group_size
             bytes before the stub section can be handled by it too.
             Don't do this if we have a really large section after the
             stubs, as adding more stubs increases the chance that
             bytes before the stub section can be handled by it too.
             Don't do this if we have a really large section after the
             stubs, as adding more stubs increases the chance that
@@ -11924,20 +12213,18 @@ group_sections (struct ppc_link_hash_table *htab,
                     && ((total += tail->output_offset - prev->output_offset)
                         < (ppc64_elf_section_data (prev) != NULL
                            && ppc64_elf_section_data (prev)->has_14bit_branch
                     && ((total += tail->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)
+                           ? (group_size = stub_group_size >> 10) : group_size))
+                    && htab->sec_info[prev->id].toc_off == curr_toc)
                {
                  tail = prev;
                {
                  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;
        }
     }
                }
            }
          tail = prev;
        }
     }
-  while (list-- != htab->input_list);
-  free (htab->input_list);
-#undef PREV_SEC
+  return TRUE;
 }
 
 static const unsigned char glink_eh_frame_cie[] =
 }
 
 static const unsigned char glink_eh_frame_cie[] =
@@ -11951,8 +12238,7 @@ static const unsigned char glink_eh_frame_cie[] =
   65,                                  /* RA reg.  */
   1,                                   /* Augmentation size.  */
   DW_EH_PE_pcrel | DW_EH_PE_sdata4,    /* FDE encoding.  */
   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.  */
-  0, 0, 0, 0
+  DW_CFA_def_cfa, 1, 0                 /* def_cfa: r1 offset 0.  */
 };
 
 /* Stripping output sections is normally done before dynamic section
 };
 
 /* Stripping output sections is normally done before dynamic section
@@ -11992,7 +12278,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
   if (htab == NULL)
     return FALSE;
 
   if (htab == NULL)
     return FALSE;
 
-  if (htab->params->plt_thread_safe == -1 && !info->executable)
+  if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
     htab->params->plt_thread_safe = 1;
   if (!htab->opd_abi)
     htab->params->plt_thread_safe = 0;
     htab->params->plt_thread_safe = 1;
   if (!htab->opd_abi)
     htab->params->plt_thread_safe = 0;
@@ -12026,7 +12312,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
        };
       unsigned i;
 
        };
       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],
        {
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, thread_starter[i],
@@ -12042,12 +12328,21 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
   else
     stub_group_size = htab->params->group_size;
 
   else
     stub_group_size = htab->params->group_size;
 
-  group_sections (htab, stub_group_size, stubs_always_before_branch);
+  if (!group_sections (info, stub_group_size, stubs_always_before_branch))
+    return FALSE;
+
+#define STUB_SHRINK_ITER 20
+  /* Loop until no stubs added.  After iteration 20 of this loop we may
+     exit on a stub section shrinking.  This is to break out of a
+     pathological case where adding stubs on one iteration decreases
+     section gaps (perhaps due to alignment), which then requires
+     fewer or smaller stubs on the next iteration.  */
 
   while (1)
     {
       bfd *input_bfd;
       unsigned int bfd_indx;
 
   while (1)
     {
       bfd *input_bfd;
       unsigned int bfd_indx;
+      struct map_stub *group;
       asection *stub_sec;
 
       htab->stub_iteration += 1;
       asection *stub_sec;
 
       htab->stub_iteration += 1;
@@ -12149,7 +12444,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                  if (hash == NULL)
                    {
                      sym_value = sym->st_value;
                  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)
                    }
                  else if (hash->elf.root.type == bfd_link_hash_defined
                           || hash->elf.root.type == bfd_link_hash_defweak)
@@ -12165,8 +12462,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         use the func descriptor sym instead if it is
                         defined.  */
                      if (hash->elf.root.root.string[0] == '.'
                         use the func descriptor sym instead if it is
                         defined.  */
                      if (hash->elf.root.root.string[0] == '.'
-                         && (fdh = lookup_fdh (hash, htab)) != NULL)
+                         && hash->oh != NULL)
                        {
                        {
+                         fdh = ppc_follow_link (hash->oh);
                          if (fdh->elf.root.type == bfd_link_hash_defined
                              || fdh->elf.root.type == bfd_link_hash_defweak)
                            {
                          if (fdh->elf.root.type == bfd_link_hash_defined
                              || fdh->elf.root.type == bfd_link_hash_defweak)
                            {
@@ -12245,8 +12543,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         fact a call needing a TOC adjustment.  */
                      if (code_sec != NULL
                          && code_sec->output_section != NULL
                         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;
                          && (code_sec->has_toc_reloc
                              || code_sec->makes_toc_func_call))
                        stub_type = ppc_stub_long_branch_r2off;
@@ -12286,7 +12584,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    stub_type = ppc_stub_plt_call_r2save;
 
                  /* Support for grouping stub sections.  */
                    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);
 
                  /* Get the name of this stub.  */
                  stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
@@ -12361,7 +12659,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
-           stub_sec->rawsize = stub_sec->size;
+           if (htab->stub_iteration <= STUB_SHRINK_ITER
+               || stub_sec->rawsize < stub_sec->size)
+             /* Past STUB_SHRINK_ITER, rawsize is the max size seen.  */
+             stub_sec->rawsize = stub_sec->size;
            stub_sec->size = 0;
            stub_sec->reloc_count = 0;
            stub_sec->flags &= ~SEC_RELOC;
            stub_sec->size = 0;
            stub_sec->reloc_count = 0;
            stub_sec->flags &= ~SEC_RELOC;
@@ -12375,6 +12676,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
 
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
+      for (group = htab->group; group != NULL; group = group->next)
+       if (group->needs_save_res)
+         group->stub_sec->size += htab->sfpr->size;
+
       if (info->emitrelocations
          && htab->glink != NULL && htab->glink->size != 0)
        {
       if (info->emitrelocations
          && htab->glink != NULL && htab->glink->size != 0)
        {
@@ -12386,21 +12691,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
          && htab->glink_eh_frame->output_section->size != 0)
        {
          && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
          && htab->glink_eh_frame->output_section->size != 0)
        {
-         size_t size = 0, align;
+         size_t size = 0, align = 4;
 
          for (stub_sec = htab->params->stub_bfd->sections;
               stub_sec != NULL;
               stub_sec = stub_sec->next)
            if ((stub_sec->flags & SEC_LINKER_CREATED) == 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)
-             size += 24;
+             size += (17 + align - 1) & -align;
          if (htab->glink != NULL && htab->glink->size != 0)
          if (htab->glink != NULL && htab->glink->size != 0)
-           size += 24;
+           size += (24 + align - 1) & -align;
          if (size != 0)
          if (size != 0)
-           size += sizeof (glink_eh_frame_cie);
-         align = 1;
-         align <<= htab->glink_eh_frame->output_section->alignment_power;
-         align -= 1;
-         size = (size + align) & ~align;
+           size += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
+         align = 1ul << htab->glink_eh_frame->output_section->alignment_power;
+         size = (size + align - 1) & -align;
          htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
          htab->glink_eh_frame->size = size;
        }
          htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
          htab->glink_eh_frame->size = size;
        }
@@ -12412,17 +12715,17 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
            stub_sec->size = ((stub_sec->size
                               + (1 << htab->params->plt_stub_align) - 1)
          if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
            stub_sec->size = ((stub_sec->size
                               + (1 << htab->params->plt_stub_align) - 1)
-                             & (-1 << htab->params->plt_stub_align));
+                             & -(1 << htab->params->plt_stub_align));
 
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 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->rawsize != stub_sec->size)
+           && stub_sec->rawsize != stub_sec->size
+           && (htab->stub_iteration <= STUB_SHRINK_ITER
+               || stub_sec->rawsize < stub_sec->size))
          break;
 
          break;
 
-      /* Exit from this loop when no stubs have been added, and no stubs
-        have changed size.  */
       if (stub_sec == NULL
          && (htab->glink_eh_frame == NULL
              || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
       if (stub_sec == NULL
          && (htab->glink_eh_frame == NULL
              || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
@@ -12445,12 +12748,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
        return FALSE;
       htab->glink_eh_frame->contents = p;
       last_fde = p;
        return FALSE;
       htab->glink_eh_frame->contents = p;
       last_fde = p;
+      align = 4;
 
       memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
       /* CIE length (rewrite in case little-endian).  */
 
       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;
+      last_fde_len = ((sizeof (glink_eh_frame_cie) + align - 1) & -align) - 4;
       bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
       bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
-      p += sizeof (glink_eh_frame_cie);
+      p += last_fde_len + 4;
 
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
 
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
@@ -12458,9 +12762,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
            last_fde = p;
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
            last_fde = p;
-           last_fde_len = 20;
+           last_fde_len = ((17 + align - 1) & -align) - 4;
            /* FDE length.  */
            /* FDE length.  */
-           bfd_put_32 (htab->elf.dynobj, 20, p);
+           bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
            p += 4;
            /* CIE pointer.  */
            val = p - htab->glink_eh_frame->contents;
            p += 4;
            /* CIE pointer.  */
            val = p - htab->glink_eh_frame->contents;
@@ -12474,14 +12778,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
            /* Augmentation.  */
            p += 1;
            /* Pad.  */
            /* Augmentation.  */
            p += 1;
            /* Pad.  */
-           p += 7;
+           p += ((17 + align - 1) & -align) - 17;
          }
       if (htab->glink != NULL && htab->glink->size != 0)
        {
          last_fde = p;
          }
       if (htab->glink != NULL && htab->glink->size != 0)
        {
          last_fde = p;
-         last_fde_len = 20;
+         last_fde_len = ((24 + align - 1) & -align) - 4;
          /* FDE length.  */
          /* FDE length.  */
-         bfd_put_32 (htab->elf.dynobj, 20, p);
+         bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
          p += 4;
          /* CIE pointer.  */
          val = p - htab->glink_eh_frame->contents;
          p += 4;
          /* CIE pointer.  */
          val = p - htab->glink_eh_frame->contents;
@@ -12498,19 +12802,18 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          *p++ = DW_CFA_advance_loc + 1;
          *p++ = DW_CFA_register;
          *p++ = 65;
          *p++ = DW_CFA_advance_loc + 1;
          *p++ = DW_CFA_register;
          *p++ = 65;
-         *p++ = 12;
+         *p++ = htab->opd_abi ? 12 : 0;
          *p++ = DW_CFA_advance_loc + 4;
          *p++ = DW_CFA_restore_extended;
          *p++ = 65;
          *p++ = DW_CFA_advance_loc + 4;
          *p++ = DW_CFA_restore_extended;
          *p++ = 65;
+         p += ((24 + align - 1) & -align) - 24;
        }
       /* 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.  */
        }
       /* 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.  */
+      align = 1ul << htab->glink_eh_frame->output_section->alignment_power;
       size = p - htab->glink_eh_frame->contents;
       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;
+      pad = ((size + align - 1) & -align) - size;
       htab->glink_eh_frame->size = size + pad;
       bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
     }
       htab->glink_eh_frame->size = size + pad;
       bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
     }
@@ -12529,7 +12832,35 @@ bfd_vma
 ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 {
   asection *s;
 ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 {
   asection *s;
-  bfd_vma TOCstart;
+  bfd_vma TOCstart, adjust;
+
+  if (info != NULL)
+    {
+      struct elf_link_hash_entry *h;
+      struct elf_link_hash_table *htab = elf_hash_table (info);
+
+      if (is_elf_hash_table (htab)
+         && htab->hgot != NULL)
+       h = htab->hgot;
+      else
+       {
+         h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE);
+         if (is_elf_hash_table (htab))
+           htab->hgot = h;
+       }
+      if (h != NULL
+         && h->root.type == bfd_link_hash_defined
+         && !h->root.linker_def
+         && (!is_elf_hash_table (htab)
+             || h->def_regular))
+       {
+         TOCstart = (h->root.u.def.value - TOC_BASE_OFF
+                     + h->root.u.def.section->output_offset
+                     + h->root.u.def.section->output_section->vma);
+         _bfd_set_gp_value (obfd, TOCstart);
+         return TOCstart;
+       }
+    }
 
   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
      order.  The TOC starts where the first of these sections starts.  */
 
   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
      order.  The TOC starts where the first of these sections starts.  */
@@ -12577,6 +12908,9 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
   if (s != NULL)
     TOCstart = s->output_section->vma + s->output_offset;
 
   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)
   _bfd_set_gp_value (obfd, TOCstart);
 
   if (info != NULL && s != NULL)
@@ -12587,7 +12921,7 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
        {
          if (htab->elf.hgot != NULL)
            {
        {
          if (htab->elf.hgot != NULL)
            {
-             htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
+             htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust;
              htab->elf.hgot->root.u.def.section = s;
            }
        }
              htab->elf.hgot->root.u.def.section = s;
            }
        }
@@ -12595,8 +12929,8 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
        {
          struct bfd_link_hash_entry *bh = NULL;
          _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
        {
          struct bfd_link_hash_entry *bh = NULL;
          _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
-                                           s, TOC_BASE_OFF, NULL, FALSE,
-                                           FALSE, &bh);
+                                           s, TOC_BASE_OFF - adjust,
+                                           NULL, FALSE, FALSE, &bh);
        }
     }
   return TOCstart;
        }
     }
   return TOCstart;
@@ -12704,6 +13038,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
                       char **stats)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (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;
   asection *stub_sec;
   bfd_byte *p;
   int stub_sec_count = 0;
@@ -12721,9 +13056,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
        if (stub_sec->contents == NULL)
          return FALSE;
        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
-          size.  rawsize is a convenient location to use.  */
-       stub_sec->rawsize = stub_sec->size;
        stub_sec->size = 0;
       }
 
        stub_sec->size = 0;
       }
 
@@ -12877,6 +13209,23 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
+  for (group = htab->group; group != NULL; group = group->next)
+    if (group->needs_save_res)
+      {
+       stub_sec = group->stub_sec;
+       memcpy (stub_sec->contents + stub_sec->size, htab->sfpr->contents,
+               htab->sfpr->size);
+       if (htab->params->emit_stub_syms)
+         {
+           unsigned int i;
+
+           for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
+             if (!sfpr_define (info, &save_res_funcs[i], stub_sec))
+               return FALSE;
+         }
+       stub_sec->size += htab->sfpr->size;
+      }
+
   if (htab->relbrlt != NULL)
     htab->relbrlt->reloc_count = 0;
 
   if (htab->relbrlt != NULL)
     htab->relbrlt->reloc_count = 0;
 
@@ -12887,7 +13236,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
        stub_sec->size = ((stub_sec->size
                           + (1 << htab->params->plt_stub_align) - 1)
       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
        stub_sec->size = ((stub_sec->size
                           + (1 << htab->params->plt_stub_align) - 1)
-                         & (-1 << htab->params->plt_stub_align));
+                         & -(1 << htab->params->plt_stub_align));
 
   for (stub_sec = htab->params->stub_bfd->sections;
        stub_sec != NULL;
 
   for (stub_sec = htab->params->stub_bfd->sections;
        stub_sec != NULL;
@@ -12895,7 +13244,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
     if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
       {
        stub_sec_count += 1;
     if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
       {
        stub_sec_count += 1;
-       if (stub_sec->rawsize != stub_sec->size)
+       if (stub_sec->rawsize != stub_sec->size
+           && (htab->stub_iteration <= STUB_SHRINK_ITER
+               || stub_sec->rawsize < stub_sec->size))
          break;
       }
 
          break;
       }
 
@@ -12940,33 +13291,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   return TRUE;
 }
 
   return TRUE;
 }
 
-/* This function undoes the changes made by add_symbol_adjust.  */
-
-static bfd_boolean
-undo_symbol_twiddle (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
-{
-  struct ppc_link_hash_entry *eh;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  eh = (struct ppc_link_hash_entry *) h;
-  if (eh->elf.root.type != bfd_link_hash_undefweak || !eh->was_undefined)
-    return TRUE;
-
-  eh->elf.root.type = bfd_link_hash_undefined;
-  return TRUE;
-}
-
-void
-ppc64_elf_restore_symbols (struct bfd_link_info *info)
-{
-  struct ppc_link_hash_table *htab = ppc_hash_table (info);
-
-  if (htab != NULL)
-    elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
-}
-
 /* What to do when ld finds relocations against symbols defined in
    discarded sections.  */
 
 /* What to do when ld finds relocations against symbols defined in
    discarded sections.  */
 
@@ -13028,6 +13352,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_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;
   Elf_Internal_Rela *relend;
   Elf_Internal_Rela outrel;
   bfd_byte *loc;
@@ -13037,7 +13362,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   bfd_boolean is_opd;
   /* Assume 'at' branch hints.  */
   bfd_boolean is_isa_v2 = TRUE;
   bfd_boolean is_opd;
   /* Assume 'at' branch hints.  */
   bfd_boolean is_isa_v2 = TRUE;
-  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
+  bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
 
   /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
 
   /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
@@ -13059,9 +13384,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;
 
   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;
   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;
     {
       enum elf_ppc64_reloc_type r_type;
       bfd_vma addend;
@@ -13085,10 +13410,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
       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;
 
       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);
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
 
@@ -13096,10 +13424,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)
         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)
          && is_opd)
-       r_symndx = ELF64_R_SYM (rel[-1].r_info);
+       r_symndx = ELF64_R_SYM (wrel[-1].r_info);
 
       sym = NULL;
       sec = NULL;
 
       sym = NULL;
       sec = NULL;
@@ -13180,18 +13508,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       h = (struct ppc_link_hash_entry *) h_elf;
 
       if (sec != NULL && discarded_section (sec))
       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)
        {
 
       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;
        }
          sec = bfd_abs_section_ptr;
          unresolved_reloc = FALSE;
        }
@@ -13250,8 +13591,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          else
            info->callbacks->einfo
              (!IS_PPC64_TLS_RELOC (r_type)
          else
            info->callbacks->einfo
              (!IS_PPC64_TLS_RELOC (r_type)
-              ? _("%P: %H: %s used with TLS symbol `%T'\n")
-              : _("%P: %H: %s used with non-TLS symbol `%T'\n"),
+              /* xgettext:c-format */
+              ? _("%H: %s used with TLS symbol `%T'\n")
+              /* xgettext:c-format */
+              : _("%H: %s used with non-TLS symbol `%T'\n"),
               input_bfd, input_section, rel->r_offset,
               ppc64_elf_howto_table[r_type]->name,
               sym_name);
               input_bfd, input_section, rel->r_offset,
               ppc64_elf_howto_table[r_type]->name,
               sym_name);
@@ -13276,11 +13619,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_LO_DS_OPT:
          break;
 
        case R_PPC64_LO_DS_OPT:
-         insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+         insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset);
          if ((insn & (0x3f << 26)) != 58u << 26)
            abort ();
          insn += (14u << 26) - (58u << 26);
          if ((insn & (0x3f << 26)) != 58u << 26)
            abort ();
          insn += (14u << 26) - (58u << 26);
-         bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+         bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset);
          r_type = R_PPC64_TOC16_LO;
          rel->r_info = ELF64_R_INFO (r_symndx, r_type);
          break;
          r_type = R_PPC64_TOC16_LO;
          rel->r_info = ELF64_R_INFO (r_symndx, r_type);
          break;
@@ -13335,7 +13678,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && (tls_mask & TLS_TPREL) == 0)
            {
              rel->r_offset -= d_offset;
              && (tls_mask & TLS_TPREL) == 0)
            {
              rel->r_offset -= d_offset;
-             bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+             bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
              r_type = R_PPC64_NONE;
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
            }
              r_type = R_PPC64_NONE;
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
            }
@@ -13347,10 +13690,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && (tls_mask & TLS_TPREL) == 0)
            {
            toctprel:
              && (tls_mask & TLS_TPREL) == 0)
            {
            toctprel:
-             insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
              insn &= 31 << 21;
              insn |= 0x3c0d0000;       /* addis 0,13,0 */
              insn &= 31 << 21;
              insn |= 0x3c0d0000;       /* addis 0,13,0 */
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+             bfd_put_32 (input_bfd, insn,
+                         contents + rel->r_offset - d_offset);
              r_type = R_PPC64_TPREL16_HA;
              if (toc_symndx != 0)
                {
              r_type = R_PPC64_TPREL16_HA;
              if (toc_symndx != 0)
                {
@@ -13358,8 +13703,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->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);
                }
              else
                rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -13370,11 +13714,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
              if (insn == 0)
                abort ();
              insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
              if (insn == 0)
                abort ();
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
              /* Was PPC64_TLS which sits on insn boundary, now
                 PPC64_TPREL16_LO which is at low-order half-word.  */
              rel->r_offset += d_offset;
              /* Was PPC64_TLS which sits on insn boundary, now
                 PPC64_TPREL16_LO which is at low-order half-word.  */
              rel->r_offset += d_offset;
@@ -13385,8 +13729,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->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);
                }
              else
                rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -13411,7 +13754,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              else
                {
                  rel->r_offset -= d_offset;
              else
                {
                  rel->r_offset -= d_offset;
-                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+                 bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
                  r_type = R_PPC64_NONE;
                }
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
                  r_type = R_PPC64_NONE;
                }
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -13449,7 +13792,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 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.  */
                 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,
+             insn1 = bfd_get_32 (input_bfd,
                                  contents + rel->r_offset - d_offset);
              if ((tls_mask & tls_gd) != 0)
                {
                                  contents + rel->r_offset - d_offset);
              if ((tls_mask & tls_gd) != 0)
                {
@@ -13505,28 +13848,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      rel[1].r_addend = rel->r_addend;
                    }
                }
                      rel[1].r_addend = rel->r_addend;
                    }
                }
-             bfd_put_32 (output_bfd, insn1,
+             bfd_put_32 (input_bfd, insn1,
                          contents + rel->r_offset - d_offset);
              if (offset != (bfd_vma) -1)
                {
                          contents + rel->r_offset - d_offset);
              if (offset != (bfd_vma) -1)
                {
-                 insn3 = bfd_get_32 (output_bfd,
+                 insn3 = bfd_get_32 (input_bfd,
                                      contents + offset + 4);
                  if (insn3 == NOP
                      || insn3 == CROR_151515 || insn3 == CROR_313131)
                    {
                      rel[1].r_offset += 4;
                                      contents + offset + 4);
                  if (insn3 == NOP
                      || insn3 == CROR_151515 || insn3 == CROR_313131)
                    {
                      rel[1].r_offset += 4;
-                     bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                     bfd_put_32 (input_bfd, insn2, contents + offset + 4);
                      insn2 = NOP;
                    }
                      insn2 = NOP;
                    }
-                 bfd_put_32 (output_bfd, insn2, contents + offset);
+                 bfd_put_32 (input_bfd, insn2, contents + offset);
                }
              if ((tls_mask & tls_gd) == 0
                  && (tls_gd == 0 || toc_symndx != 0))
                {
                  /* We changed the symbol.  Start over in order
                     to get h, sym, sec etc. right.  */
                }
              if ((tls_mask & tls_gd) == 0
                  && (tls_gd == 0 || toc_symndx != 0))
                {
                  /* We changed the symbol.  Start over in order
                     to get h, sym, sec etc. right.  */
-                 rel--;
-                 continue;
+                 goto again;
                }
            }
          break;
                }
            }
          break;
@@ -13559,21 +13901,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (offset == rel[1].r_offset);
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (offset == rel[1].r_offset);
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
-             insn3 = bfd_get_32 (output_bfd,
+             insn3 = bfd_get_32 (input_bfd,
                                  contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
                  rel->r_offset += 4;
                                  contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
                  rel->r_offset += 4;
-                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 bfd_put_32 (input_bfd, insn2, contents + offset + 4);
                  insn2 = NOP;
                }
                  insn2 = NOP;
                }
-             bfd_put_32 (output_bfd, insn2, contents + offset);
+             bfd_put_32 (input_bfd, insn2, contents + offset);
              if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
              if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
-               {
-                 rel--;
-                 continue;
-               }
+               goto again;
            }
          break;
 
            }
          break;
 
@@ -13605,18 +13944,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              BFD_ASSERT (offset == rel[1].r_offset);
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
              insn2 = 0x38630000;       /* addi 3,3,0 */
              BFD_ASSERT (offset == rel[1].r_offset);
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
              insn2 = 0x38630000;       /* addi 3,3,0 */
-             insn3 = bfd_get_32 (output_bfd,
+             insn3 = bfd_get_32 (input_bfd,
                                  contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
                  rel->r_offset += 4;
                                  contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
                  rel->r_offset += 4;
-                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 bfd_put_32 (input_bfd, insn2, contents + offset + 4);
                  insn2 = NOP;
                }
                  insn2 = NOP;
                }
-             bfd_put_32 (output_bfd, insn2, contents + offset);
-             rel--;
-             continue;
+             bfd_put_32 (input_bfd, insn2, contents + offset);
+             goto again;
            }
          break;
 
            }
          break;
 
@@ -13657,6 +13995,52 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
            }
          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 (input_bfd,
+                             LIS_R2 + PPC_HA (relocation),
+                             contents + rel->r_offset);
+                 bfd_put_32 (input_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 (input_bfd,
+                                 ADDIS_R2_R12 + PPC_HA (relocation),
+                                 contents + rel->r_offset);
+                     bfd_put_32 (input_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
        case R_PPC64_REL16_HA:
          /* If we are generating a non-PIC executable, edit
             .  0:      addis 2,12,.TOC.-0b@ha
@@ -13665,8 +14049,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             .          lis 2,.TOC.@ha
             .          addi 2,2,.TOC.@l
             if .TOC. is in range.  */
             .          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
              && !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)
              && h != NULL && &h->elf == htab->elf.hgot
              && rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
@@ -13676,17 +14062,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              unsigned int insn1, insn2;
              bfd_vma offset = rel->r_offset - d_offset;
            {
              unsigned int insn1, insn2;
              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 */)
+             insn1 = bfd_get_32 (input_bfd, contents + offset);
+             insn2 = bfd_get_32 (input_bfd, contents + offset + 4);
+             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;
                {
                  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 (input_bfd, LIS_R2, contents + offset);
                }
            }
          break;
                }
            }
          break;
@@ -13722,18 +14108,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
          insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
          insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
-         /* Fall thru.  */
+         /* Fall through.  */
 
          /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
 
          /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
-         insn |= bfd_get_32 (output_bfd,
+         insn |= bfd_get_32 (input_bfd,
                              contents + rel->r_offset) & ~(0x01 << 21);
                              contents + rel->r_offset) & ~(0x01 << 21);
-         /* Fall thru.  */
+         /* Fall through.  */
 
        case R_PPC64_REL14:
          max_br_offset = 1 << 15;
 
        case R_PPC64_REL14:
          max_br_offset = 1 << 15;
-         /* Fall thru.  */
+         /* Fall through.  */
 
        case R_PPC64_REL24:
          /* Calls to functions with a different TOC, such as calls to
 
        case R_PPC64_REL24:
          /* Calls to functions with a different TOC, such as calls to
@@ -13778,7 +14164,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          if (h != NULL
                              && (h == htab->tls_get_addr_fd
                                  || h == htab->tls_get_addr)
                          if (h != NULL
                              && (h == htab->tls_get_addr_fd
                                  || h == htab->tls_get_addr)
-                             && !htab->params->no_tls_get_addr_opt)
+                             && htab->params->tls_get_addr_opt)
                            {
                              /* Special stub used, leave nop alone.  */
                            }
                            {
                              /* Special stub used, leave nop alone.  */
                            }
@@ -13837,12 +14223,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  if (stub_entry->stub_type == ppc_stub_plt_call
                      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
                    info->callbacks->einfo
                  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; "
+                     /* xgettext:c-format */
+                     (_("%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
                         "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; "
+                     /* xgettext:c-format */
+                     (_("%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);
 
                         "(-mcmodel=small toc adjust stub)\n"),
                       input_bfd, input_section, rel->r_offset, sym_name);
 
@@ -13898,9 +14286,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.  */
            {
              /* 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;
 
              addend = 0;
              reloc_dest = DEST_STUB;
 
@@ -13935,7 +14332,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    insn ^= 0x01 << 21;
                }
 
                    insn ^= 0x01 << 21;
                }
 
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
            }
 
          /* NOP out calls to undefined weak functions.
            }
 
          /* NOP out calls to undefined weak functions.
@@ -13948,8 +14345,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   && relocation == 0
                   && addend == 0)
            {
                   && relocation == 0
                   && addend == 0)
            {
-             bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
-             continue;
+             bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
+             goto copy_reloc;
            }
          break;
        }
            }
          break;
        }
@@ -13960,12 +14357,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        {
        default:
          info->callbacks->einfo
        {
        default:
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: %B: unknown relocation type %d for `%T'\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
            (_("%P: %B: unknown relocation type %d for `%T'\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
@@ -13974,7 +14372,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOCSAVE:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
        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
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
             address in the GOT as relocation value instead of the
@@ -14030,14 +14429,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              ent = ppc64_tlsld_got (input_bfd);
            else
              {
              ent = ppc64_tlsld_got (input_bfd);
            else
              {
-
                if (h != NULL)
                  {
                if (h != NULL)
                  {
-                   bfd_boolean dyn = htab->elf.dynamic_sections_created;
-                   if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
-                                                         &h->elf)
-                       || (info->shared
-                           && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
+                   if (!htab->elf.dynamic_sections_created
+                       || h->elf.dynindx == -1
+                       || SYMBOL_REFERENCES_LOCAL (info, &h->elf)
+                       || (ELF_ST_VISIBILITY (h->elf.other) != STV_DEFAULT
+                           && h->elf.root.type == bfd_link_hash_undefweak))
                      /* 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
                      /* 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
@@ -14045,7 +14443,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      ;
                    else
                      {
                      ;
                    else
                      {
-                       BFD_ASSERT (h->elf.dynindx != -1);
                        indx = h->elf.dynindx;
                        unresolved_reloc = FALSE;
                      }
                        indx = h->elf.dynindx;
                        unresolved_reloc = FALSE;
                      }
@@ -14094,13 +14491,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                         ? h->elf.type == STT_GNU_IFUNC
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if (ifunc)
                         ? h->elf.type == STT_GNU_IFUNC
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if (ifunc)
-                 relgot = htab->elf.irelplt;
-               else if ((info->shared || indx != 0)
-                        && (h == NULL
-                            || (tls_type == (TLS_TLS | TLS_LD)
-                                && !h->elf.def_dynamic)
-                            || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
-                            || h->elf.root.type != bfd_link_hash_undefweak))
+                 {
+                   relgot = htab->elf.irelplt;
+                   if (indx == 0)
+                     htab->local_ifunc_resolver = 1;
+                   else if (is_static_defined (&h->elf))
+                     htab->maybe_local_ifunc_resolver = 1;
+                 }
+               else if (indx != 0
+                        || (bfd_link_pic (info)
+                            && (h == NULL
+                                || (ELF_ST_VISIBILITY (h->elf.other)
+                                    == STV_DEFAULT)
+                                || h->elf.root.type != bfd_link_hash_undefweak
+                                || (tls_type == (TLS_TLS | TLS_LD)
+                                    && !h->elf.def_dynamic))))
                  relgot = ppc64_elf_tdata (ent->owner)->relgot;
                if (relgot != NULL)
                  {
                  relgot = ppc64_elf_tdata (ent->owner)->relgot;
                if (relgot != NULL)
                  {
@@ -14166,28 +14571,34 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   emitting a reloc.  */
                else
                  {
                   emitting a reloc.  */
                else
                  {
+                   int tlsopt
+                     = (htab->params->tls_get_addr_opt
+                        && htab->tls_get_addr_fd != NULL
+                        && htab->tls_get_addr_fd->elf.plt.plist != NULL);
+
                    relocation += addend;
                    relocation += addend;
-                   if (tls_type == (TLS_TLS | TLS_LD))
-                     relocation = 1;
-                   else if (tls_type != 0)
+                   if (tls_type != 0)
                      {
                        if (htab->elf.tls_sec == NULL)
                          relocation = 0;
                        else
                          {
                      {
                        if (htab->elf.tls_sec == NULL)
                          relocation = 0;
                        else
                          {
-                           relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
-                           if (tls_type == (TLS_TLS | TLS_TPREL))
+                           if (tls_type & TLS_LD)
+                             relocation = 0;
+                           else
+                             relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
+                           if ((tls_type & TLS_TPREL)
+                               || (tlsopt && !(tls_type & TLS_DTPREL)))
                              relocation += DTP_OFFSET - TP_OFFSET;
                          }
 
                              relocation += DTP_OFFSET - TP_OFFSET;
                          }
 
-                       if (tls_type == (TLS_TLS | TLS_GD))
+                       if (tls_type & (TLS_GD | TLS_LD))
                          {
                            bfd_put_64 (output_bfd, relocation,
                                        got->contents + off + 8);
                          {
                            bfd_put_64 (output_bfd, relocation,
                                        got->contents + off + 8);
-                           relocation = 1;
+                           relocation = !tlsopt;
                          }
                      }
                          }
                      }
-
                    bfd_put_64 (output_bfd, relocation,
                                got->contents + off);
                  }
                    bfd_put_64 (output_bfd, relocation,
                                got->contents + off);
                  }
@@ -14197,7 +14608,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              abort ();
 
            relocation = got->output_section->vma + got->output_offset + off;
              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;
 
          }
          break;
 
@@ -14208,41 +14619,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.  */
        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)
          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 (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;
          else
            unresolved_reloc = TRUE;
          goto dodyn;
@@ -14257,7 +14681,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC16_DS:
        case R_PPC64_TOC16_LO_DS:
        case R_PPC64_TOC16_HA:
        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.  */
          break;
 
          /* Relocate against the beginning of the section.  */
@@ -14275,6 +14699,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_REL16_LO:
        case R_PPC64_REL16_HI:
        case R_PPC64_REL16_HA:
+       case R_PPC64_REL16DX_HA:
          break;
 
        case R_PPC64_REL14:
          break;
 
        case R_PPC64_REL14:
@@ -14305,15 +14730,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 defined before using them.  */
              bfd_byte *p = contents + rel->r_offset - d_offset;
 
                 defined before using them.  */
              bfd_byte *p = contents + rel->r_offset - d_offset;
 
-             insn = bfd_get_32 (output_bfd, p);
+             insn = bfd_get_32 (input_bfd, p);
              insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
              if (insn != 0)
              insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
              if (insn != 0)
-               bfd_put_32 (output_bfd, insn, p);
+               bfd_put_32 (input_bfd, insn, p);
              break;
            }
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + TP_OFFSET;
              break;
            }
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + TP_OFFSET;
-         if (info->shared)
+         if (bfd_link_pic (info))
            /* The TPREL16 relocs shouldn't really be used in shared
               libs as they will result in DT_TEXTREL being set, but
               support them anyway.  */
            /* The TPREL16 relocs shouldn't really be used in shared
               libs as they will result in DT_TEXTREL being set, but
               support them anyway.  */
@@ -14355,7 +14780,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_DTPREL64:
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
        case R_PPC64_DTPREL64:
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
-         /* Fall thru */
+         /* Fall through.  */
 
          /* Relocations that may need to be propagated if this is a
             dynamic object.  */
 
          /* Relocations that may need to be propagated if this is a
             dynamic object.  */
@@ -14390,26 +14815,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (NO_OPD_RELOCS && is_opd)
            break;
 
          if (NO_OPD_RELOCS && is_opd)
            break;
 
-         if ((info->shared
-              && (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
-                 && h != NULL
-                 && h->elf.dynindx != -1
-                 && !h->elf.non_got_ref
-                 && !h->elf.def_regular)
-             || (!info->shared
-                 && (h != NULL
-                     ? h->elf.type == STT_GNU_IFUNC
-                     : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
+         if (bfd_link_pic (info)
+             ? ((h == NULL
+                 || h->dyn_relocs != NULL)
+                && ((h != NULL && pc_dynrelocs (h))
+                    || must_be_dyn_reloc (info, r_type)))
+             : (h != NULL
+                ? h->dyn_relocs != NULL
+                : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
            {
              bfd_boolean skip, relocate;
              asection *sreloc;
              bfd_vma out_off;
            {
              bfd_boolean skip, relocate;
              asection *sreloc;
              bfd_vma out_off;
+             long indx = 0;
 
              /* When generating a dynamic object, these relocations
                 are copied into the output file to be resolved at run
 
              /* When generating a dynamic object, these relocations
                 are copied into the output file to be resolved at run
@@ -14446,8 +14864,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                {
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                {
-                 BFD_ASSERT (h->elf.dynindx != -1);
-                 outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+                 indx = h->elf.dynindx;
+                 BFD_ASSERT (indx != -1);
+                 outrel.r_info = ELF64_R_INFO (indx, r_type);
                }
              else
                {
                }
              else
                {
@@ -14490,14 +14909,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    }
                  else
                    {
                    }
                  else
                    {
-                     long indx = 0;
-
                      if (h != NULL
                          ? h->elf.type == STT_GNU_IFUNC
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                        {
                          info->callbacks->einfo
                      if (h != NULL
                          ? h->elf.type == STT_GNU_IFUNC
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                        {
                          info->callbacks->einfo
-                           (_("%P: %H: %s for indirect "
+                           /* xgettext:c-format */
+                           (_("%H: %s for indirect "
                               "function `%T' unsupported\n"),
                             input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
                               "function `%T' unsupported\n"),
                             input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
@@ -14545,7 +14963,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (h != NULL
                  ? h->elf.type == STT_GNU_IFUNC
                  : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
              if (h != NULL
                  ? h->elf.type == STT_GNU_IFUNC
                  : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-               sreloc = htab->elf.irelplt;
+               {
+                 sreloc = htab->elf.irelplt;
+                 if (indx == 0)
+                   htab->local_ifunc_resolver = 1;
+                 else if (is_static_defined (&h->elf))
+                   htab->maybe_local_ifunc_resolver = 1;
+               }
              if (sreloc == NULL)
                abort ();
 
              if (sreloc == NULL)
                abort ();
 
@@ -14577,11 +15001,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    addend = outrel.r_addend;
                  /* Adjust pc_relative relocs to have zero in *r_offset.  */
                  else if (ppc64_elf_howto_table[r_type]->pc_relative)
                    addend = outrel.r_addend;
                  /* Adjust pc_relative relocs to have zero in *r_offset.  */
                  else if (ppc64_elf_howto_table[r_type]->pc_relative)
-                   addend = (input_section->output_section->vma
-                             + input_section->output_offset
-                             + rel->r_offset);
+                   addend = outrel.r_offset;
                }
            }
                }
            }
+         else if (r_type == R_PPC64_DTPMOD64
+                  && htab->params->tls_get_addr_opt
+                  && htab->tls_get_addr_fd != NULL
+                  && htab->tls_get_addr_fd->elf.plt.plist != NULL)
+           {
+             /* Set up for __tls_get_addr_opt stub, when this entry
+                does not have dynamic relocs.  */
+             relocation = 0;
+             /* Set up the next word for local dynamic.  If it turns
+                out to be global dynamic, the reloc will overwrite
+                this value.  */
+             if (rel->r_offset + 16 <= input_section->size)
+               bfd_put_64 (input_bfd, DTP_OFFSET - TP_OFFSET,
+                           contents + rel->r_offset + 8);
+           }
+         else if (r_type == R_PPC64_DTPREL64
+                  && htab->params->tls_get_addr_opt
+                  && htab->tls_get_addr_fd != NULL
+                  && htab->tls_get_addr_fd->elf.plt.plist != NULL
+                  && rel > relocs
+                  && rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64)
+                  && rel[-1].r_offset + 8 == rel->r_offset)
+           {
+             /* __tls_get_addr_opt stub value.  */
+             addend += DTP_OFFSET - TP_OFFSET;
+           }
          break;
 
        case R_PPC64_COPY:
          break;
 
        case R_PPC64_COPY:
@@ -14604,13 +15052,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          /* These ones haven't been implemented yet.  */
 
          info->callbacks->einfo
          /* These ones haven't been implemented yet.  */
 
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: %B: %s is not supported for `%T'\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
          bfd_set_error (bfd_error_invalid_operation);
          ret = FALSE;
            (_("%P: %B: %s is not supported for `%T'\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
          bfd_set_error (bfd_error_invalid_operation);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
        }
 
       /* Multi-instruction sequences that access the TOC can be
        }
 
       /* Multi-instruction sequences that access the TOC can be
@@ -14687,6 +15136,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_REL16_HA:
          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:
        case R_PPC64_ADDR16_HA:
        case R_PPC64_ADDR16_HIGHA:
        case R_PPC64_ADDR16_HIGHERA:
@@ -14707,7 +15157,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             alone (it will be set to zero elsewhere in the link).  */
          if (sec == NULL)
            break;
             alone (it will be set to zero elsewhere in the link).  */
          if (sec == NULL)
            break;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC64_GOT16_HA:
        case R_PPC64_PLTGOT16_HA:
 
        case R_PPC64_GOT16_HA:
        case R_PPC64_PLTGOT16_HA:
@@ -14742,24 +15192,29 @@ 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;
        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;
            mask = 15;
-         if (((relocation + addend) & mask) != 0)
+         relocation += addend;
+         addend = insn & (mask ^ 3);
+         if ((relocation & mask) != 0)
            {
            {
+             relocation ^= relocation & mask;
              info->callbacks->einfo
              info->callbacks->einfo
-               (_("%P: %H: error: %s not a multiple of %u\n"),
+               /* xgettext:c-format */
+               (_("%H: error: %s not a multiple of %u\n"),
                 input_bfd, input_section, rel->r_offset,
                 howto->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
              ret = FALSE;
                 input_bfd, input_section, rel->r_offset,
                 howto->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
              ret = FALSE;
-             continue;
+             goto copy_reloc;
            }
          break;
        }
            }
          break;
        }
@@ -14774,7 +15229,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                      rel->r_offset) != (bfd_vma) -1)
        {
          info->callbacks->einfo
                                      rel->r_offset) != (bfd_vma) -1)
        {
          info->callbacks->einfo
-           (_("%P: %H: unresolvable %s against `%T'\n"),
+           /* xgettext:c-format */
+           (_("%H: unresolvable %s against `%T'\n"),
             input_bfd, input_section, rel->r_offset,
             howto->name,
             h->elf.root.root.string);
             input_bfd, input_section, rel->r_offset,
             howto->name,
             h->elf.root.root.string);
@@ -14809,8 +15265,30 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
        }
 
            }
        }
 
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                   rel->r_offset, relocation, addend);
+      if (r_type == R_PPC64_REL16DX_HA)
+       {
+         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         if (rel->r_offset + 4 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             relocation += addend;
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             relocation = (bfd_signed_vma) relocation >> 16;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~0x1fffc1;
+             insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+             r = bfd_reloc_ok;
+             if (relocation + 0x8000 > 0xffff)
+               r = bfd_reloc_overflow;
+           }
+       }
+      else
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
 
       if (r != bfd_reloc_ok)
        {
@@ -14831,31 +15309,25 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          if (r == bfd_reloc_overflow)
            {
 
          if (r == bfd_reloc_overflow)
            {
-             if (warned)
-               continue;
-             if (h != NULL
-                 && h->elf.root.type == bfd_link_hash_undefweak
-                 && howto->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
            {
              info->callbacks->einfo
            }
          else
            {
              info->callbacks->einfo
-               (_("%P: %H: %s against `%T': error %d\n"),
+               /* xgettext:c-format */
+               (_("%H: %s against `%T': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
                 reloc_name, sym_name, (int) r);
              ret = FALSE;
                 input_bfd, input_section, rel->r_offset,
                 reloc_name, sym_name, (int) r);
              ret = FALSE;
@@ -14863,6 +15335,29 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (more_info != NULL)
            free (more_info);
        }
          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
     }
 
   /* If we're emitting relocations, then shortly after this function
@@ -14870,7 +15365,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.  */
      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);
     {
       bfd_size_type amt;
       amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
@@ -14905,7 +15400,7 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
     return 1;
 
   value = elfsym->st_value - input_sec->output_offset;
     return 1;
 
   value = elfsym->st_value - input_sec->output_offset;
-  if (!info->relocatable)
+  if (!bfd_link_relocatable (info))
     value -= input_sec->output_section->vma;
 
   adjust = opd->adjust[OPD_NDX (value)];
     value -= input_sec->output_section->vma;
 
   adjust = opd->adjust[OPD_NDX (value)];
@@ -14923,7 +15418,7 @@ static bfd_boolean
 ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h,
 ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h,
-                                Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
+                                Elf_Internal_Sym *sym)
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
@@ -14960,6 +15455,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
            loc = (htab->elf.irelplt->contents
                   + (htab->elf.irelplt->reloc_count++
                      * sizeof (Elf64_External_Rela)));
            loc = (htab->elf.irelplt->contents
                   + (htab->elf.irelplt->reloc_count++
                      * sizeof (Elf64_External_Rela)));
+           htab->local_ifunc_resolver = 1;
          }
        else
          {
          }
        else
          {
@@ -14971,6 +15467,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
            loc = (htab->elf.srelplt->contents
                   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
                      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
            loc = (htab->elf.srelplt->contents
                   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
                      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+             htab->maybe_local_ifunc_resolver = 1;
          }
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
          }
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
 
@@ -15002,11 +15500,13 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
+      asection *srel;
 
       if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
              && h->root.type != bfd_link_hash_defweak)
 
       if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
              && h->root.type != bfd_link_hash_defweak)
-         || htab->relbss == NULL)
+         || htab->elf.srelbss == NULL
+         || htab->elf.sreldynrelro == NULL)
        abort ();
 
       rela.r_offset = (h->root.u.def.value
        abort ();
 
       rela.r_offset = (h->root.u.def.value
@@ -15014,8 +15514,12 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                       + h->root.u.def.section->output_offset);
       rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
       rela.r_addend = 0;
                       + h->root.u.def.section->output_offset);
       rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
       rela.r_addend = 0;
-      loc = htab->relbss->contents;
-      loc += htab->relbss->reloc_count++ * sizeof (Elf64_External_Rela);
+      if (h->root.u.def.section == htab->elf.sdynrelro)
+       srel = htab->elf.sreldynrelro;
+      else
+       srel = htab->elf.srelbss;
+      loc = srel->contents;
+      loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
@@ -15131,33 +15635,24 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
              dyn.d_un.d_val = htab->elf.srelplt->size;
              break;
 
              dyn.d_un.d_val = htab->elf.srelplt->size;
              break;
 
-           case DT_RELASZ:
-             /* Don't count procedure linkage table relocs in the
-                overall reloc count.  */
-             s = htab->elf.srelplt;
-             if (s == NULL)
-               continue;
-             dyn.d_un.d_val -= s->size;
-             break;
-
-           case DT_RELA:
-             /* We may not be using the standard ELF linker script.
-                If .rela.plt is the first .rela section, we adjust
-                DT_RELA to not include it.  */
-             s = htab->elf.srelplt;
-             if (s == NULL)
-               continue;
-             if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset)
-               continue;
-             dyn.d_un.d_ptr += s->size;
-             break;
+           case DT_TEXTREL:
+             if (htab->local_ifunc_resolver)
+               info->callbacks->einfo
+                 (_("%X%P: text relocations and GNU indirect "
+                    "functions will result in a segfault at runtime\n"));
+             else if (htab->maybe_local_ifunc_resolver)
+               info->callbacks->einfo
+                 (_("%P: warning: text relocations and GNU indirect "
+                    "functions may result in a segfault at runtime\n"));
+             continue;
            }
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
     }
 
            }
 
          bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
     }
 
-  if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0)
+  if (htab->elf.sgot != NULL && htab->elf.sgot->size != 0
+      && htab->elf.sgot->output_section != bfd_abs_section_ptr)
     {
       /* Fill in the first entry in the global offset table.
         We use it to hold the link-time TOCbase.  */
     {
       /* Fill in the first entry in the global offset table.
         We use it to hold the link-time TOCbase.  */
@@ -15169,7 +15664,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
       elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8;
     }
 
       elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 8;
     }
 
-  if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
+  if (htab->elf.splt != NULL && htab->elf.splt->size != 0
+      && htab->elf.splt->output_section != bfd_abs_section_ptr)
     {
       /* Set .plt entry size.  */
       elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize
     {
       /* Set .plt entry size.  */
       elf_section_data (htab->elf.splt->output_section)->this_hdr.sh_entsize
@@ -15202,8 +15698,10 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
       bfd_vma val;
       bfd_byte *p;
       asection *stub_sec;
       bfd_vma val;
       bfd_byte *p;
       asection *stub_sec;
+      size_t align = 4;
 
 
-      p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie);
+      p = htab->glink_eh_frame->contents;
+      p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
       for (stub_sec = htab->params->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
@@ -15233,7 +15731,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
            /* Augmentation.  */
            p += 1;
            /* Pad.  */
            /* Augmentation.  */
            p += 1;
            /* Pad.  */
-           p += 7;
+           p += ((17 + align - 1) & -align) - 17;
          }
       if (htab->glink != NULL && htab->glink->size != 0)
        {
          }
       if (htab->glink != NULL && htab->glink->size != 0)
        {
@@ -15263,6 +15761,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
          p += 1;
          /* Ops.  */
          p += 7;
          p += 1;
          /* Ops.  */
          p += 7;
+         p += ((24 + align - 1) & -align) - 24;
        }
 
       if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
        }
 
       if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
This page took 0.112533 seconds and 4 git commands to generate.