PowerPC, use size_t rather than long for indices
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index a795ad1578d237be13584c3ca0530c6b0524e2b7..e475421951f24b430d278abfb9892c891af3760d 100644 (file)
@@ -35,6 +35,9 @@
 #include "elf64-ppc.h"
 #include "dwarf2.h"
 
+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
 static bfd_reloc_status_type ppc64_elf_ha_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type ppc64_elf_branch_reloc
@@ -51,6 +54,8 @@ static bfd_reloc_status_type ppc64_elf_toc_ha_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type ppc64_elf_toc64_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type ppc64_elf_prefix_reloc
+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type ppc64_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_vma opd_entry_value
@@ -185,18 +190,25 @@ static bfd_vma opd_entry_value
 #define LD_R2_0R12     0xe84c0000      /* ld    %r2,0(%r12)     */
 #define ADD_R2_R2_R12  0x7c426214      /* add   %r2,%r2,%r12    */
 
+#define LI_R11_0       0x39600000      /* li    %r11,0         */
 #define LIS_R2         0x3c400000      /* lis %r2,xxx@ha         */
+#define LIS_R11                0x3d600000      /* lis %r11,xxx@ha        */
 #define LIS_R12                0x3d800000      /* lis %r12,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_R11  0x3d8b0000      /* addis %r12,%r11,xxx@ha */
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,xxx@ha */
 #define ORIS_R12_R12_0 0x658c0000      /* oris  %r12,%r12,xxx@hi */
+#define ORI_R11_R11_0  0x616b0000      /* ori   %r11,%r11,xxx@l  */
 #define ORI_R12_R12_0  0x618c0000      /* ori   %r12,%r12,xxx@l  */
 #define LD_R12_0R12    0xe98c0000      /* ld    %r12,xxx@l(%r12) */
+#define SLDI_R11_R11_34        0x796b1746      /* sldi  %r11,%r11,34     */
 #define SLDI_R12_R12_32        0x799c07c6      /* sldi  %r12,%r12,32     */
 #define LDX_R12_R11_R12 0x7d8b602a     /* ldx   %r12,%r11,%r12   */
 #define ADD_R12_R11_R12 0x7d8b6214     /* add   %r12,%r11,%r12   */
+#define PADDI_R12_PC   0x0610000039800000ULL
+#define PLD_R12_PC     0x04100000e5800000ULL
+#define PNOP           0x0700000000000000ULL
 
 /* __glink_PLTresolve stub instructions.  We enter with the index in R0.  */
 #define GLINK_PLTRESOLVE_SIZE(htab)                    \
@@ -878,6 +890,87 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
   HOW (R_PPC64_ADDR64_LOCAL, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
        bfd_elf_generic_reloc),
 
+  HOW (R_PPC64_PLTSEQ_NOTOC, 2, 32, 0, 0, FALSE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_PLTCALL_NOTOC, 2, 32, 0, 0, FALSE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_PCREL_OPT, 2, 32, 0, 0, FALSE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_D34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_D34_LO, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, dont,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_D34_HI30, 4, 34, 0x3ffff0000ffffULL, 34, FALSE, dont,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_D34_HA30, 4, 34, 0x3ffff0000ffffULL, 34, FALSE, dont,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_GOT_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_PLT_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_PLT_PCREL34_NOTOC, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_GOT_TLSGD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_unhandled_reloc),
+
+  HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_ADDR16_HIGHERA34, 1, 16, 0xffff, 34, FALSE, dont,
+       ppc64_elf_ha_reloc),
+
+  HOW (R_PPC64_ADDR16_HIGHEST34, 1, 16, 0xffff, 50, FALSE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_ADDR16_HIGHESTA34, 1, 16, 0xffff, 50, FALSE, dont,
+       ppc64_elf_ha_reloc),
+
+  HOW (R_PPC64_REL16_HIGHER34, 1, 16, 0xffff, 34, TRUE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_REL16_HIGHERA34, 1, 16, 0xffff, 34, TRUE, dont,
+       ppc64_elf_ha_reloc),
+
+  HOW (R_PPC64_REL16_HIGHEST34, 1, 16, 0xffff, 50, TRUE, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC64_REL16_HIGHESTA34, 1, 16, 0xffff, 50, TRUE, dont,
+       ppc64_elf_ha_reloc),
+
+  HOW (R_PPC64_D28, 4, 28, 0xfff0000ffffULL, 0, FALSE, signed,
+       ppc64_elf_prefix_reloc),
+
+  HOW (R_PPC64_PCREL28, 4, 28, 0xfff0000ffffULL, 0, TRUE, signed,
+       ppc64_elf_prefix_reloc),
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOW (R_PPC64_GNU_VTINHERIT, 0, 0, 0, 0, FALSE, dont,
        NULL),
@@ -1047,6 +1140,7 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
       break;
     case BFD_RELOC_PPC64_PLTGOT16_LO_DS:       r = R_PPC64_PLTGOT16_LO_DS;
       break;
+    case BFD_RELOC_PPC64_TLS_PCREL:
     case BFD_RELOC_PPC_TLS:                    r = R_PPC64_TLS;
       break;
     case BFD_RELOC_PPC_TLSGD:                  r = R_PPC64_TLSGD;
@@ -1167,6 +1261,52 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
       break;
     case BFD_RELOC_PPC64_ADDR64_LOCAL:         r = R_PPC64_ADDR64_LOCAL;
       break;
+    case BFD_RELOC_PPC64_D34:                  r = R_PPC64_D34;
+      break;
+    case BFD_RELOC_PPC64_D34_LO:               r = R_PPC64_D34_LO;
+      break;
+    case BFD_RELOC_PPC64_D34_HI30:             r = R_PPC64_D34_HI30;
+      break;
+    case BFD_RELOC_PPC64_D34_HA30:             r = R_PPC64_D34_HA30;
+      break;
+    case BFD_RELOC_PPC64_PCREL34:              r = R_PPC64_PCREL34;
+      break;
+    case BFD_RELOC_PPC64_GOT_PCREL34:          r = R_PPC64_GOT_PCREL34;
+      break;
+    case BFD_RELOC_PPC64_PLT_PCREL34:          r = R_PPC64_PLT_PCREL34;
+      break;
+    case BFD_RELOC_PPC64_TPREL34:              r = R_PPC64_TPREL34;
+      break;
+    case BFD_RELOC_PPC64_DTPREL34:             r = R_PPC64_DTPREL34;
+      break;
+    case BFD_RELOC_PPC64_GOT_TLSGD34:          r = R_PPC64_GOT_TLSGD34;
+      break;
+    case BFD_RELOC_PPC64_GOT_TLSLD34:          r = R_PPC64_GOT_TLSLD34;
+      break;
+    case BFD_RELOC_PPC64_GOT_TPREL34:          r = R_PPC64_GOT_TPREL34;
+      break;
+    case BFD_RELOC_PPC64_GOT_DTPREL34:         r = R_PPC64_GOT_DTPREL34;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_HIGHER34:      r = R_PPC64_ADDR16_HIGHER34;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_HIGHERA34:     r = R_PPC64_ADDR16_HIGHERA34;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_HIGHEST34:     r = R_PPC64_ADDR16_HIGHEST34;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_HIGHESTA34:    r = R_PPC64_ADDR16_HIGHESTA34;
+      break;
+    case BFD_RELOC_PPC64_REL16_HIGHER34:       r = R_PPC64_REL16_HIGHER34;
+      break;
+    case BFD_RELOC_PPC64_REL16_HIGHERA34:      r = R_PPC64_REL16_HIGHERA34;
+      break;
+    case BFD_RELOC_PPC64_REL16_HIGHEST34:      r = R_PPC64_REL16_HIGHEST34;
+      break;
+    case BFD_RELOC_PPC64_REL16_HIGHESTA34:     r = R_PPC64_REL16_HIGHESTA34;
+      break;
+    case BFD_RELOC_PPC64_D28:                  r = R_PPC64_D28;
+      break;
+    case BFD_RELOC_PPC64_PCREL28:              r = R_PPC64_PCREL28;
+      break;
     case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
       break;
     case BFD_RELOC_VTABLE_ENTRY:               r = R_PPC64_GNU_VTENTRY;
@@ -1243,11 +1383,17 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                  input_section, output_bfd, error_message);
 
-  /* Adjust the addend for sign extension of the low 16 bits.
-     We won't actually be using the low 16 bits, so trashing them
+  /* Adjust the addend for sign extension of the low 16 (or 34) bits.
+     We won't actually be using the low bits, so trashing them
      doesn't matter.  */
-  reloc_entry->addend += 0x8000;
   r_type = reloc_entry->howto->type;
+  if (r_type == R_PPC64_ADDR16_HIGHERA34
+      || r_type == R_PPC64_ADDR16_HIGHESTA34
+      || r_type == R_PPC64_REL16_HIGHERA34
+      || r_type == R_PPC64_REL16_HIGHESTA34)
+    reloc_entry->addend += 1ULL << 33;
+  else
+    reloc_entry->addend += 1U << 15;
   if (r_type != R_PPC64_REL16DX_HA)
     return bfd_reloc_continue;
 
@@ -1262,7 +1408,7 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
            + input_section->output_section->vma);
   value = (bfd_signed_vma) value >> 16;
 
-  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn &= ~0x1fffc1;
   insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
@@ -1337,7 +1483,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                  input_section, output_bfd, error_message);
 
-  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn &= ~(0x01 << 21);
   r_type = reloc_entry->howto->type;
@@ -1487,11 +1633,53 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   if (TOCstart == 0)
     TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
 
-  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
   bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
   return bfd_reloc_ok;
 }
 
+static bfd_reloc_status_type
+ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+                       void *data, asection *input_section,
+                       bfd *output_bfd, char **error_message)
+{
+  uint64_t insn;
+  bfd_vma targ;
+
+  if (output_bfd != NULL)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+  insn <<= 32;
+  insn |= bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address + 4);
+
+  targ = (symbol->section->output_section->vma
+         + symbol->section->output_offset
+         + reloc_entry->addend);
+  if (!bfd_is_com_section (symbol->section))
+    targ += symbol->value;
+  if (reloc_entry->howto->type == R_PPC64_D34_HA30)
+    targ += 1ULL << 33;
+  if (reloc_entry->howto->pc_relative)
+    {
+      bfd_vma from = (reloc_entry->address
+                     + input_section->output_offset
+                     + input_section->output_section->vma);
+      targ -=from;
+    }
+  targ >>= reloc_entry->howto->rightshift;
+  insn &= ~reloc_entry->howto->dst_mask;
+  insn |= ((targ << 16) | (targ & 0xffff)) & reloc_entry->howto->dst_mask;
+  bfd_put_32 (abfd, insn >> 32, (bfd_byte *) data + reloc_entry->address);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address + 4);
+  if (reloc_entry->howto->complain_on_overflow == complain_overflow_signed
+      && (targ + (1ULL << (reloc_entry->howto->bitsize - 1))
+         >= 1ULL << reloc_entry->howto->bitsize))
+    return bfd_reloc_overflow;
+  return bfd_reloc_ok;
+}
+
 static bfd_reloc_status_type
 ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                           void *data, asection *input_section,
@@ -1594,6 +1782,10 @@ struct ppc64_elf_obj_tdata
   /* Set if toc/got ha relocs detected not using r2, or lo reloc
      instruction not one we handle.  */
   unsigned int unexpected_toc_insn : 1;
+
+  /* Set if PLT/GOT/TOC relocs that can be optimised are present in
+     this file.  */
+  unsigned int has_optrel : 1;
 };
 
 #define ppc64_elf_tdata(bfd) \
@@ -1793,6 +1985,10 @@ struct _ppc64_elf_section_data
 
   /* Flag set when PLTCALL relocs are detected.  */
   unsigned int has_pltcall:1;
+
+  /* Flag set when section has PLT/GOT/TOC relocations that can be
+     optimised.  */
+  unsigned int has_optrel:1;
 };
 
 #define ppc64_elf_section_data(sec) \
@@ -1908,15 +2104,26 @@ compare_symbols (const void *ap, const void *bp)
   if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
     return 1;
 
-  return a > b;
+  /* Finally, sort on where the symbol is in memory.  The symbols will
+     be in at most two malloc'd blocks, one for static syms, one for
+     dynamic syms, and we distinguish the two blocks above by testing
+     BSF_DYNAMIC.  Since we are sorting the symbol pointers which were
+     originally in the same order as the symbols (and we're not
+     sorting the symbols themselves), this ensures a stable sort.  */
+  if (a < b)
+    return -1;
+  if (a > b)
+    return 1;
+  return 0;
 }
 
 /* Search SYMS for a symbol of the given VALUE.  */
 
 static asymbol *
-sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value)
+sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id,
+              bfd_vma value)
 {
-  long mid;
+  size_t mid;
 
   if (id == (unsigned) -1)
     {
@@ -2552,6 +2759,12 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC64_REL32:
     case R_PPC64_REL64:
     case R_PPC64_REL30:
+    case R_PPC64_TOC16:
+    case R_PPC64_TOC16_DS:
+    case R_PPC64_TOC16_LO:
+    case R_PPC64_TOC16_HI:
+    case R_PPC64_TOC16_HA:
+    case R_PPC64_TOC16_LO_DS:
       return 0;
 
     case R_PPC64_TPREL16:
@@ -2567,6 +2780,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_TPREL34:
       /* These relocations are relative but in a shared library the
         linker doesn't know the thread pointer base.  */
       return bfd_link_dll (info);
@@ -2687,8 +2901,34 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    .   mtctr   %r12
    .   bctr
 
+   There are also ELFv1 powerxx variants of these stubs.
+   ppc_stub_long_branch_notoc:
+   .   pla     %r12,dest@pcrel
+   .   b       dest
+   ppc_stub_plt_branch_notoc:
+   .   lis     %r11,(dest-1f)@highesta34
+   .   ori     %r11,%r11,(dest-1f)@highera34
+   .   sldi    %r11,%r11,34
+   . 1: pla    %r12,dest@pcrel
+   .   add     %r12,%r11,%r12
+   .   mtctr   %r12
+   .   bctr
+   ppc_stub_plt_call_notoc:
+   .   lis     %r11,(xxx-1f)@highesta34
+   .   ori     %r11,%r11,(xxx-1f)@highera34
+   .   sldi    %r11,%r11,34
+   . 1: pla    %r12,xxx@pcrel
+   .   ldx     %r12,%r11,%r12
+   .   mtctr   %r12
+   .   bctr
+
    In cases where the high instructions would add zero, they are
    omitted and following instructions modified in some cases.
+   For example, a powerxx ppc_stub_plt_call_notoc might simplify down
+   to
+   .   pld     %r12,xxx@pcrel
+   .   mtctr   %r12
+   .   bctr
 
    For a given stub group (a set of sections all using the same toc
    pointer value) there will be just one stub type used for any
@@ -2853,9 +3093,7 @@ struct ppc_link_hash_entry
      of the other TLS bits are set.  tls_optimize clears bits when
      optimizing to indicate the corresponding GOT entry type is not
      needed.  If set, TLS_TLS is never cleared.  tls_optimize may also
-     set TLS_TPRELGD when a GD reloc turns into a TPREL one.  We use a
-     separate flag rather than setting TPREL just for convenience in
-     distinguishing the two cases.
+     set TLS_GDIE when a GD reloc turns into an IE one.
      These flags are also kept for local symbols.  */
 #define TLS_TLS                 1      /* Any TLS reloc.  */
 #define TLS_GD          2      /* GD reloc. */
@@ -2863,8 +3101,8 @@ struct ppc_link_hash_entry
 #define TLS_TPREL       8      /* TPREL reloc, => IE. */
 #define TLS_DTPREL     16      /* DTPREL reloc, => LD. */
 #define TLS_MARK       32      /* __tls_get_addr call marked. */
-#define TLS_TPRELGD    64      /* TPREL reloc resulting from GD->IE. */
-#define TLS_EXPLICIT   128     /* Marks TOC section TLS relocs. */
+#define TLS_GDIE       64      /* GOT TPREL reloc resulting from GD->IE. */
+#define TLS_EXPLICIT   256     /* TOC section TLS reloc, not stored. */
   unsigned char tls_mask;
 
   /* The above field is also used to mark function symbols.  In which
@@ -2975,6 +3213,12 @@ struct ppc_link_hash_table
   /* Whether plt calls for ELFv2 localentry:0 funcs have been optimized.  */
   unsigned int has_plt_localentry0:1;
 
+  /* Whether calls are made via the PLT from NOTOC functions.  */
+  unsigned int notoc_plt:1;
+
+  /* Whether to use powerxx instructions in linkage stubs.  */
+  unsigned int powerxx_stubs:1;
+
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
@@ -2988,8 +3232,9 @@ struct ppc_link_hash_table
 /* Nonzero if this section has TLS related relocations.  */
 #define has_tls_reloc sec_flg0
 
-/* Nonzero if this section has an old-style call to __tls_get_addr.  */
-#define has_tls_get_addr_call sec_flg1
+/* Nonzero if this section has a call to __tls_get_addr lacking marker
+   relocations.  */
+#define nomark_tls_get_addr sec_flg1
 
 /* Nonzero if this section has any toc or got relocs.  */
 #define has_toc_reloc sec_flg2
@@ -3257,7 +3502,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
                                                       flags);
       if (htab->sfpr == NULL
-         || !bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+         || !bfd_set_section_alignment (htab->sfpr, 2))
        return FALSE;
     }
 
@@ -3268,7 +3513,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
                                                    flags);
   if (htab->glink == NULL
-      || !bfd_set_section_alignment (dynobj, htab->glink, 3))
+      || !bfd_set_section_alignment (htab->glink, 3))
     return FALSE;
 
   /* The part of .glink used by global entry stubs, separate so that
@@ -3276,7 +3521,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink",
                                                           flags);
   if (htab->global_entry == NULL
-      || !bfd_set_section_alignment (dynobj, htab->global_entry, 2))
+      || !bfd_set_section_alignment (htab->global_entry, 2))
     return FALSE;
 
   if (!info->no_ld_generated_unwind_info)
@@ -3287,14 +3532,14 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                                 ".eh_frame",
                                                                 flags);
       if (htab->glink_eh_frame == NULL
-         || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
+         || !bfd_set_section_alignment (htab->glink_eh_frame, 2))
        return FALSE;
     }
 
   flags = SEC_ALLOC | SEC_LINKER_CREATED;
   htab->elf.iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
   if (htab->elf.iplt == NULL
-      || !bfd_set_section_alignment (dynobj, htab->elf.iplt, 3))
+      || !bfd_set_section_alignment (htab->elf.iplt, 3))
     return FALSE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
@@ -3302,7 +3547,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->elf.irelplt
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags);
   if (htab->elf.irelplt == NULL
-      || !bfd_set_section_alignment (dynobj, htab->elf.irelplt, 3))
+      || !bfd_set_section_alignment (htab->elf.irelplt, 3))
     return FALSE;
 
   /* Create branch lookup table for plt_branch stubs.  */
@@ -3311,7 +3556,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
                                                   flags);
   if (htab->brlt == NULL
-      || !bfd_set_section_alignment (dynobj, htab->brlt, 3))
+      || !bfd_set_section_alignment (htab->brlt, 3))
     return FALSE;
 
   /* Local plt entries, put in .branch_lt but a separate section for
@@ -3319,7 +3564,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
                                                       flags);
   if (htab->pltlocal == NULL
-      || !bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+      || !bfd_set_section_alignment (htab->pltlocal, 3))
     return FALSE;
 
   if (!bfd_link_pic (info))
@@ -3330,13 +3575,13 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->relbrlt
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relbrlt == NULL
-      || !bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+      || !bfd_set_section_alignment (htab->relbrlt, 3))
     return FALSE;
 
   htab->relpltlocal
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relpltlocal == NULL
-      || !bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+      || !bfd_set_section_alignment (htab->relpltlocal, 3))
     return FALSE;
 
   return TRUE;
@@ -3532,13 +3777,13 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
   if (!got
-      || !bfd_set_section_alignment (abfd, got, 3))
+      || !bfd_set_section_alignment (got, 3))
     return FALSE;
 
   relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
                                               flags | SEC_READONLY);
   if (!relgot
-      || !bfd_set_section_alignment (abfd, relgot, 3))
+      || !bfd_set_section_alignment (relgot, 3))
     return FALSE;
 
   ppc64_elf_tdata (abfd)->got = got;
@@ -4229,7 +4474,8 @@ is_branch_reloc (enum elf_ppc64_reloc_type r_type)
          || r_type == R_PPC64_ADDR14
          || r_type == R_PPC64_ADDR14_BRTAKEN
          || r_type == R_PPC64_ADDR14_BRNTAKEN
-         || r_type == R_PPC64_PLTCALL);
+         || r_type == R_PPC64_PLTCALL
+         || r_type == R_PPC64_PLTCALL_NOTOC);
 }
 
 /* Relocs on inline plt call sequence insns prior to the call.  */
@@ -4241,7 +4487,10 @@ is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
          || r_type == R_PPC64_PLT16_HI
          || r_type == R_PPC64_PLT16_LO
          || r_type == R_PPC64_PLT16_LO_DS
-         || r_type == R_PPC64_PLTSEQ);
+         || r_type == R_PPC64_PLT_PCREL34
+         || r_type == R_PPC64_PLT_PCREL34_NOTOC
+         || r_type == R_PPC64_PLTSEQ
+         || r_type == R_PPC64_PLTSEQ_NOTOC);
 }
 
 /* Look through the relocs for a section during the first phase, and
@@ -4309,7 +4558,58 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            sec->has_toc_reloc = 1;
        }
 
-      tls_type = 0;
+      r_type = ELF64_R_TYPE (rel->r_info);
+      switch (r_type)
+       {
+       case R_PPC64_D34:
+       case R_PPC64_D34_LO:
+       case R_PPC64_D34_HI30:
+       case R_PPC64_D34_HA30:
+       case R_PPC64_D28:
+       case R_PPC64_TPREL34:
+       case R_PPC64_DTPREL34:
+       case R_PPC64_PCREL34:
+       case R_PPC64_GOT_PCREL34:
+       case R_PPC64_GOT_TLSGD34:
+       case R_PPC64_GOT_TLSLD34:
+       case R_PPC64_GOT_TPREL34:
+       case R_PPC64_GOT_DTPREL34:
+       case R_PPC64_PLT_PCREL34:
+       case R_PPC64_PLT_PCREL34_NOTOC:
+       case R_PPC64_PCREL28:
+         htab->powerxx_stubs = 1;
+         break;
+       default:
+         break;
+       }
+
+      switch (r_type)
+       {
+       case R_PPC64_PLT16_HA:
+       case R_PPC64_GOT_TLSLD16_HA:
+       case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TPREL16_HA:
+       case R_PPC64_GOT_DTPREL16_HA:
+       case R_PPC64_GOT16_HA:
+       case R_PPC64_TOC16_HA:
+       case R_PPC64_PLT16_LO:
+       case R_PPC64_PLT16_LO_DS:
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_GOT16_LO:
+       case R_PPC64_GOT16_LO_DS:
+       case R_PPC64_TOC16_LO:
+       case R_PPC64_TOC16_LO_DS:
+       case R_PPC64_GOT_PCREL34:
+         ppc64_elf_tdata (abfd)->has_optrel = 1;
+         ppc64_elf_section_data (sec)->has_optrel = 1;
+         break;
+       default:
+         break;
+       }
+
       ifunc = NULL;
       if (h != NULL)
        {
@@ -4336,7 +4636,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            }
        }
 
-      r_type = ELF64_R_TYPE (rel->r_info);
+      tls_type = 0;
       switch (r_type)
        {
        case R_PPC64_TLSGD:
@@ -4357,6 +4657,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
        case R_PPC64_GOT_TLSLD16_HA:
+       case R_PPC64_GOT_TLSLD34:
          tls_type = TLS_TLS | TLS_LD;
          goto dogottls;
 
@@ -4364,6 +4665,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT_TLSGD16_LO:
        case R_PPC64_GOT_TLSGD16_HI:
        case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TLSGD34:
          tls_type = TLS_TLS | TLS_GD;
          goto dogottls;
 
@@ -4371,6 +4673,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_TPREL34:
          if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
@@ -4380,17 +4683,20 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT_DTPREL16_LO_DS:
        case R_PPC64_GOT_DTPREL16_HI:
        case R_PPC64_GOT_DTPREL16_HA:
+       case R_PPC64_GOT_DTPREL34:
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
-         /* Fall through */
+         goto dogot;
 
        case R_PPC64_GOT16:
-       case R_PPC64_GOT16_DS:
-       case R_PPC64_GOT16_HA:
-       case R_PPC64_GOT16_HI:
        case R_PPC64_GOT16_LO:
+       case R_PPC64_GOT16_HI:
+       case R_PPC64_GOT16_HA:
+       case R_PPC64_GOT16_DS:
        case R_PPC64_GOT16_LO_DS:
+       case R_PPC64_GOT_PCREL34:
+       dogot:
          /* This symbol requires a global offset table entry.  */
          sec->has_toc_reloc = 1;
          if (r_type == R_PPC64_GOT_TLSLD16
@@ -4455,6 +4761,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_PLT16_HI:
        case R_PPC64_PLT16_LO:
        case R_PPC64_PLT16_LO_DS:
+       case R_PPC64_PLT_PCREL34:
+       case R_PPC64_PLT_PCREL34_NOTOC:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
          /* This symbol requires a procedure linkage table entry.  */
@@ -4510,6 +4818,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_REL16_HIGHERA:
        case R_PPC64_REL16_HIGHEST:
        case R_PPC64_REL16_HIGHESTA:
+       case R_PPC64_REL16_HIGHER34:
+       case R_PPC64_REL16_HIGHERA34:
+       case R_PPC64_REL16_HIGHEST34:
+       case R_PPC64_REL16_HIGHESTA34:
        case R_PPC64_REL16DX_HA:
          break;
 
@@ -4539,6 +4851,16 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TOC16_HA:
        case R_PPC64_TOC16_LO_DS:
          sec->has_toc_reloc = 1;
+         if (h != NULL && bfd_link_executable (info))
+           {
+             /* We may need a copy reloc.  */
+             h->non_got_ref = 1;
+             /* Strongly prefer a copy reloc over a dynamic reloc.
+                glibc ld.so as of 2019-08 will error out if one of
+                these relocations is emitted.  */
+             h->needs_copy = 1;
+             goto dodyn;
+           }
          break;
 
          /* Marker reloc.  */
@@ -4592,6 +4914,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          goto rel24;
 
        case R_PPC64_PLTCALL:
+       case R_PPC64_PLTCALL_NOTOC:
          ppc64_elf_section_data (sec)->has_pltcall = 1;
          /* Fall through.  */
 
@@ -4617,7 +4940,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    ;
                  else
                    /* Mark this section as having an old-style call.  */
-                   sec->has_tls_get_addr_call = 1;
+                   sec->nomark_tls_get_addr = 1;
                }
              plt_list = &h->plt.plist;
            }
@@ -4665,7 +4988,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            {
              struct ppc_link_hash_entry *eh;
              eh = (struct ppc_link_hash_entry *) h;
-             eh->tls_mask |= tls_type;
+             eh->tls_mask |= tls_type & 0xff;
            }
          else
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
@@ -4713,6 +5036,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_TPREL34:
          if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
@@ -4739,12 +5063,21 @@ 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_D34:
+       case R_PPC64_D34_LO:
+       case R_PPC64_D34_HI30:
+       case R_PPC64_D34_HA30:
+       case R_PPC64_ADDR16_HIGHER34:
+       case R_PPC64_ADDR16_HIGHERA34:
+       case R_PPC64_ADDR16_HIGHEST34:
+       case R_PPC64_ADDR16_HIGHESTA34:
+       case R_PPC64_D28:
          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
                 function in a shared lib.  */
-             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
+             if (!update_plt_info (abfd, &h->plt.plist, 0))
                return FALSE;
              h->pointer_equality_needed = 1;
            }
@@ -4758,7 +5091,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_UADDR32:
        case R_PPC64_UADDR64:
        case R_PPC64_TOC:
-         if (h != NULL && !bfd_link_pic (info))
+         if (h != NULL && bfd_link_executable (info))
            /* We may need a copy reloc.  */
            h->non_got_ref = 1;
 
@@ -4788,17 +5121,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
        dodyn:
-         if ((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
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular))
+         if ((h != NULL
+              && (h->root.type == bfd_link_hash_defweak
+                  || !h->def_regular))
+             || (h != NULL
+                 && !bfd_link_executable (info)
+                 && !SYMBOLIC_BIND (info, h))
+             || (bfd_link_pic (info)
+                 && must_be_dyn_reloc (info, r_type))
              || (!bfd_link_pic (info)
                  && ifunc != NULL))
            {
@@ -5511,9 +5841,7 @@ sfpr_define (struct bfd_link_info *info,
              s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE);
              if (s == NULL)
                return FALSE;
-             if (s->root.type == bfd_link_hash_new
-                 || (s->root.type = bfd_link_hash_defined
-                     && s->root.u.def.section == stub_sec))
+             if (s->root.type == bfd_link_hash_new)
                {
                  s->root.type = bfd_link_hash_defined;
                  s->root.u.def.section = stub_sec;
@@ -6107,7 +6435,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (bfd_link_pic (info))
+  if (!bfd_link_executable (info))
     return TRUE;
 
   /* If there are no references to this symbol that do not use the
@@ -6123,7 +6451,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
       /* If we don'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))
+      || (ELIMINATE_COPY_RELOCS
+         && !h->needs_copy
+         && !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
@@ -6511,6 +6841,16 @@ dec_dynrel_count (bfd_vma r_info,
     default:
       return TRUE;
 
+    case R_PPC64_TOC16:
+    case R_PPC64_TOC16_DS:
+    case R_PPC64_TOC16_LO:
+    case R_PPC64_TOC16_HI:
+    case R_PPC64_TOC16_HA:
+    case R_PPC64_TOC16_LO_DS:
+      if (h == NULL)
+       return TRUE;
+      break;
+
     case R_PPC64_TPREL16:
     case R_PPC64_TPREL16_LO:
     case R_PPC64_TPREL16_HI:
@@ -6524,6 +6864,7 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_TPREL16_HIGHEST:
     case R_PPC64_TPREL16_HIGHESTA:
     case R_PPC64_TPREL64:
+    case R_PPC64_TPREL34:
     case R_PPC64_DTPMOD64:
     case R_PPC64_DTPREL64:
     case R_PPC64_ADDR64:
@@ -6551,6 +6892,15 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_UADDR32:
     case R_PPC64_UADDR64:
     case R_PPC64_TOC:
+    case R_PPC64_D34:
+    case R_PPC64_D34_LO:
+    case R_PPC64_D34_HI30:
+    case R_PPC64_D34_HA30:
+    case R_PPC64_ADDR16_HIGHER34:
+    case R_PPC64_ADDR16_HIGHERA34:
+    case R_PPC64_ADDR16_HIGHEST34:
+    case R_PPC64_ADDR16_HIGHESTA34:
+    case R_PPC64_D28:
       break;
     }
 
@@ -6564,17 +6914,18 @@ dec_dynrel_count (bfd_vma r_info,
        return FALSE;
     }
 
-  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
-         && !bfd_link_pic (info)
-         && h != NULL
-         && (h->root.type == bfd_link_hash_defweak
-             || !h->def_regular)))
+  if ((h != NULL
+       && (h->root.type == bfd_link_hash_defweak
+          || !h->def_regular))
+      || (h != NULL
+         && !bfd_link_executable (info)
+         && !SYMBOLIC_BIND (info, h))
+      || (bfd_link_pic (info)
+         && must_be_dyn_reloc (info, r_type))
+      || (!bfd_link_pic (info)
+         && (h != NULL
+             ? h->type == STT_GNU_IFUNC
+             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
     ;
   else
     return TRUE;
@@ -7156,7 +7507,8 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
                unsigned char *tls_maskp;
 
                r_type = ELF64_R_TYPE (rel->r_info);
-               if (r_type != R_PPC64_PLTCALL)
+               if (r_type != R_PPC64_PLTCALL
+                   && r_type != R_PPC64_PLTCALL_NOTOC)
                  continue;
 
                r_symndx = ELF64_R_SYM (rel->r_info);
@@ -7184,7 +7536,11 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
                    from = (rel->r_offset
                            + sec->output_offset
                            + sec->output_section->vma);
-                   if (to - from + limit < 2 * limit)
+                   if (to - from + limit < 2 * limit
+                       && !(r_type == R_PPC64_PLTCALL_NOTOC
+                            && (((h ? h->other : sym->st_other)
+                                 & STO_PPC64_LOCAL_MASK)
+                                > 1 << STO_PPC64_LOCAL_BIT)))
                      *tls_maskp &= ~PLT_KEEP;
                  }
              }
@@ -7418,7 +7774,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                  Elf_Internal_Sym *sym;
                  asection *sym_sec;
                  unsigned char *tls_mask;
-                 unsigned char tls_set, tls_clear, tls_type = 0;
+                 unsigned int tls_set, tls_clear, tls_type = 0;
                  bfd_vma value;
                  bfd_boolean ok_tprel, is_local;
                  long toc_ref_index = 0;
@@ -7460,11 +7816,9 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    value = sym->st_value;
 
                  ok_tprel = FALSE;
-                 is_local = FALSE;
-                 if (h == NULL
-                     || !h->def_dynamic)
+                 is_local = SYMBOL_REFERENCES_LOCAL (info, h);
+                 if (is_local)
                    {
-                     is_local = TRUE;
                      if (h != NULL
                          && h->root.type == bfd_link_hash_undefweak)
                        ok_tprel = TRUE;
@@ -7473,9 +7827,14 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                        {
                          value += sym_sec->output_offset;
                          value += sym_sec->output_section->vma;
-                         value -= htab->elf.tls_sec->vma;
-                         ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
-                                     < (bfd_vma) 1 << 32);
+                         value -= htab->elf.tls_sec->vma + TP_OFFSET;
+                         /* Note that even though the prefix insns
+                            allow a 1<<33 offset we use the same test
+                            as for addis;addi.  There may be a mix of
+                            pcrel and non-pcrel code and the decision
+                            to optimise is per symbol, not per TLS
+                            sequence.  */
+                         ok_tprel = value + 0x80008000ULL < 1ULL << 32;
                        }
                    }
 
@@ -7487,7 +7846,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                     setup insn.  If we don't find matching arg setup
                     relocs, don't do any tls optimization.  */
                  if (pass == 0
-                     && sec->has_tls_get_addr_call
+                     && sec->nomark_tls_get_addr
                      && h != NULL
                      && (h == &htab->tls_get_addr->elf
                          || h == &htab->tls_get_addr_fd->elf)
@@ -7506,6 +7865,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    {
                    case R_PPC64_GOT_TLSLD16:
                    case R_PPC64_GOT_TLSLD16_LO:
+                   case R_PPC64_GOT_TLSLD34:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                      /* Fall through.  */
@@ -7526,6 +7886,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
 
                    case R_PPC64_GOT_TLSGD16:
                    case R_PPC64_GOT_TLSGD16_LO:
+                   case R_PPC64_GOT_TLSGD34:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                      /* Fall through. */
@@ -7537,11 +7898,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                        tls_set = 0;
                      else
                        /* GD -> IE */
-                       tls_set = TLS_TLS | TLS_TPRELGD;
+                       tls_set = TLS_TLS | TLS_GDIE;
                      tls_clear = TLS_GD;
                      tls_type = TLS_TLS | TLS_GD;
                      break;
 
+                   case R_PPC64_GOT_TPREL34:
                    case R_PPC64_GOT_TPREL16_DS:
                    case R_PPC64_GOT_TPREL16_LO_DS:
                    case R_PPC64_GOT_TPREL16_HI:
@@ -7556,14 +7918,19 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                        }
                      continue;
 
-                   case R_PPC64_TLSGD:
                    case R_PPC64_TLSLD:
+                     if (!is_local)
+                       continue;
+                     /* Fall through.  */
+                   case R_PPC64_TLSGD:
                      if (rel + 1 < relend
                          && is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
                        {
                          if (pass != 0
                              && (ELF64_R_TYPE (rel[1].r_info)
-                                 != R_PPC64_PLTSEQ))
+                                 != R_PPC64_PLTSEQ)
+                             && (ELF64_R_TYPE (rel[1].r_info)
+                                 != R_PPC64_PLTSEQ_NOTOC))
                            {
                              r_symndx = ELF64_R_SYM (rel[1].r_info);
                              if (!get_sym_h (&h, NULL, NULL, NULL, &locsyms,
@@ -7662,7 +8029,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                            tls_set = TLS_EXPLICIT | TLS_GD;
                          else
                            /* GD -> IE */
-                           tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD;
+                           tls_set = TLS_EXPLICIT | TLS_GD | TLS_GDIE;
                          tls_clear = TLS_GD;
                        }
                      else
@@ -7683,7 +8050,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                  if (pass == 0)
                    {
                      if (!expecting_tls_get_addr
-                         || !sec->has_tls_get_addr_call)
+                         || !sec->nomark_tls_get_addr)
                        continue;
 
                      if (rel + 1 < relend
@@ -7735,12 +8102,12 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                     Disable optimization in this case.  */
                  if ((tls_clear & (TLS_GD | TLS_LD)) != 0
                      && (tls_set & TLS_EXPLICIT) == 0
-                     && !sec->has_tls_get_addr_call
+                     && !sec->nomark_tls_get_addr
                      && ((*tls_mask & (TLS_TLS | TLS_MARK))
                          != (TLS_TLS | TLS_MARK)))
                    continue;
 
-                 if (expecting_tls_get_addr)
+                 if (expecting_tls_get_addr == 1 + !sec->nomark_tls_get_addr)
                    {
                      struct plt_entry *ent = NULL;
 
@@ -7807,7 +8174,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                        }
                    }
 
-                 *tls_mask |= tls_set;
+                 *tls_mask |= tls_set & 0xff;
                  *tls_mask &= ~tls_clear;
                }
 
@@ -7893,37 +8260,165 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 static bfd_boolean
 ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
 {
-  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)) == 38u << 26 /* stb */
-         || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
-         || (insn & (0x3f << 26)) == 42u << 26 /* lha */
-         || (insn & (0x3f << 26)) == 44u << 26 /* sth */
-         || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
-         || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
-         || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
-         || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
-         || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
-         || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
-         || (insn & (0x3f << 26)) == 56u << 26 /* lq,lfq */
-         || ((insn & (0x3f << 26)) == 57u << 26 /* lxsd,lxssp,lfdp */
+  return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */
+         || (insn & (0x3fu << 26)) == 14u << 26 /* addi */
+         || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */
+         || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */
+         || (insn & (0x3fu << 26)) == 36u << 26 /* stw */
+         || (insn & (0x3fu << 26)) == 38u << 26 /* stb */
+         || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */
+         || (insn & (0x3fu << 26)) == 42u << 26 /* lha */
+         || (insn & (0x3fu << 26)) == 44u << 26 /* sth */
+         || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */
+         || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */
+         || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */
+         || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */
+         || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */
+         || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */
+         || (insn & (0x3fu << 26)) == 56u << 26 /* lq,lfq */
+         || ((insn & (0x3fu << 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 & (0x3fu << 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 */
+         || (insn & (0x3fu << 26)) == 60u << 26 /* stfq */
+         || ((insn & (0x3fu << 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 & (0x3fu << 26)) == 62u << 26 /* std,stq */
              && (insn & 1) == 0));
 }
 
+/* PCREL_OPT in one instance flags to the linker that a pair of insns:
+     pld ra,symbol@got@pcrel
+     load/store rt,off(ra)
+   or
+     pla ra,symbol@pcrel
+     load/store rt,off(ra)
+   may be translated to
+     pload/pstore rt,symbol+off@pcrel
+     nop.
+   This function returns true if the optimization is possible, placing
+   the prefix insn in *PINSN1, a NOP in *PINSN2 and the offset in *POFF.
+
+   On entry to this function, the linker has already determined that
+   the pld can be replaced with pla: *PINSN1 is that pla insn,
+   while *PINSN2 is the second instruction.  */
+
+static bfd_boolean
+xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
+{
+  uint64_t insn1 = *pinsn1;
+  uint64_t insn2 = *pinsn2;
+  bfd_signed_vma off;
+
+  if ((insn2 & (63ULL << 58)) == 1ULL << 58)
+    {
+      /* Check that regs match.  */
+      if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
+       return FALSE;
+
+      /* P8LS or PMLS form, non-pcrel.  */
+      if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58))
+       return FALSE;
+
+      *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52);
+      *pinsn2 = PNOP;
+      off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff);
+      *poff = (off ^ 0x200000000ULL) - 0x200000000ULL;
+      return TRUE;
+    }
+
+  insn2 >>= 32;
+
+  /* Check that regs match.  */
+  if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
+    return FALSE;
+
+  switch ((insn2 >> 26) & 63)
+    {
+    default:
+      return FALSE;
+
+    case 32: /* lwz */
+    case 34: /* lbz */
+    case 36: /* stw */
+    case 38: /* stb */
+    case 40: /* lhz */
+    case 42: /* lha */
+    case 44: /* sth */
+    case 48: /* lfs */
+    case 50: /* lfd */
+    case 52: /* stfs */
+    case 54: /* stfd */
+      /* These are the PMLS cases, where we just need to tack a prefix
+        on the insn.  */
+      insn1 = ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+              | (insn2 & ((63ULL << 26) | (31ULL << 21))));
+      off = insn2 & 0xffff;
+      break;
+
+    case 58: /* lwa, ld */
+      if ((insn2 & 1) != 0)
+       return FALSE;
+      insn1 = ((1ULL << 58) | (1ULL << 52)
+              | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26)
+              | (insn2 & (31ULL << 21)));
+      off = insn2 & 0xfffc;
+      break;
+
+    case 57: /* lxsd, lxssp */
+      if ((insn2 & 3) < 2)
+       return FALSE;
+      insn1 = ((1ULL << 58) | (1ULL << 52)
+              | ((40ULL | (insn2 & 3)) << 26)
+              | (insn2 & (31ULL << 21)));
+      off = insn2 & 0xfffc;
+      break;
+
+    case 61: /* stxsd, stxssp, lxv, stxv  */
+      if ((insn2 & 3) == 0)
+       return FALSE;
+      else if ((insn2 & 3) >= 2)
+       {
+         insn1 = ((1ULL << 58) | (1ULL << 52)
+                  | ((44ULL | (insn2 & 3)) << 26)
+                  | (insn2 & (31ULL << 21)));
+         off = insn2 & 0xfffc;
+       }
+      else
+       {
+         insn1 = ((1ULL << 58) | (1ULL << 52)
+                  | ((50ULL | (insn2 & 4) | ((insn2 & 8) >> 3)) << 26)
+                  | (insn2 & (31ULL << 21)));
+         off = insn2 & 0xfff0;
+       }
+      break;
+
+    case 56: /* lq */
+      insn1 = ((1ULL << 58) | (1ULL << 52)
+              | (insn2 & ((63ULL << 26) | (31ULL << 21))));
+      off = insn2 & 0xffff;
+      break;
+
+    case 62: /* std, stq */
+      if ((insn2 & 1) != 0)
+       return FALSE;
+      insn1 = ((1ULL << 58) | (1ULL << 52)
+              | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26)
+              | (insn2 & (31ULL << 21)));
+      off = insn2 & 0xfffc;
+      break;
+    }
+
+  *pinsn1 = insn1;
+  *pinsn2 = (uint64_t) NOP << 32;
+  *poff = (off ^ 0x8000) - 0x8000;
+  return TRUE;
+}
+
 /* Examine all relocs referencing .toc sections in order to remove
    unused .toc entries.  */
 
@@ -8183,65 +8678,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  struct elf_link_hash_entry *h;
                  Elf_Internal_Sym *sym;
                  bfd_vma val;
-                 enum {no_check, check_lo, check_ha} insn_check;
 
                  r_type = ELF64_R_TYPE (rel->r_info);
-                 switch (r_type)
-                   {
-                   default:
-                     insn_check = no_check;
-                     break;
-
-                   case R_PPC64_GOT_TLSLD16_HA:
-                   case R_PPC64_GOT_TLSGD16_HA:
-                   case R_PPC64_GOT_TPREL16_HA:
-                   case R_PPC64_GOT_DTPREL16_HA:
-                   case R_PPC64_GOT16_HA:
-                   case R_PPC64_TOC16_HA:
-                     insn_check = check_ha;
-                     break;
-
-                   case R_PPC64_GOT_TLSLD16_LO:
-                   case R_PPC64_GOT_TLSGD16_LO:
-                   case R_PPC64_GOT_TPREL16_LO_DS:
-                   case R_PPC64_GOT_DTPREL16_LO_DS:
-                   case R_PPC64_GOT16_LO:
-                   case R_PPC64_GOT16_LO_DS:
-                   case R_PPC64_TOC16_LO:
-                   case R_PPC64_TOC16_LO_DS:
-                     insn_check = check_lo;
-                     break;
-                   }
-
-                 if (insn_check != no_check)
-                   {
-                     bfd_vma off = rel->r_offset & ~3;
-                     unsigned char buf[4];
-                     unsigned int insn;
-
-                     if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
-                       {
-                         free (used);
-                         goto error_ret;
-                       }
-                     insn = bfd_get_32 (ibfd, buf);
-                     if (insn_check == check_lo
-                         ? !ok_lo_toc_insn (insn, r_type)
-                         : ((insn & ((0x3f << 26) | 0x1f << 16))
-                            != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
-                       {
-                         char str[12];
-
-                         ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
-                         sprintf (str, "%#08x", insn);
-                         info->callbacks->einfo
-                           /* xgettext:c-format */
-                           (_("%H: toc optimization is not supported for"
-                              " %s instruction\n"),
-                            ibfd, sec, rel->r_offset & ~3, str);
-                       }
-                   }
-
                  switch (r_type)
                    {
                    case R_PPC64_TOC16:
@@ -8579,11 +9017,249 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
       free (skip);
     }
 
-  return TRUE;
-}
+  /* Look for cases where we can change an indirect GOT access to
+     a GOT relative or PC relative access, possibly reducing the
+     number of GOT entries.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      asection *sec;
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Rela *relstart, *rel;
+      bfd_vma got;
 
-/* Return true iff input section I references the TOC using
-   instructions limited to +/-32k offsets.  */
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      if (!ppc64_elf_tdata (ibfd)->has_optrel)
+       continue;
+
+      sec = ppc64_elf_tdata (ibfd)->got;
+      got = 0;
+      if (sec != NULL)
+       got = sec->output_section->vma + sec->output_offset + 0x8000;
+
+      local_syms = NULL;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       {
+         if (sec->reloc_count == 0
+             || !ppc64_elf_section_data (sec)->has_optrel
+             || discarded_section (sec))
+           continue;
+
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                               info->keep_memory);
+         if (relstart == NULL)
+           {
+           got_error_ret:
+             if (local_syms != NULL
+                 && symtab_hdr->contents != (unsigned char *) local_syms)
+               free (local_syms);
+             if (sec != NULL
+                 && relstart != NULL
+                 && elf_section_data (sec)->relocs != relstart)
+               free (relstart);
+             return FALSE;
+           }
+
+         for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+           {
+             enum elf_ppc64_reloc_type r_type;
+             unsigned long r_symndx;
+             Elf_Internal_Sym *sym;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             struct got_entry *ent;
+             bfd_vma val, pc;
+             unsigned char buf[8];
+             unsigned int insn;
+             enum {no_check, check_lo, check_ha} insn_check;
+
+             r_type = ELF64_R_TYPE (rel->r_info);
+             switch (r_type)
+               {
+               default:
+                 insn_check = no_check;
+                 break;
+
+               case R_PPC64_PLT16_HA:
+               case R_PPC64_GOT_TLSLD16_HA:
+               case R_PPC64_GOT_TLSGD16_HA:
+               case R_PPC64_GOT_TPREL16_HA:
+               case R_PPC64_GOT_DTPREL16_HA:
+               case R_PPC64_GOT16_HA:
+               case R_PPC64_TOC16_HA:
+                 insn_check = check_ha;
+                 break;
+
+               case R_PPC64_PLT16_LO:
+               case R_PPC64_PLT16_LO_DS:
+               case R_PPC64_GOT_TLSLD16_LO:
+               case R_PPC64_GOT_TLSGD16_LO:
+               case R_PPC64_GOT_TPREL16_LO_DS:
+               case R_PPC64_GOT_DTPREL16_LO_DS:
+               case R_PPC64_GOT16_LO:
+               case R_PPC64_GOT16_LO_DS:
+               case R_PPC64_TOC16_LO:
+               case R_PPC64_TOC16_LO_DS:
+                 insn_check = check_lo;
+                 break;
+               }
+
+             if (insn_check != no_check)
+               {
+                 bfd_vma off = rel->r_offset & ~3;
+
+                 if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+                   goto got_error_ret;
+
+                 insn = bfd_get_32 (ibfd, buf);
+                 if (insn_check == check_lo
+                     ? !ok_lo_toc_insn (insn, r_type)
+                     : ((insn & ((0x3fu << 26) | 0x1f << 16))
+                        != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+                   {
+                     char str[12];
+
+                     ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+                     sprintf (str, "%#08x", insn);
+                     info->callbacks->einfo
+                       /* xgettext:c-format */
+                       (_("%H: got/toc optimization is not supported for"
+                          " %s instruction\n"),
+                        ibfd, sec, rel->r_offset & ~3, str);
+                     continue;
+                   }
+               }
+
+             switch (r_type)
+               {
+               /* Note that we don't delete GOT entries for
+                  R_PPC64_GOT16_DS since we'd need a lot more
+                  analysis.  For starters, the preliminary layout is
+                  before the GOT, PLT, dynamic sections and stubs are
+                  laid out.  Then we'd need to allow for changes in
+                  distance between sections caused by alignment.  */
+               default:
+                 continue;
+
+               case R_PPC64_GOT16_HA:
+               case R_PPC64_GOT16_LO_DS:
+               case R_PPC64_GOT_PCREL34:
+                 break;
+               }
+
+             r_symndx = ELF64_R_SYM (rel->r_info);
+             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                             r_symndx, ibfd))
+               goto got_error_ret;
+
+             if (sym_sec == NULL
+                 || sym_sec->output_section == NULL
+                 || discarded_section (sym_sec))
+               continue;
+
+             if (!SYMBOL_REFERENCES_LOCAL (info, h))
+               continue;
+
+             if (h != NULL)
+               val = h->root.u.def.value;
+             else
+               val = sym->st_value;
+             val += rel->r_addend;
+             val += sym_sec->output_section->vma + sym_sec->output_offset;
+
+/* Fudge factor to allow for the fact that the preliminary layout
+   isn't exact.  Reduce limits by this factor.  */
+#define LIMIT_ADJUST(LIMIT) ((LIMIT) - (LIMIT) / 16)
+
+             switch (r_type)
+               {
+               default:
+                 continue;
+
+               case R_PPC64_GOT16_HA:
+                 if (val - got + LIMIT_ADJUST (0x80008000ULL)
+                     >= LIMIT_ADJUST (0x100000000ULL))
+                   continue;
+
+                 if (!bfd_get_section_contents (ibfd, sec, buf,
+                                                rel->r_offset & ~3, 4))
+                   goto got_error_ret;
+                 insn = bfd_get_32 (ibfd, buf);
+                 if (((insn & ((0x3fu << 26) | 0x1f << 16))
+                      != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+                   continue;
+                 break;
+
+               case R_PPC64_GOT16_LO_DS:
+                 if (val - got + LIMIT_ADJUST (0x80008000ULL)
+                     >= LIMIT_ADJUST (0x100000000ULL))
+                   continue;
+                 if (!bfd_get_section_contents (ibfd, sec, buf,
+                                                rel->r_offset & ~3, 4))
+                   goto got_error_ret;
+                 insn = bfd_get_32 (ibfd, buf);
+                 if ((insn & (0x3fu << 26 | 0x3)) != 58u << 26 /* ld */)
+                   continue;
+                 break;
+
+               case R_PPC64_GOT_PCREL34:
+                 pc = rel->r_offset;
+                 pc += sec->output_section->vma + sec->output_offset;
+                 if (val - pc + LIMIT_ADJUST (1ULL << 33)
+                     >= LIMIT_ADJUST (1ULL << 34))
+                   continue;
+                 if (!bfd_get_section_contents (ibfd, sec, buf,
+                                                rel->r_offset & ~3, 8))
+                   goto got_error_ret;
+                 insn = bfd_get_32 (ibfd, buf);
+                 if ((insn & (-1u << 18)) != ((1u << 26) | (1u << 20)))
+                   continue;
+                 insn = bfd_get_32 (ibfd, buf + 4);
+                 if ((insn & (0x3fu << 26)) != 57u << 26)
+                   continue;
+                 break;
+               }
+#undef LIMIT_ADJUST
+
+             if (h != NULL)
+               ent = h->got.glist;
+             else
+               {
+                 struct got_entry **local_got_ents = elf_local_got_ents (ibfd);
+                 ent = local_got_ents[r_symndx];
+               }
+             for (; ent != NULL; ent = ent->next)
+               if (ent->addend == rel->r_addend
+                   && ent->owner == ibfd
+                   && ent->tls_type == 0)
+                 break;
+             BFD_ASSERT (ent && ent->got.refcount > 0);
+             ent->got.refcount -= 1;
+           }
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
+       }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
+
+  return TRUE;
+}
+
+/* Return true iff input section I references the TOC using
+   instructions limited to +/-32k offsets.  */
 
 bfd_boolean
 ppc64_elf_has_small_toc_reloc (asection *i)
@@ -8616,7 +9292,7 @@ allocate_got (struct elf_link_hash_entry *h,
       htab->got_reli_size += rentsize;
     }
   else if (((bfd_link_pic (info)
-            && !((gent->tls_type & TLS_TPREL) != 0
+            && !(gent->tls_type != 0
                  && bfd_link_executable (info)
                  && SYMBOL_REFERENCES_LOCAL (info, h)))
            || (htab->elf.dynamic_sections_created
@@ -8691,7 +9367,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   eh = (struct ppc_link_hash_entry *) h;
   /* Run through the TLS GD got entries first if we're changing them
      to TPREL.  */
-  if ((eh->tls_mask & (TLS_TLS | TLS_TPRELGD)) == (TLS_TLS | TLS_TPRELGD))
+  if ((eh->tls_mask & (TLS_TLS | TLS_GDIE)) == (TLS_TLS | TLS_GDIE))
     for (gent = h->got.glist; gent != NULL; gent = gent->next)
       if (gent->got.refcount > 0
          && (gent->tls_type & TLS_GD) != 0)
@@ -8722,7 +9398,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     if (gent->got.refcount > 0)
       {
        if ((gent->tls_type & TLS_LD) != 0
-           && !h->def_dynamic)
+           && SYMBOL_REFERENCES_LOCAL (info, h))
          {
            ppc64_tlsld_got (gent->owner)->got.refcount += 1;
            *pgent = gent->next;
@@ -8739,7 +9415,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   for (gent = h->got.glist; gent != NULL; gent = gent->next)
     if (!gent->is_indirect)
       {
-       /* Make sure this symbol is output as a dynamic symbol.  */
+       /* Ensure we catch all the cases where this symbol should
+          be made dynamic.  */
        if (!ensure_undef_dynamic (info, h))
          return FALSE;
 
@@ -8774,7 +9451,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         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))
        {
          /* Relocs that use pc_count are those that appear on a call
@@ -8799,24 +9475,27 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
          if (eh->dyn_relocs != NULL)
            {
-             /* Make sure this symbol is output as a dynamic symbol.  */
+             /* Ensure we catch all the cases where this symbol
+                should be made dynamic.  */
              if (!ensure_undef_dynamic (info, h))
                return FALSE;
            }
        }
-      else if (ELIMINATE_COPY_RELOCS && h->type != STT_GNU_IFUNC)
+
+      /* For a fixed position executable, discard space for
+        relocs against symbols which are not dynamic.  */
+      else if (h->type != STT_GNU_IFUNC)
        {
-         /* For the non-pic case, discard space for relocs against
-            symbols which turn out to need copy relocs or are not
-            dynamic.  */
          if (h->dynamic_adjusted
              && !h->def_regular
              && !ELF_COMMON_DEF_P (h))
            {
-             /* Make sure this symbol is output as a dynamic symbol.  */
+             /* Ensure we catch all the cases where this symbol
+                should be made dynamic.  */
              if (!ensure_undef_dynamic (info, h))
                return FALSE;
 
+             /* But if that didn't work out, discard dynamic relocs.  */
              if (h->dynindx == -1)
                eh->dyn_relocs = NULL;
            }
@@ -8926,6 +9605,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 #define PPC_LO(v) ((v) & 0xffff)
 #define PPC_HI(v) (((v) >> 16) & 0xffff)
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
+#define D34(v) \
+  ((((v) & 0x3ffff0000ULL) << 16) | (v & 0xffff))
+#define HA34(v) ((v + (1ULL << 33)) >> 34)
 
 /* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections
    to set up space for global entry stubs.  These are put in glink,
@@ -9145,7 +9827,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        htab->got_reli_size += rel_size;
                      }
                    else if (bfd_link_pic (info)
-                            && !((ent->tls_type & TLS_TPREL) != 0
+                            && !(ent->tls_type != 0
                                  && bfd_link_executable (info)))
                      {
                        asection *srel = ppc64_elf_tdata (ibfd)->relgot;
@@ -9222,7 +9904,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              ent->got.offset = s->size;
              ent->owner = ibfd;
              s->size += 16;
-             if (bfd_link_pic (info))
+             if (bfd_link_dll (info))
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += sizeof (Elf64_External_Rela);
@@ -9707,6 +10389,146 @@ emit_relocs_for_offset (struct bfd_link_info *info, Elf_Internal_Rela *r,
   return r;
 }
 
+static bfd_byte *
+build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
+                     bfd_boolean load)
+{
+  uint64_t insn;
+  if (off - odd + (1ULL << 33) < 1ULL << 34)
+    {
+      off -= odd;
+      if (odd)
+       {
+         bfd_put_32 (abfd, NOP, p);
+         p += 4;
+       }
+      if (load)
+       insn = PLD_R12_PC;
+      else
+       insn = PADDI_R12_PC;
+      insn |= D34 (off);
+      bfd_put_32 (abfd, insn >> 32, p);
+      p += 4;
+      bfd_put_32 (abfd, insn, p);
+    }
+  /* The minimum value for paddi is -0x200000000.  The minimum value
+     for li is -0x8000, which when shifted by 34 and added gives a
+     minimum value of -0x2000200000000.  The maximum value is
+     0x1ffffffff+0x7fff<<34 which is 0x2000200000000-1.  */
+  else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+    {
+      off -= 8 - odd;
+      bfd_put_32 (abfd, LI_R11_0 | (HA34 (off) & 0xffff), p);
+      p += 4;
+      if (!odd)
+       {
+         bfd_put_32 (abfd, SLDI_R11_R11_34, p);
+         p += 4;
+       }
+      insn = PADDI_R12_PC | D34 (off);
+      bfd_put_32 (abfd, insn >> 32, p);
+      p += 4;
+      bfd_put_32 (abfd, insn, p);
+      p += 4;
+      if (odd)
+       {
+         bfd_put_32 (abfd, SLDI_R11_R11_34, p);
+         p += 4;
+       }
+      if (load)
+       bfd_put_32 (abfd, LDX_R12_R11_R12, p);
+      else
+       bfd_put_32 (abfd, ADD_R12_R11_R12, p);
+    }
+  else
+    {
+      off -= odd + 8;
+      bfd_put_32 (abfd, LIS_R11 | ((HA34 (off) >> 16) & 0x3fff), p);
+      p += 4;
+      bfd_put_32 (abfd, ORI_R11_R11_0 | (HA34 (off) & 0xffff), p);
+      p += 4;
+      if (odd)
+       {
+         bfd_put_32 (abfd, SLDI_R11_R11_34, p);
+         p += 4;
+       }
+      insn = PADDI_R12_PC | D34 (off);
+      bfd_put_32 (abfd, insn >> 32, p);
+      p += 4;
+      bfd_put_32 (abfd, insn, p);
+      p += 4;
+      if (!odd)
+       {
+         bfd_put_32 (abfd, SLDI_R11_R11_34, p);
+         p += 4;
+       }
+      if (load)
+       bfd_put_32 (abfd, LDX_R12_R11_R12, p);
+      else
+       bfd_put_32 (abfd, ADD_R12_R11_R12, p);
+    }
+  p += 4;
+  return p;
+}
+
+static unsigned int
+size_powerxx_offset (bfd_vma off, int odd)
+{
+  if (off - odd + (1ULL << 33) < 1ULL << 34)
+    return odd + 8;
+  else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+    return 20;
+  else
+    return 24;
+}
+
+static unsigned int
+num_relocs_for_powerxx_offset (bfd_vma off, int odd)
+{
+  if (off - odd + (1ULL << 33) < 1ULL << 34)
+    return 1;
+  else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+    return 2;
+  else
+    return 3;
+}
+
+static Elf_Internal_Rela *
+emit_relocs_for_powerxx_offset (struct bfd_link_info *info,
+                               Elf_Internal_Rela *r, bfd_vma roff,
+                               bfd_vma targ, bfd_vma off, int odd)
+{
+  if (off - odd + (1ULL << 33) < 1ULL << 34)
+    roff += odd;
+  else if (off - (8 - odd) + (0x20002ULL << 32) < 0x40004ULL << 32)
+    {
+      int d_offset = bfd_big_endian (info->output_bfd) ? 2 : 0;
+      r->r_offset = roff + d_offset;
+      r->r_addend = targ + 8 - odd - d_offset;
+      r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHERA34);
+      ++r;
+      roff += 8 - odd;
+    }
+  else
+    {
+      int d_offset = bfd_big_endian (info->output_bfd) ? 2 : 0;
+      r->r_offset = roff + d_offset;
+      r->r_addend = targ + 8 + odd - d_offset;
+      r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHESTA34);
+      ++r;
+      roff += 4;
+      r->r_offset = roff + d_offset;
+      r->r_addend = targ + 4 + odd - d_offset;
+      r->r_info = ELF64_R_INFO (0, R_PPC64_REL16_HIGHERA34);
+      ++r;
+      roff += 4 + odd;
+    }
+  r->r_offset = roff;
+  r->r_addend = targ;
+  r->r_info = ELF64_R_INFO (0, R_PPC64_PCREL34);
+  return r;
+}
+
 /* Emit .eh_frame opcode to advance pc by DELTA.  */
 
 static bfd_byte *
@@ -9784,7 +10606,17 @@ plt_stub_size (struct ppc_link_hash_table *htab,
 
   if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
     {
-      size = 8 + size_offset (off - 8);
+      if (htab->powerxx_stubs)
+       {
+         bfd_vma start = (stub_entry->stub_offset
+                          + stub_entry->group->stub_sec->output_offset
+                          + stub_entry->group->stub_sec->output_section->vma);
+         if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
+           start += 4;
+         size = 8 + size_powerxx_offset (off, start & 4);
+       }
+      else
+       size = 8 + size_offset (off - 8);
       if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
        size += 4;
       return size;
@@ -10237,6 +11069,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   Elf_Internal_Rela *r;
   asection *plt;
   int num_rel;
+  int odd;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
@@ -10515,18 +11348,28 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        targ = (stub_entry->target_value
                + stub_entry->target_section->output_offset
                + stub_entry->target_section->output_section->vma);
+      odd = off & 4;
       off = targ - off;
 
       relp = p;
       num_rel = 0;
-      /* The notoc stubs calculate their target (either a PLT entry or
-        the global entry point of a function) relative to the PC
-        returned by the "bcl" two instructions past the start of the
-        sequence emitted by build_offset.  The offset is therefore 8
-        less than calculated from the start of the sequence.  */
-      off -= 8;
-      p = build_offset (htab->params->stub_bfd, p, off,
-                       stub_entry->stub_type >= ppc_stub_plt_call_notoc);
+      if (htab->powerxx_stubs)
+       {
+         bfd_boolean load = stub_entry->stub_type >= ppc_stub_plt_call_notoc;
+         p = build_powerxx_offset (htab->params->stub_bfd, p, off, odd, load);
+       }
+      else
+       {
+         /* The notoc stubs calculate their target (either a PLT entry or
+            the global entry point of a function) relative to the PC
+            returned by the "bcl" two instructions past the start of the
+            sequence emitted by build_offset.  The offset is therefore 8
+            less than calculated from the start of the sequence.  */
+         off -= 8;
+         p = build_offset (htab->params->stub_bfd, p, off,
+                           stub_entry->stub_type >= ppc_stub_plt_call_notoc);
+       }
+
       if (stub_entry->stub_type <= ppc_stub_long_branch_both)
        {
          bfd_vma from;
@@ -10548,13 +11391,21 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
-         bfd_vma roff;
-         num_rel += num_relocs_for_offset (off);
+         bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
+         if (htab->powerxx_stubs)
+           num_rel += num_relocs_for_powerxx_offset (off, odd);
+         else
+           {
+             num_rel += num_relocs_for_offset (off);
+             roff += 16;
+           }
          r = get_relocs (stub_entry->group->stub_sec, num_rel);
          if (r == NULL)
            return FALSE;
-         roff = relp + 16 - stub_entry->group->stub_sec->contents;
-         r = emit_relocs_for_offset (info, r, roff, targ, off);
+         if (htab->powerxx_stubs)
+           r = emit_relocs_for_powerxx_offset (info, r, roff, targ, off, odd);
+         else
+           r = emit_relocs_for_offset (info, r, roff, targ, off);
          if (stub_entry->stub_type == ppc_stub_long_branch_notoc
              || stub_entry->stub_type == ppc_stub_long_branch_both)
            {
@@ -10569,8 +11420,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            }
        }
 
-      if (htab->glink_eh_frame != NULL
-       && htab->glink_eh_frame->size != 0)
+      if (!htab->powerxx_stubs
+         && htab->glink_eh_frame != NULL
+         && htab->glink_eh_frame->size != 0)
        {
          bfd_byte *base, *eh;
          unsigned int lr_used, delta;
@@ -10739,7 +11591,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   struct ppc_link_hash_table *htab;
   asection *plt;
   bfd_vma targ, off, r2off;
-  unsigned int size, extra, lr_used, delta;
+  unsigned int size, extra, lr_used, delta, odd;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
@@ -10892,16 +11744,24 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
              + stub_entry->target_section->output_section->vma);
+      odd = off & 4;
       off = targ - off;
 
       if (info->emitrelocations)
        {
-         stub_entry->group->stub_sec->reloc_count
-           += num_relocs_for_offset (off);
+         unsigned int num_rel;
+         if (htab->powerxx_stubs)
+           num_rel = num_relocs_for_powerxx_offset (off, odd);
+         else
+           num_rel = num_relocs_for_offset (off - 8);
+         stub_entry->group->stub_sec->reloc_count += num_rel;
          stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
 
-      extra = size_offset (off - 8);
+      if (htab->powerxx_stubs)
+       extra = size_powerxx_offset (off, odd);
+      else
+       extra = size_offset (off - 8);
       /* Include branch insn plus those in the offset sequence.  */
       size += 4 + extra;
       /* The branch insn is at the end, or "extra" bytes along.  So
@@ -10909,17 +11769,20 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
         calculated.  */
       off -= extra;
 
-      /* After the bcl, lr has been modified so we need to emit
-        .eh_frame info saying the return address is in r12.  */
-      lr_used = stub_entry->stub_offset + 8;
-      if (stub_entry->stub_type == ppc_stub_long_branch_both)
-       lr_used += 4;
-      /* The eh_frame info will consist of a DW_CFA_advance_loc or
-        variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
-        DW_CFA_restore_extended 65.  */
-      delta = lr_used - stub_entry->group->lr_restore;
-      stub_entry->group->eh_size += eh_advance_size (delta) + 6;
-      stub_entry->group->lr_restore = lr_used + 8;
+      if (!htab->powerxx_stubs)
+       {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         lr_used = stub_entry->stub_offset + 8;
+         if (stub_entry->stub_type == ppc_stub_long_branch_both)
+           lr_used += 4;
+         /* The eh_frame info will consist of a DW_CFA_advance_loc or
+            variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
+            DW_CFA_restore_extended 65.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+       }
 
       /* If the branch can't reach, use a plt_branch.  */
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
@@ -10954,6 +11817,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            plt = htab->pltlocal;
        }
       targ += plt->output_offset + plt->output_section->vma;
+      odd = off & 4;
       off = targ - off;
 
       if (htab->params->plt_stub_align != 0)
@@ -10967,24 +11831,31 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (info->emitrelocations)
        {
-         stub_entry->group->stub_sec->reloc_count
-           += num_relocs_for_offset (off - 8);
+         unsigned int num_rel;
+         if (htab->powerxx_stubs)
+           num_rel = num_relocs_for_powerxx_offset (off, odd);
+         else
+           num_rel = num_relocs_for_offset (off - 8);
+         stub_entry->group->stub_sec->reloc_count += num_rel;
          stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
 
       size = plt_stub_size (htab, stub_entry, off);
 
-      /* After the bcl, lr has been modified so we need to emit
-        .eh_frame info saying the return address is in r12.  */
-      lr_used = stub_entry->stub_offset + 8;
-      if (stub_entry->stub_type == ppc_stub_plt_call_both)
-       lr_used += 4;
-      /* The eh_frame info will consist of a DW_CFA_advance_loc or
-        variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
-        DW_CFA_restore_extended 65.  */
-      delta = lr_used - stub_entry->group->lr_restore;
-      stub_entry->group->eh_size += eh_advance_size (delta) + 6;
-      stub_entry->group->lr_restore = lr_used + 8;
+      if (!htab->powerxx_stubs)
+       {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         lr_used = stub_entry->stub_offset + 8;
+         if (stub_entry->stub_type == ppc_stub_plt_call_both)
+           lr_used += 4;
+         /* The eh_frame info will consist of a DW_CFA_advance_loc or
+            variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
+            DW_CFA_restore_extended 65.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+       }
       break;
 
     case ppc_stub_plt_call:
@@ -11328,7 +12199,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  htab->got_reli_size += rel_size;
                }
              else if (bfd_link_pic (info)
-                      && !((ent->tls_type & TLS_TPREL) != 0
+                      && !(ent->tls_type != 0
                            && bfd_link_executable (info)))
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
@@ -11354,7 +12225,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
          asection *s = ppc64_elf_tdata (ibfd)->got;
          ent->got.offset = s->size;
          s->size += 16;
-         if (bfd_link_pic (info))
+         if (bfd_link_dll (info))
            {
              asection *srel = ppc64_elf_tdata (ibfd)->relgot;
              srel->size += sizeof (Elf64_External_Rela);
@@ -11465,7 +12336,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
              && r_type != R_PPC64_REL14
              && r_type != R_PPC64_REL14_BRTAKEN
              && r_type != R_PPC64_REL14_BRNTAKEN
-             && r_type != R_PPC64_PLTCALL)
+             && r_type != R_PPC64_PLTCALL
+             && r_type != R_PPC64_PLTCALL_NOTOC)
            continue;
 
          r_symndx = ELF64_R_SYM (rel->r_info);
@@ -12157,7 +13029,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                                   && code_sec->output_section != NULL
                                   && (((hash ? hash->elf.other : sym->st_other)
                                        & STO_PPC64_LOCAL_MASK)
-                                      != 1 << STO_PPC64_LOCAL_BIT)))
+                                      > 1 << STO_PPC64_LOCAL_BIT)))
                        stub_type = ppc_stub_long_branch_notoc;
                    }
                  else if (stub_type != ppc_stub_plt_call)
@@ -13291,6 +14163,66 @@ ppc64_elf_action_discarded (asection *sec)
   return _bfd_elf_default_action_discarded (sec);
 }
 
+/* These are the dynamic relocations supported by glibc.  */
+
+static bfd_boolean
+ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
+{
+  switch (r_type)
+    {
+    case R_PPC64_RELATIVE:
+    case R_PPC64_NONE:
+    case R_PPC64_ADDR64:
+    case R_PPC64_GLOB_DAT:
+    case R_PPC64_IRELATIVE:
+    case R_PPC64_JMP_IREL:
+    case R_PPC64_JMP_SLOT:
+    case R_PPC64_DTPMOD64:
+    case R_PPC64_DTPREL64:
+    case R_PPC64_TPREL64:
+    case R_PPC64_TPREL16_LO_DS:
+    case R_PPC64_TPREL16_DS:
+    case R_PPC64_TPREL16:
+    case R_PPC64_TPREL16_LO:
+    case R_PPC64_TPREL16_HI:
+    case R_PPC64_TPREL16_HIGH:
+    case R_PPC64_TPREL16_HA:
+    case R_PPC64_TPREL16_HIGHA:
+    case R_PPC64_TPREL16_HIGHER:
+    case R_PPC64_TPREL16_HIGHEST:
+    case R_PPC64_TPREL16_HIGHERA:
+    case R_PPC64_TPREL16_HIGHESTA:
+    case R_PPC64_ADDR16_LO_DS:
+    case R_PPC64_ADDR16_LO:
+    case R_PPC64_ADDR16_HI:
+    case R_PPC64_ADDR16_HIGH:
+    case R_PPC64_ADDR16_HA:
+    case R_PPC64_ADDR16_HIGHA:
+    case R_PPC64_REL30:
+    case R_PPC64_COPY:
+    case R_PPC64_UADDR64:
+    case R_PPC64_UADDR32:
+    case R_PPC64_ADDR32:
+    case R_PPC64_ADDR24:
+    case R_PPC64_ADDR16:
+    case R_PPC64_UADDR16:
+    case R_PPC64_ADDR16_DS:
+    case R_PPC64_ADDR16_HIGHER:
+    case R_PPC64_ADDR16_HIGHEST:
+    case R_PPC64_ADDR16_HIGHERA:
+    case R_PPC64_ADDR16_HIGHESTA:
+    case R_PPC64_ADDR14:
+    case R_PPC64_ADDR14_BRTAKEN:
+    case R_PPC64_ADDR14_BRNTAKEN:
+    case R_PPC64_REL32:
+    case R_PPC64_REL64:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -13344,6 +14276,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   bfd_boolean is_opd;
   /* Assume 'at' branch hints.  */
   bfd_boolean is_isa_v2 = TRUE;
+  bfd_boolean warned_dynamic = FALSE;
   bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
 
   /* Initialize howto table if needed.  */
@@ -13399,6 +14332,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       Elf_Internal_Rela orig_rel;
       reloc_howto_type *howto;
       struct reloc_howto_struct alt_howto;
+      uint64_t pinsn;
+      bfd_vma offset;
 
     again:
       orig_rel = *rel;
@@ -13563,10 +14498,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          && (h == NULL
              || h->elf.root.type == bfd_link_hash_defined
              || h->elf.root.type == bfd_link_hash_defweak)
-         && (IS_PPC64_TLS_RELOC (r_type)
-             != (sym_type == STT_TLS
-                 || (sym_type == STT_SECTION
-                     && (sec->flags & SEC_THREAD_LOCAL) != 0))))
+         && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS))
        {
          if ((tls_mask & TLS_TLS) != 0
              && (r_type == R_PPC64_TLS
@@ -13606,7 +14538,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_LO_DS_OPT:
          insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset);
-         if ((insn & (0x3f << 26)) != 58u << 26)
+         if ((insn & (0x3fu << 26)) != 58u << 26)
            abort ();
          insn += (14u << 26) - (58u << 26);
          bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset);
@@ -13644,7 +14576,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                       doing a GD->IE transition.  */
                    if (retval == 2)
                      {
-                       tls_gd = TLS_TPRELGD;
+                       tls_gd = TLS_GDIE;
                        if ((tls_mask & TLS_TLS) != 0
                            && (tls_mask & TLS_GD) == 0)
                          goto tls_ldgd_opt;
@@ -13698,35 +14630,78 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC64_GOT_TPREL34:
+         if ((tls_mask & TLS_TLS) != 0
+             && (tls_mask & TLS_TPREL) == 0)
+           {
+             /* pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel  */
+             pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+             pinsn += ((2ULL << 56) + (-1ULL << 52)
+                       + (14ULL << 26) - (57ULL << 26) + (13ULL << 16));
+             bfd_put_32 (input_bfd, pinsn >> 32,
+                         contents + rel->r_offset);
+             bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+                         contents + rel->r_offset + 4);
+             r_type = R_PPC64_TPREL34;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+           }
+         break;
+
        case R_PPC64_TLS:
          if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
              insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
              if (insn == 0)
-               abort ();
-             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;
-             r_type = R_PPC64_TPREL16_LO;
-             if (toc_symndx != 0)
+               break;
+             if ((rel->r_offset & 3) == 0)
                {
-                 rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
-                 rel->r_addend = toc_addend;
-                 /* We changed the symbol.  Start over in order to
-                    get h, sym, sec etc. right.  */
-                 goto again;
+                 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;
+                 r_type = R_PPC64_TPREL16_LO;
+                 if (toc_symndx != 0)
+                   {
+                     rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+                     rel->r_addend = toc_addend;
+                     /* We changed the symbol.  Start over in order to
+                        get h, sym, sec etc. right.  */
+                     goto again;
+                   }
+                 else
+                   rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+               }
+             else if ((rel->r_offset & 3) == 1)
+               {
+                 /* For pcrel IE to LE we already have the full
+                    offset and thus don't need an addi here.  A nop
+                    or mr will do.  */
+                 if ((insn & (0x3fu << 26)) == 14 << 26)
+                   {
+                     /* Extract regs from addi rt,ra,si.  */
+                     unsigned int rt = (insn >> 21) & 0x1f;
+                     unsigned int ra = (insn >> 16) & 0x1f;
+                     if (rt == ra)
+                       insn = NOP;
+                     else
+                       {
+                         /* Build or ra,rs,rb with rb==rs, ie. mr ra,rs.  */
+                         insn = (rt << 16) | (ra << 21) | (ra << 11);
+                         insn |= (31u << 26) | (444u << 1);
+                       }
+                   }
+                 bfd_put_32 (input_bfd, insn, contents + rel->r_offset - 1);
                }
-             else
-               rel->r_info = ELF64_R_INFO (r_symndx, r_type);
            }
          break;
 
        case R_PPC64_GOT_TLSGD16_HI:
        case R_PPC64_GOT_TLSGD16_HA:
-         tls_gd = TLS_TPRELGD;
+         tls_gd = TLS_GDIE;
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_gdld_hi;
          break;
@@ -13751,7 +14726,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_GOT_TLSGD16:
        case R_PPC64_GOT_TLSGD16_LO:
-         tls_gd = TLS_TPRELGD;
+         tls_gd = TLS_GDIE;
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_ldgd_opt;
          break;
@@ -13761,7 +14736,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
            {
              unsigned int insn1, insn2;
-             bfd_vma offset;
 
            tls_ldgd_opt:
              offset = (bfd_vma) -1;
@@ -13770,7 +14744,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 stays with its arg setup insns, ie. that the next
                 reloc is the __tls_get_addr call associated with
                 the current reloc.  Edit both insns.  */
-             if (input_section->has_tls_get_addr_call
+             if (input_section->nomark_tls_get_addr
                  && rel + 1 < relend
                  && branch_reloc_hash_match (input_bfd, rel + 1,
                                              htab->tls_get_addr,
@@ -13786,15 +14760,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                {
                  /* IE */
                  insn1 &= (0x1f << 21) | (0x1f << 16);
-                 insn1 |= 58 << 26;    /* ld */
+                 insn1 |= 58u << 26;   /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
                  if (offset != (bfd_vma) -1)
                    rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
-                 if ((tls_mask & TLS_EXPLICIT) == 0)
-                   r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
-                             + R_PPC64_GOT_TPREL16_DS);
-                 else
+                 if (r_type == R_PPC64_TOC16
+                     || r_type == R_PPC64_TOC16_LO)
                    r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
+                 else
+                   r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 1)) & 1)
+                             + R_PPC64_GOT_TPREL16_DS);
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
                }
              else
@@ -13806,20 +14781,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
-                     if (toc_symndx)
-                       sec = local_sections[toc_symndx];
-                     for (r_symndx = 0;
-                          r_symndx < symtab_hdr->sh_info;
-                          r_symndx++)
-                       if (local_sections[r_symndx] == sec)
-                         break;
-                     if (r_symndx >= symtab_hdr->sh_info)
-                       r_symndx = STN_UNDEF;
+                     r_symndx = STN_UNDEF;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-                     if (r_symndx != STN_UNDEF)
-                       rel->r_addend -= (local_syms[r_symndx].st_value
-                                         + sec->output_offset
-                                         + sec->output_section->vma);
                    }
                  else if (toc_symndx != 0)
                    {
@@ -13858,16 +14821,65 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC64_GOT_TLSGD34:
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+             if ((tls_mask & TLS_GDIE) != 0)
+               {
+                 /* IE, pla -> pld  */
+                 pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26);
+                 r_type = R_PPC64_GOT_TPREL34;
+               }
+             else
+               {
+                 /* LE, pla pcrel -> paddi r13  */
+                 pinsn += (-1ULL << 52) + (13ULL << 16);
+                 r_type = R_PPC64_TPREL34;
+               }
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             bfd_put_32 (input_bfd, pinsn >> 32,
+                         contents + rel->r_offset);
+             bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+                         contents + rel->r_offset + 4);
+           }
+         break;
+
+       case R_PPC64_GOT_TLSLD34:
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+             pinsn += (-1ULL << 52) + (13ULL << 16);
+             bfd_put_32 (input_bfd, pinsn >> 32,
+                         contents + rel->r_offset);
+             bfd_put_32 (input_bfd, pinsn & 0xffffffff,
+                         contents + rel->r_offset + 4);
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             r_symndx = STN_UNDEF;
+             r_type = R_PPC64_TPREL34;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             goto again;
+           }
+         break;
+
        case R_PPC64_TLSGD:
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
              && rel + 1 < relend)
            {
              unsigned int insn2;
-             bfd_vma offset = rel->r_offset;
+             enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
 
-             if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+             offset = rel->r_offset;
+             if (is_plt_seq_reloc (r_type1))
                {
                  bfd_put_32 (output_bfd, NOP, contents + offset);
+                 if (r_type1 == R_PPC64_PLT_PCREL34
+                     || r_type1 == R_PPC64_PLT_PCREL34_NOTOC)
+                   bfd_put_32 (output_bfd, NOP, contents + offset + 4);
                  rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
                  break;
                }
@@ -13875,7 +14887,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
                bfd_put_32 (output_bfd, NOP, contents + offset + 4);
 
-             if ((tls_mask & TLS_TPRELGD) != 0)
+             if ((tls_mask & TLS_GDIE) != 0)
                {
                  /* IE */
                  r_type = R_PPC64_NONE;
@@ -13889,16 +14901,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      r_symndx = toc_symndx;
                      rel->r_addend = toc_addend;
                    }
-                 r_type = R_PPC64_TPREL16_LO;
-                 rel->r_offset = offset + d_offset;
-                 insn2 = 0x38630000;   /* addi 3,3,0 */
+                 if (r_type1 == R_PPC64_REL24_NOTOC
+                     || r_type1 == R_PPC64_PLTCALL_NOTOC)
+                   {
+                     r_type = R_PPC64_NONE;
+                     insn2 = NOP;
+                   }
+                 else
+                   {
+                     rel->r_offset = offset + d_offset;
+                     r_type = R_PPC64_TPREL16_LO;
+                     insn2 = 0x38630000;       /* addi 3,3,0 */
+                   }
                }
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
              /* 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);
              bfd_put_32 (input_bfd, insn2, contents + offset);
-             if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
+             if ((tls_mask & TLS_GDIE) == 0
+                 && toc_symndx != 0
+                 && r_type != R_PPC64_NONE)
                goto again;
            }
          break;
@@ -13908,11 +14931,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && rel + 1 < relend)
            {
              unsigned int insn2;
-             bfd_vma offset = rel->r_offset;
+             enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
 
-             if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+             offset = rel->r_offset;
+             if (is_plt_seq_reloc (r_type1))
                {
                  bfd_put_32 (output_bfd, NOP, contents + offset);
+                 if (r_type1 == R_PPC64_PLT_PCREL34
+                     || r_type1 == R_PPC64_PLT_PCREL34_NOTOC)
+                   bfd_put_32 (output_bfd, NOP, contents + offset + 4);
                  rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
                  break;
                }
@@ -13920,30 +14947,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
                bfd_put_32 (output_bfd, NOP, contents + offset + 4);
 
-             if (toc_symndx)
-               sec = local_sections[toc_symndx];
-             for (r_symndx = 0;
-                  r_symndx < symtab_hdr->sh_info;
-                  r_symndx++)
-               if (local_sections[r_symndx] == sec)
-                 break;
-             if (r_symndx >= symtab_hdr->sh_info)
-               r_symndx = STN_UNDEF;
-             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-             if (r_symndx != STN_UNDEF)
-               rel->r_addend -= (local_syms[r_symndx].st_value
-                                 + sec->output_offset
-                                 + sec->output_section->vma);
-
-             r_type = R_PPC64_TPREL16_LO;
+             if (r_type1 == R_PPC64_REL24_NOTOC
+                 || r_type1 == R_PPC64_PLTCALL_NOTOC)
+               {
+                 r_type = R_PPC64_NONE;
+                 insn2 = NOP;
+               }
+             else
+               {
+                 rel->r_offset = offset + d_offset;
+                 r_symndx = STN_UNDEF;
+                 r_type = R_PPC64_TPREL16_LO;
+                 rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-             rel->r_offset = offset + d_offset;
              /* 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);
-             insn2 = 0x38630000;       /* addi 3,3,0 */
              bfd_put_32 (input_bfd, insn2, contents + offset);
-             goto again;
+             if (r_type != R_PPC64_NONE)
+               goto again;
            }
          break;
 
@@ -13955,7 +14979,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if ((tls_mask & TLS_GD) == 0)
                {
                  rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE);
-                 if ((tls_mask & TLS_TPRELGD) != 0)
+                 if ((tls_mask & TLS_GDIE) != 0)
                    r_type = R_PPC64_TPREL64;
                  else
                    {
@@ -14050,7 +15074,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && relocation + 0x80008000 <= 0xffffffff)
            {
              unsigned int insn1, insn2;
-             bfd_vma offset = rel->r_offset - d_offset;
+             offset = rel->r_offset - d_offset;
              insn1 = bfd_get_32 (input_bfd, contents + offset);
              insn2 = bfd_get_32 (input_bfd, contents + offset + 4);
              if ((insn1 & 0xffff0000) == ADDIS_R2_R12
@@ -14113,6 +15137,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_REL24:
        case R_PPC64_REL24_NOTOC:
        case R_PPC64_PLTCALL:
+       case R_PPC64_PLTCALL_NOTOC:
          /* Calls to functions with a different TOC, such as calls to
             shared objects, need to alter the TOC pointer.  This is
             done using a linkage stub.  A REL24 branching to these
@@ -14126,7 +15151,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            fdh = ppc_follow_link (h->oh);
          stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
                                           htab);
-         if (r_type == R_PPC64_PLTCALL
+         if ((r_type == R_PPC64_PLTCALL
+              || r_type == R_PPC64_PLTCALL_NOTOC)
              && stub_entry != NULL
              && stub_entry->stub_type >= ppc_stub_plt_call
              && stub_entry->stub_type <= ppc_stub_plt_call_both)
@@ -14305,7 +15331,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || stub_entry->stub_type == ppc_stub_plt_branch_both)
              && (r_type != R_PPC64_REL24_NOTOC
                  || ((fdh ? fdh->elf.other : sym->st_other)
-                     & STO_PPC64_LOCAL_MASK) == 1 << STO_PPC64_LOCAL_BIT)
+                     & STO_PPC64_LOCAL_MASK) <= 1 << STO_PPC64_LOCAL_BIT)
              && (relocation + addend - from + max_br_offset
                  < 2 * max_br_offset))
            stub_entry = NULL;
@@ -14356,6 +15382,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        || stub_entry->stub_type == ppc_stub_plt_call_both)
                       && r_type == R_PPC64_REL24_NOTOC)
                relocation += 4;
+
+             if (r_type == R_PPC64_REL24_NOTOC
+                 && (stub_entry->stub_type == ppc_stub_plt_call_notoc
+                     || stub_entry->stub_type == ppc_stub_plt_call_both))
+               htab->notoc_plt = 1;
            }
 
          if (insn != 0)
@@ -14397,9 +15428,125 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              goto copy_reloc;
            }
          break;
+
+       case R_PPC64_GOT16_DS:
+         from = TOCstart + htab->sec_info[input_section->id].toc_off;
+         if (relocation + addend - from + 0x8000 < 0x10000
+             && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+           {
+             insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+             if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
+               {
+                 insn += (14u << 26) - (58u << 26);
+                 bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
+                 r_type = R_PPC64_TOC16;
+                 rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+               }
+           }
+         break;
+
+       case R_PPC64_GOT16_LO_DS:
+       case R_PPC64_GOT16_HA:
+         from = TOCstart + htab->sec_info[input_section->id].toc_off;
+         if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL
+             && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+           {
+             insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+             if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
+               {
+                 insn += (14u << 26) - (58u << 26);
+                 bfd_put_32 (input_bfd, insn, contents + (rel->r_offset & ~3));
+                 r_type = R_PPC64_TOC16_LO;
+                 rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+               }
+             else if ((insn & (0x3fu << 26)) == 15u << 26 /* addis */)
+               {
+                 r_type = R_PPC64_TOC16_HA;
+                 rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+               }
+           }
+         break;
+
+       case R_PPC64_GOT_PCREL34:
+         from = (rel->r_offset
+                 + input_section->output_section->vma
+                 + input_section->output_offset);
+         if (relocation - from + (1ULL << 33) < 1ULL << 34
+             && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+           {
+             offset = rel->r_offset;
+             pinsn = bfd_get_32 (input_bfd, contents + offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + offset + 4);
+             if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
+                  == ((1ULL << 58) | (1ULL << 52) | (57ULL << 26) /* pld */))
+               {
+                 /* Replace with paddi.  */
+                 pinsn += (2ULL << 56) + (14ULL << 26) - (57ULL << 26);
+                 r_type = R_PPC64_PCREL34;
+                 rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+                 bfd_put_32 (input_bfd, pinsn >> 32, contents + offset);
+                 bfd_put_32 (input_bfd, pinsn, contents + offset + 4);
+                 goto pcrelopt;
+               }
+           }
+         break;
+
+       case R_PPC64_PCREL34:
+         if (SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+           {
+             offset = rel->r_offset;
+             pinsn = bfd_get_32 (input_bfd, contents + offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + offset + 4);
+             if ((pinsn & ((-1ULL << 50) | (63ULL << 26)))
+                  == ((1ULL << 58) | (2ULL << 56) | (1ULL << 52)
+                      | (14ULL << 26) /* paddi */))
+               {
+               pcrelopt:
+                 if (rel + 1 < relend
+                     && rel[1].r_offset == offset
+                     && rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT))
+                   {
+                     bfd_vma off2 = rel[1].r_addend;
+                     if (off2 == 0)
+                       /* zero means next insn.  */
+                       off2 = 8;
+                     off2 += offset;
+                     if (off2 + 4 <= input_section->size)
+                       {
+                         uint64_t pinsn2;
+                         bfd_signed_vma addend_off;
+                         pinsn2 = bfd_get_32 (input_bfd, contents + off2);
+                         pinsn2 <<= 32;
+                         if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+                           {
+                             if (off2 + 8 > input_section->size)
+                               break;
+                             pinsn2 |= bfd_get_32 (input_bfd,
+                                                   contents + off2 + 4);
+                           }
+                         if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
+                           {
+                             addend += addend_off;
+                             rel->r_addend = addend;
+                             bfd_put_32 (input_bfd, pinsn >> 32,
+                                         contents + offset);
+                             bfd_put_32 (input_bfd, pinsn,
+                                         contents + offset + 4);
+                             bfd_put_32 (input_bfd, pinsn2 >> 32,
+                                         contents + off2);
+                             if ((pinsn2 & (63ULL << 58)) == 1ULL << 58)
+                               bfd_put_32 (input_bfd, pinsn2,
+                                           contents + off2 + 4);
+                           }
+                       }
+                   }
+               }
+           }
+         break;
        }
 
-      /* Set `addend'.  */
       tls_type = 0;
       save_unresolved_reloc = unresolved_reloc;
       switch (r_type)
@@ -14421,6 +15568,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
        case R_PPC64_ENTRY:
+       case R_PPC64_PCREL_OPT:
          goto copy_reloc;
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
@@ -14431,6 +15579,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSGD16_LO:
        case R_PPC64_GOT_TLSGD16_HI:
        case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TLSGD34:
          tls_type = TLS_TLS | TLS_GD;
          goto dogot;
 
@@ -14438,6 +15587,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
        case R_PPC64_GOT_TLSLD16_HA:
+       case R_PPC64_GOT_TLSLD34:
          tls_type = TLS_TLS | TLS_LD;
          goto dogot;
 
@@ -14445,6 +15595,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
+       case R_PPC64_GOT_TPREL34:
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogot;
 
@@ -14452,6 +15603,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_DTPREL16_LO_DS:
        case R_PPC64_GOT_DTPREL16_HI:
        case R_PPC64_GOT_DTPREL16_HA:
+       case R_PPC64_GOT_DTPREL34:
          tls_type = TLS_TLS | TLS_DTPREL;
          goto dogot;
 
@@ -14461,6 +15613,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT16_HA:
        case R_PPC64_GOT16_DS:
        case R_PPC64_GOT16_LO_DS:
+       case R_PPC64_GOT_PCREL34:
        dogot:
          {
            /* Relocation is to the entry for this symbol in the global
@@ -14472,8 +15625,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            struct got_entry *ent;
 
            if (tls_type == (TLS_TLS | TLS_LD)
-               && (h == NULL
-                   || !h->elf.def_dynamic))
+               && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
              ent = ppc64_tlsld_got (input_bfd);
            else
              {
@@ -14548,10 +15700,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                else if (indx != 0
                         || (bfd_link_pic (info)
                             && (h == NULL
-                                || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
-                                || (tls_type == (TLS_TLS | TLS_LD)
-                                    && !h->elf.def_dynamic))
-                            && !(tls_type == (TLS_TLS | TLS_TPREL)
+                                || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf))
+                            && !(tls_type != 0
                                  && bfd_link_executable (info)
                                  && SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
                  relgot = ppc64_elf_tdata (ent->owner)->relgot;
@@ -14560,7 +15710,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    outrel.r_offset = (got->output_section->vma
                                       + got->output_offset
                                       + off);
-                   outrel.r_addend = addend;
+                   outrel.r_addend = orig_rel.r_addend;
                    if (tls_type & (TLS_LD | TLS_GD))
                      {
                        outrel.r_addend = 0;
@@ -14573,7 +15723,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                            bfd_elf64_swap_reloca_out (output_bfd,
                                                       &outrel, loc);
                            outrel.r_offset += 8;
-                           outrel.r_addend = addend;
+                           outrel.r_addend = orig_rel.r_addend;
                            outrel.r_info
                              = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
                          }
@@ -14619,7 +15769,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   emitting a reloc.  */
                else
                  {
-                   relocation += addend;
+                   relocation += orig_rel.r_addend;
                    if (tls_type != 0)
                      {
                        if (htab->elf.tls_sec == NULL)
@@ -14650,7 +15800,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              abort ();
 
            relocation = got->output_section->vma + got->output_offset + off;
-           addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
+           addend = 0;
+           if (!(r_type == R_PPC64_GOT_PCREL34
+                 || r_type == R_PPC64_GOT_TLSGD34
+                 || r_type == R_PPC64_GOT_TLSLD34
+                 || r_type == R_PPC64_GOT_TPREL34
+                 || r_type == R_PPC64_GOT_DTPREL34))
+             addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
          }
          break;
 
@@ -14658,10 +15814,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLT16_HI:
        case R_PPC64_PLT16_LO:
        case R_PPC64_PLT16_LO_DS:
+       case R_PPC64_PLT_PCREL34:
+       case R_PPC64_PLT_PCREL34_NOTOC:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
        case R_PPC64_PLTSEQ:
+       case R_PPC64_PLTSEQ_NOTOC:
        case R_PPC64_PLTCALL:
+       case R_PPC64_PLTCALL_NOTOC:
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
          unresolved_reloc = TRUE;
@@ -14742,6 +15902,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC16_LO_DS:
        case R_PPC64_TOC16_HA:
          addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
+         if (h != NULL)
+           goto dodyn;
          break;
 
          /* Relocate against the beginning of the section.  */
@@ -14765,14 +15927,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_REL16_HIGHERA:
        case R_PPC64_REL16_HIGHEST:
        case R_PPC64_REL16_HIGHESTA:
+       case R_PPC64_REL16_HIGHER34:
+       case R_PPC64_REL16_HIGHERA34:
+       case R_PPC64_REL16_HIGHEST34:
+       case R_PPC64_REL16_HIGHESTA34:
        case R_PPC64_REL16DX_HA:
-         break;
-
        case R_PPC64_REL14:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
        case R_PPC64_REL24_NOTOC:
+       case R_PPC64_PCREL34:
+       case R_PPC64_PCREL28:
          break;
 
        case R_PPC64_TPREL16:
@@ -14787,6 +15953,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
+       case R_PPC64_TPREL34:
          if (h != NULL
              && h->elf.root.type == bfd_link_hash_undefweak
              && h->elf.dynindx == -1)
@@ -14822,6 +15989,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_DTPREL16_HIGHERA:
        case R_PPC64_DTPREL16_HIGHEST:
        case R_PPC64_DTPREL16_HIGHESTA:
+       case R_PPC64_DTPREL34:
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          break;
@@ -14867,12 +16035,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_ADDR16_LO:
        case R_PPC64_ADDR16_LO_DS:
+       case R_PPC64_ADDR16_HIGHER34:
+       case R_PPC64_ADDR16_HIGHERA34:
+       case R_PPC64_ADDR16_HIGHEST34:
+       case R_PPC64_ADDR16_HIGHESTA34:
        case R_PPC64_ADDR24:
        case R_PPC64_ADDR32:
        case R_PPC64_ADDR64:
        case R_PPC64_UADDR16:
        case R_PPC64_UADDR32:
        case R_PPC64_UADDR64:
+       case R_PPC64_D34:
+       case R_PPC64_D34_LO:
+       case R_PPC64_D34_HI30:
+       case R_PPC64_D34_HA30:
+       case R_PPC64_D28:
        dodyn:
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
@@ -14996,21 +16173,38 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        }
                      else
                        {
-                         asection *osec;
-
-                         osec = sec->output_section;
-                         indx = elf_section_data (osec)->dynindx;
+                         asection *osec = sec->output_section;
 
-                         if (indx == 0)
+                         if ((osec->flags & SEC_THREAD_LOCAL) != 0)
+                           {
+                             /* TLS symbol values are relative to the
+                                TLS segment.  Dynamic relocations for
+                                local TLS symbols therefore can't be
+                                reduced to a relocation against their
+                                section symbol because it holds the
+                                address of the section, not a value
+                                relative to the TLS segment.  We could
+                                change the .tdata dynamic section symbol
+                                to be zero value but STN_UNDEF works
+                                and is used elsewhere, eg. for TPREL64
+                                GOT relocs against local TLS symbols.  */
+                             osec = htab->elf.tls_sec;
+                             indx = 0;
+                           }
+                         else
                            {
-                             if ((osec->flags & SEC_READONLY) == 0
-                                 && htab->elf.data_index_section != NULL)
-                               osec = htab->elf.data_index_section;
-                             else
-                               osec = htab->elf.text_index_section;
                              indx = elf_section_data (osec)->dynindx;
+                             if (indx == 0)
+                               {
+                                 if ((osec->flags & SEC_READONLY) == 0
+                                     && htab->elf.data_index_section != NULL)
+                                   osec = htab->elf.data_index_section;
+                                 else
+                                   osec = htab->elf.text_index_section;
+                                 indx = elf_section_data (osec)->dynindx;
+                               }
+                             BFD_ASSERT (indx != 0);
                            }
-                         BFD_ASSERT (indx != 0);
 
                          /* We are turning this relocation into one
                             against a section symbol, so subtract out
@@ -15045,6 +16239,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
 
+             if (!warned_dynamic
+                 && !ppc64_glibc_dynamic_reloc (ELF64_R_TYPE (outrel.r_info)))
+               {
+                 info->callbacks->einfo
+                   /* xgettext:c-format */
+                   (_("%X%P: %pB: %s against %pT "
+                      "is not supported by glibc as a dynamic relocation\n"),
+                    input_bfd,
+                    ppc64_elf_howto_table[ELF64_R_TYPE (outrel.r_info)]->name,
+                    sym_name);
+                 warned_dynamic = TRUE;
+               }
+
              /* If this reloc is against an external symbol, it will
                 be computed at runtime, so there's no need to do
                 anything now.  However, for the sake of prelink ensure
@@ -15124,6 +16331,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             insn.  */
          break;
 
+       case R_PPC64_PLTCALL_NOTOC:
+         if (!unresolved_reloc)
+           htab->notoc_plt = 1;
+         /* Fall through.  */
        case R_PPC64_PLTCALL:
          if (unresolved_reloc)
            {
@@ -15132,12 +16343,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              insn = bfd_get_32 (input_bfd, p);
              insn &= 1;
              bfd_put_32 (input_bfd, B_DOT | insn, p);
-             bfd_put_32 (input_bfd, NOP, p + 4);
+             if (r_type == R_PPC64_PLTCALL)
+               bfd_put_32 (input_bfd, NOP, p + 4);
              unresolved_reloc = save_unresolved_reloc;
              r_type = R_PPC64_REL24;
            }
          break;
 
+       case R_PPC64_PLTSEQ_NOTOC:
        case R_PPC64_PLTSEQ:
          if (unresolved_reloc)
            {
@@ -15146,6 +16359,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
+       case R_PPC64_PLT_PCREL34_NOTOC:
+         if (!unresolved_reloc)
+           htab->notoc_plt = 1;
+         /* Fall through.  */
+       case R_PPC64_PLT_PCREL34:
+         if (unresolved_reloc)
+           {
+             bfd_byte *p = contents + rel->r_offset;
+             bfd_put_32 (input_bfd, PNOP >> 32, p);
+             bfd_put_32 (input_bfd, PNOP, p + 4);
+             unresolved_reloc = FALSE;
+             goto copy_reloc;
+           }
+         break;
+
        case R_PPC64_PLT16_HA:
          if (unresolved_reloc)
            {
@@ -15191,10 +16419,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
-             if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+             if ((insn & (0x3fu << 26)) == 12u << 26 /* addic */)
                {
                  /* Transform addic to addi when we change reg.  */
-                 insn &= ~((0x3f << 26) | (0x1f << 16));
+                 insn &= ~((0x3fu << 26) | (0x1f << 16));
                  insn |= (14u << 26) | (2 << 16);
                }
              else
@@ -15211,7 +16439,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
-             if ((insn & ((0x3f << 26) | 0x1f << 16))
+             if ((insn & ((0x3fu << 26) | 0x1f << 16))
                  != ((15u << 26) | (13 << 16)) /* addis rt,13,imm */)
                /* xgettext:c-format */
                info->callbacks->minfo
@@ -15284,6 +16512,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          addend += 0x8000;
          break;
 
+       case R_PPC64_D34_HA30:
+       case R_PPC64_ADDR16_HIGHERA34:
+       case R_PPC64_ADDR16_HIGHESTA34:
+       case R_PPC64_REL16_HIGHERA34:
+       case R_PPC64_REL16_HIGHESTA34:
+         if (sec != NULL)
+           addend += 1ULL << 33;
+         break;
+
        case R_PPC64_ADDR16_DS:
        case R_PPC64_ADDR16_LO_DS:
        case R_PPC64_GOT16_DS:
@@ -15311,8 +16548,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             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))
+         if ((insn & (0x3fu << 26)) == (56u << 26)
+             || ((insn & (0x3fu << 26)) == (61u << 26) && (insn & 3) == 1))
            mask = 15;
          relocation += addend;
          addend = insn & (mask ^ 3);
@@ -15361,15 +16598,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          enum complain_overflow complain = complain_overflow_signed;
 
          insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
-         if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+         if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */)
            complain = complain_overflow_bitfield;
          else if (howto->rightshift == 0
-                  ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
-                     || (insn & (0x3f << 26)) == 24u << 26 /* ori */
-                     || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
-                  : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
-                     || (insn & (0x3f << 26)) == 25u << 26 /* oris */
-                     || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+                  ? ((insn & (0x3fu << 26)) == 28u << 26 /* andi */
+                     || (insn & (0x3fu << 26)) == 24u << 26 /* ori */
+                     || (insn & (0x3fu << 26)) == 26u << 26 /* xori */)
+                  : ((insn & (0x3fu << 26)) == 29u << 26 /* andis */
+                     || (insn & (0x3fu << 26)) == 25u << 26 /* oris */
+                     || (insn & (0x3fu << 26)) == 27u << 26 /* xoris */))
            complain = complain_overflow_unsigned;
          if (howto->complain_on_overflow != complain)
            {
@@ -15379,9 +16616,54 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
        }
 
-      if (r_type == R_PPC64_REL16DX_HA)
+      switch (r_type)
        {
-         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         /* Split field relocs aren't handled by _bfd_final_link_relocate.  */
+       case R_PPC64_D34:
+       case R_PPC64_D34_LO:
+       case R_PPC64_D34_HI30:
+       case R_PPC64_D34_HA30:
+       case R_PPC64_PCREL34:
+       case R_PPC64_GOT_PCREL34:
+       case R_PPC64_TPREL34:
+       case R_PPC64_DTPREL34:
+       case R_PPC64_GOT_TLSGD34:
+       case R_PPC64_GOT_TLSLD34:
+       case R_PPC64_GOT_TPREL34:
+       case R_PPC64_GOT_DTPREL34:
+       case R_PPC64_PLT_PCREL34:
+       case R_PPC64_PLT_PCREL34_NOTOC:
+       case R_PPC64_D28:
+       case R_PPC64_PCREL28:
+         if (rel->r_offset + 8 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             relocation += addend;
+             if (howto->pc_relative)
+               relocation -= (rel->r_offset
+                              + input_section->output_offset
+                              + input_section->output_section->vma);
+             relocation >>= howto->rightshift;
+
+             pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             pinsn <<= 32;
+             pinsn |= bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
+
+             pinsn &= ~howto->dst_mask;
+             pinsn |= (((relocation << 16) | (relocation & 0xffff))
+                       & howto->dst_mask);
+             bfd_put_32 (input_bfd, pinsn >> 32, contents + rel->r_offset);
+             bfd_put_32 (input_bfd, pinsn, contents + rel->r_offset + 4);
+             r = bfd_reloc_ok;
+             if (howto->complain_on_overflow == complain_overflow_signed
+                 && (relocation + (1ULL << (howto->bitsize - 1))
+                     >= 1ULL << howto->bitsize))
+               r = bfd_reloc_overflow;
+           }
+         break;
+
+       case R_PPC64_REL16DX_HA:
          if (rel->r_offset + 4 > input_section->size)
            r = bfd_reloc_outofrange;
          else
@@ -15399,10 +16681,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (relocation + 0x8000 > 0xffff)
                r = bfd_reloc_overflow;
            }
+         break;
+
+       default:
+         r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                       contents, rel->r_offset,
+                                       relocation, addend);
        }
-      else
-       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
@@ -15565,18 +16850,18 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
          break;
        }
 
-  if (h->needs_copy)
+  if (h->needs_copy
+      && (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak)
+      && (h->root.u.def.section == htab->elf.sdynbss
+         || h->root.u.def.section == htab->elf.sdynrelro))
     {
       /* This symbol needs a copy reloc.  Set it up.  */
       Elf_Internal_Rela rela;
       asection *srel;
       bfd_byte *loc;
 
-      if (h->dynindx == -1
-         || (h->root.type != bfd_link_hash_defined
-             && h->root.type != bfd_link_hash_defweak)
-         || htab->elf.srelbss == NULL
-         || htab->elf.sreldynrelro == NULL)
+      if (h->dynindx == -1)
        abort ();
 
       rela.r_offset = (h->root.u.def.value
@@ -15680,7 +16965,8 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_PPC64_OPT:
-             if (htab->do_multi_toc && htab->multi_toc_needed)
+             if ((htab->do_multi_toc && htab->multi_toc_needed)
+                 || htab->notoc_plt)
                dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC;
              if (htab->has_plt_localentry0)
                dyn.d_un.d_val |= PPC64_OPT_LOCALENTRY;
This page took 0.064948 seconds and 4 git commands to generate.