binutils 2.38 vs. ppc32 linux kernel
[binutils-gdb.git] / bfd / elf64-ppc.c
index 05ef34b030ac551cc3158080451bf31853720837..dd79c05bb6161ef3bc5194a4dc043af27ceea5a4 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright (C) 1999-2020 Free Software Foundation, Inc.
+   Copyright (C) 1999-2022 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
    Largely rewritten by Alan Modra.
    http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and
    http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html  */
 
+/* The assembler should generate a full set of section symbols even
+   when they appear unused.  The linux kernel build tool recordmcount
+   needs them.  */
+#define TARGET_KEEP_UNUSED_SECTION_SYMBOLS true
+
 #include "sysdep.h"
 #include <stdarg.h>
 #include "bfd.h"
@@ -59,7 +64,7 @@ static bfd_reloc_status_type ppc64_elf_prefix_reloc
 static bfd_reloc_status_type ppc64_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_vma opd_entry_value
-  (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
+  (asection *, bfd_vma, asection **, bfd_vma *, bool);
 
 #define TARGET_LITTLE_SYM      powerpc_elf64_le_vec
 #define TARGET_LITTLE_NAME     "elf64-powerpcle"
@@ -70,7 +75,6 @@ static bfd_vma opd_entry_value
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
 #define ELF_COMMONPAGESIZE     0x1000
-#define ELF_RELROPAGESIZE      ELF_MAXPAGESIZE
 #define elf_info_to_howto      ppc64_elf_info_to_howto
 
 #define elf_backend_want_got_sym 0
@@ -114,7 +118,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_adjust_dynamic_symbol     ppc64_elf_adjust_dynamic_symbol
 #define elf_backend_hide_symbol                      ppc64_elf_hide_symbol
 #define elf_backend_maybe_function_sym       ppc64_elf_maybe_function_sym
-#define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
+#define elf_backend_always_size_sections      ppc64_elf_edit
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
 #define elf_backend_hash_symbol                      ppc64_elf_hash_symbol
 #define elf_backend_init_index_section       _bfd_elf_init_2_index_sections
@@ -211,9 +215,10 @@ static bfd_vma opd_entry_value
 #define PLD_R12_PC     0x04100000e5800000ULL
 #define PNOP           0x0700000000000000ULL
 
-/* __glink_PLTresolve stub instructions.  We enter with the index in R0.  */
+/* __glink_PLTresolve stub instructions.  We enter with the index in
+   R0 for ELFv1, and the address of a glink branch in R12 for ELFv2.  */
 #define GLINK_PLTRESOLVE_SIZE(htab)                    \
-  (8u + (htab->opd_abi ? 11 * 4 : 14 * 4))
+  (8u + (htab->opd_abi ? 11 * 4 : htab->has_plt_localentry0 ? 14 * 4 : 13 * 4))
                                        /* 0:                           */
                                        /*  .quad plt0-1f               */
                                        /* __glink:                     */
@@ -229,11 +234,14 @@ static bfd_vma opd_entry_value
                                        /*  mtctr %12                   */
                                        /*  ld %11,16(%11)              */
                                        /*  bctr                        */
-#define MFLR_R0                0x7c0802a6      /*  mflr %r0                    */
-#define MTLR_R0                0x7c0803a6      /*  mtlr %r0                    */
-#define SUB_R12_R12_R11        0x7d8b6050      /*  subf %r12,%r11,%r12         */
-#define ADDI_R0_R12    0x380c0000      /*  addi %r0,%r12,0             */
-#define SRDI_R0_R0_2   0x7800f082      /*  rldicl %r0,%r0,62,2         */
+
+#define MFLR_R0                0x7c0802a6      /* mflr %r0                     */
+#define MTLR_R0                0x7c0803a6      /* mtlr %r0                     */
+#define SUB_R12_R12_R11        0x7d8b6050      /* subf %r12,%r11,%r12          */
+#define ADDI_R0_R12    0x380c0000      /* addi %r0,%r12,0              */
+#define SRDI_R0_R0_2   0x7800f082      /* rldicl %r0,%r0,62,2          */
+#define LD_R0_0R11     0xe80b0000      /* ld %r0,0(%r11)               */
+#define ADD_R11_R0_R11 0x7d605a14      /* add %r11,%r0,%r11            */
 
 /* Pad with this.  */
 #define NOP            0x60000000
@@ -301,101 +309,105 @@ set_abiversion (bfd *abfd, int ver)
            complain, special_func)                             \
   HOWTO (type, rightshift, size, bitsize, pc_relative, 0,      \
         complain_overflow_ ## complain, special_func,          \
-        #type, FALSE, 0, mask, pc_relative)
+        #type, false, 0, mask, pc_relative)
 
 static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC64_max];
 
 static reloc_howto_type ppc64_elf_howto_raw[] =
 {
   /* This reloc does nothing.  */
-  HOW (R_PPC64_NONE, 3, 0, 0, 0, FALSE, dont,
+  HOW (R_PPC64_NONE, 3, 0, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* A standard 32 bit relocation.  */
-  HOW (R_PPC64_ADDR32, 2, 32, 0xffffffff, 0, FALSE, bitfield,
+  HOW (R_PPC64_ADDR32, 2, 32, 0xffffffff, 0, false, bitfield,
        bfd_elf_generic_reloc),
 
   /* An absolute 26 bit branch; the lower two bits must be zero.
      FIXME: we don't check that, we just clear them.  */
-  HOW (R_PPC64_ADDR24, 2, 26, 0x03fffffc, 0, FALSE, bitfield,
+  HOW (R_PPC64_ADDR24, 2, 26, 0x03fffffc, 0, false, bitfield,
        bfd_elf_generic_reloc),
 
   /* A standard 16 bit relocation.  */
-  HOW (R_PPC64_ADDR16, 1, 16, 0xffff, 0, FALSE, bitfield,
+  HOW (R_PPC64_ADDR16, 1, 16, 0xffff, 0, false, bitfield,
        bfd_elf_generic_reloc),
 
   /* A 16 bit relocation without overflow.  */
-  HOW (R_PPC64_ADDR16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_ADDR16_LO, 1, 16, 0xffff, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Bits 16-31 of an address.  */
-  HOW (R_PPC64_ADDR16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_ADDR16_HI, 1, 16, 0xffff, 16, false, signed,
        bfd_elf_generic_reloc),
 
   /* Bits 16-31 of an address, plus 1 if the contents of the low 16
      bits, treated as a signed number, is negative.  */
-  HOW (R_PPC64_ADDR16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_ADDR16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_ha_reloc),
 
   /* An absolute 16 bit branch; the lower two bits must be zero.
      FIXME: we don't check that, we just clear them.  */
-  HOW (R_PPC64_ADDR14, 2, 16, 0x0000fffc, 0, FALSE, signed,
+  HOW (R_PPC64_ADDR14, 2, 16, 0x0000fffc, 0, false, signed,
        ppc64_elf_branch_reloc),
 
   /* An absolute 16 bit branch, for which bit 10 should be set to
      indicate that the branch is expected to be taken.  The lower two
      bits must be zero.  */
-  HOW (R_PPC64_ADDR14_BRTAKEN, 2, 16, 0x0000fffc, 0, FALSE, signed,
+  HOW (R_PPC64_ADDR14_BRTAKEN, 2, 16, 0x0000fffc, 0, false, signed,
        ppc64_elf_brtaken_reloc),
 
   /* An absolute 16 bit branch, for which bit 10 should be set to
      indicate that the branch is not expected to be taken.  The lower
      two bits must be zero.  */
-  HOW (R_PPC64_ADDR14_BRNTAKEN, 2, 16, 0x0000fffc, 0, FALSE, signed,
+  HOW (R_PPC64_ADDR14_BRNTAKEN, 2, 16, 0x0000fffc, 0, false, signed,
        ppc64_elf_brtaken_reloc),
 
   /* A relative 26 bit branch; the lower two bits must be zero.  */
-  HOW (R_PPC64_REL24, 2, 26, 0x03fffffc, 0, TRUE, signed,
+  HOW (R_PPC64_REL24, 2, 26, 0x03fffffc, 0, true, signed,
        ppc64_elf_branch_reloc),
 
   /* A variant of R_PPC64_REL24, used when r2 is not the toc pointer.  */
-  HOW (R_PPC64_REL24_NOTOC, 2, 26, 0x03fffffc, 0, TRUE, signed,
+  HOW (R_PPC64_REL24_NOTOC, 2, 26, 0x03fffffc, 0, true, signed,
+       ppc64_elf_branch_reloc),
+
+  /* Another variant, when p10 insns can't be used on stubs.  */
+  HOW (R_PPC64_REL24_P9NOTOC, 2, 26, 0x03fffffc, 0, true, signed,
        ppc64_elf_branch_reloc),
 
   /* A relative 16 bit branch; the lower two bits must be zero.  */
-  HOW (R_PPC64_REL14, 2, 16, 0x0000fffc, 0, TRUE, signed,
+  HOW (R_PPC64_REL14, 2, 16, 0x0000fffc, 0, true, signed,
        ppc64_elf_branch_reloc),
 
   /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is expected to be taken.  The lower two bits must be
      zero.  */
-  HOW (R_PPC64_REL14_BRTAKEN, 2, 16, 0x0000fffc, 0, TRUE, signed,
+  HOW (R_PPC64_REL14_BRTAKEN, 2, 16, 0x0000fffc, 0, true, signed,
        ppc64_elf_brtaken_reloc),
 
   /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is not expected to be taken.  The lower two bits must
      be zero.  */
-  HOW (R_PPC64_REL14_BRNTAKEN, 2, 16, 0x0000fffc, 0, TRUE, signed,
+  HOW (R_PPC64_REL14_BRNTAKEN, 2, 16, 0x0000fffc, 0, true, signed,
        ppc64_elf_brtaken_reloc),
 
   /* Like R_PPC64_ADDR16, but referring to the GOT table entry for the
      symbol.  */
-  HOW (R_PPC64_GOT16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_GOT16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_LO, but referring to the GOT table entry for
      the symbol.  */
-  HOW (R_PPC64_GOT16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_GOT16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_HI, but referring to the GOT table entry for
      the symbol.  */
-  HOW (R_PPC64_GOT16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_HA, but referring to the GOT table entry for
      the symbol.  */
-  HOW (R_PPC64_GOT16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* This is used only by the dynamic linker.  The symbol should exist
@@ -403,148 +415,148 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
      dynamic linker copies the data addressed by the symbol from the
      shared library into the object, because the object being
      run has to have the data at some particular address.  */
-  HOW (R_PPC64_COPY, 0, 0, 0, 0, FALSE, dont,
+  HOW (R_PPC64_COPY, 0, 0, 0, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR64, but used when setting global offset table
      entries.  */
-  HOW (R_PPC64_GLOB_DAT, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_GLOB_DAT, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Created by the link editor.  Marks a procedure linkage table
      entry for a symbol.  */
-  HOW (R_PPC64_JMP_SLOT, 0, 0, 0, 0, FALSE, dont,
+  HOW (R_PPC64_JMP_SLOT, 0, 0, 0, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Used only by the dynamic linker.  When the object is run, this
      doubleword64 is set to the load address of the object, plus the
      addend.  */
-  HOW (R_PPC64_RELATIVE, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_RELATIVE, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Like R_PPC64_ADDR32, but may be unaligned.  */
-  HOW (R_PPC64_UADDR32, 2, 32, 0xffffffff, 0, FALSE, bitfield,
+  HOW (R_PPC64_UADDR32, 2, 32, 0xffffffff, 0, false, bitfield,
        bfd_elf_generic_reloc),
 
   /* Like R_PPC64_ADDR16, but may be unaligned.  */
-  HOW (R_PPC64_UADDR16, 1, 16, 0xffff, 0, FALSE, bitfield,
+  HOW (R_PPC64_UADDR16, 1, 16, 0xffff, 0, false, bitfield,
        bfd_elf_generic_reloc),
 
   /* 32-bit PC relative.  */
-  HOW (R_PPC64_REL32, 2, 32, 0xffffffff, 0, TRUE, signed,
+  HOW (R_PPC64_REL32, 2, 32, 0xffffffff, 0, true, signed,
        bfd_elf_generic_reloc),
 
   /* 32-bit relocation to the symbol's procedure linkage table.  */
-  HOW (R_PPC64_PLT32, 2, 32, 0xffffffff, 0, FALSE, bitfield,
+  HOW (R_PPC64_PLT32, 2, 32, 0xffffffff, 0, false, bitfield,
        ppc64_elf_unhandled_reloc),
 
   /* 32-bit PC relative relocation to the symbol's procedure linkage table.
      FIXME: R_PPC64_PLTREL32 not supported.  */
-  HOW (R_PPC64_PLTREL32, 2, 32, 0xffffffff, 0, TRUE, signed,
+  HOW (R_PPC64_PLTREL32, 2, 32, 0xffffffff, 0, true, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_LO, but referring to the PLT table entry for
      the symbol.  */
-  HOW (R_PPC64_PLT16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_PLT16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_HI, but referring to the PLT table entry for
      the symbol.  */
-  HOW (R_PPC64_PLT16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_PLT16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16_HA, but referring to the PLT table entry for
      the symbol.  */
-  HOW (R_PPC64_PLT16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_PLT16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* 16-bit section relative relocation.  */
-  HOW (R_PPC64_SECTOFF, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_SECTOFF, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_sectoff_reloc),
 
   /* Like R_PPC64_SECTOFF, but no overflow warning.  */
-  HOW (R_PPC64_SECTOFF_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_SECTOFF_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_sectoff_reloc),
 
   /* 16-bit upper half section relative relocation.  */
-  HOW (R_PPC64_SECTOFF_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_SECTOFF_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_sectoff_reloc),
 
   /* 16-bit upper half adjusted section relative relocation.  */
-  HOW (R_PPC64_SECTOFF_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_SECTOFF_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_sectoff_ha_reloc),
 
   /* Like R_PPC64_REL24 without touching the two least significant bits.  */
-  HOW (R_PPC64_REL30, 2, 30, 0xfffffffc, 2, TRUE, dont,
+  HOW (R_PPC64_REL30, 2, 30, 0xfffffffc, 2, true, dont,
        bfd_elf_generic_reloc),
 
   /* Relocs in the 64-bit PowerPC ELF ABI, not in the 32-bit ABI.  */
 
   /* A standard 64-bit relocation.  */
-  HOW (R_PPC64_ADDR64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_ADDR64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* The bits 32-47 of an address.  */
-  HOW (R_PPC64_ADDR16_HIGHER, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGHER, 1, 16, 0xffff, 32, false, dont,
        bfd_elf_generic_reloc),
 
   /* The bits 32-47 of an address, plus 1 if the contents of the low
      16 bits, treated as a signed number, is negative.  */
-  HOW (R_PPC64_ADDR16_HIGHERA, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGHERA, 1, 16, 0xffff, 32, false, dont,
        ppc64_elf_ha_reloc),
 
   /* The bits 48-63 of an address.  */
-  HOW (R_PPC64_ADDR16_HIGHEST, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGHEST, 1, 16, 0xffff, 48, false, dont,
        bfd_elf_generic_reloc),
 
   /* The bits 48-63 of an address, plus 1 if the contents of the low
      16 bits, treated as a signed number, is negative.  */
-  HOW (R_PPC64_ADDR16_HIGHESTA, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGHESTA, 1, 16, 0xffff, 48, false, dont,
        ppc64_elf_ha_reloc),
 
   /* Like ADDR64, but may be unaligned.  */
-  HOW (R_PPC64_UADDR64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_UADDR64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* 64-bit relative relocation.  */
-  HOW (R_PPC64_REL64, 4, 64, 0xffffffffffffffffULL, 0, TRUE, dont,
+  HOW (R_PPC64_REL64, 4, 64, 0xffffffffffffffffULL, 0, true, dont,
        bfd_elf_generic_reloc),
 
   /* 64-bit relocation to the symbol's procedure linkage table.  */
-  HOW (R_PPC64_PLT64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_PLT64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* 64-bit PC relative relocation to the symbol's procedure linkage
      table.  */
   /* FIXME: R_PPC64_PLTREL64 not supported.  */
-  HOW (R_PPC64_PLTREL64, 4, 64, 0xffffffffffffffffULL, 0, TRUE, dont,
+  HOW (R_PPC64_PLTREL64, 4, 64, 0xffffffffffffffffULL, 0, true, dont,
        ppc64_elf_unhandled_reloc),
 
   /* 16 bit TOC-relative relocation.  */
   /* R_PPC64_TOC16       47       half16*      S + A - .TOC.  */
-  HOW (R_PPC64_TOC16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_TOC16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_toc_reloc),
 
   /* 16 bit TOC-relative relocation without overflow.  */
   /* R_PPC64_TOC16_LO    48       half16        #lo (S + A - .TOC.)  */
-  HOW (R_PPC64_TOC16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_TOC16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_toc_reloc),
 
   /* 16 bit TOC-relative relocation, high 16 bits.  */
   /* R_PPC64_TOC16_HI    49       half16        #hi (S + A - .TOC.)  */
-  HOW (R_PPC64_TOC16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_TOC16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_toc_reloc),
 
   /* 16 bit TOC-relative relocation, high 16 bits, plus 1 if the
      contents of the low 16 bits, treated as a signed number, is
      negative.  */
   /* R_PPC64_TOC16_HA    50       half16        #ha (S + A - .TOC.)  */
-  HOW (R_PPC64_TOC16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_TOC16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_toc_ha_reloc),
 
   /* 64-bit relocation; insert value of TOC base (.TOC.).  */
   /* R_PPC64_TOC                 51       doubleword64  .TOC.  */
-  HOW (R_PPC64_TOC, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_TOC, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_toc64_reloc),
 
   /* Like R_PPC64_GOT16, but also informs the link editor that the
@@ -556,428 +568,428 @@ static reloc_howto_type ppc64_elf_howto_raw[] =
      The link editor may also skip all of this and just (c) emit a
      R_PPC64_GLOB_DAT to tie the symbol to the GOT entry.  */
   /* FIXME: R_PPC64_PLTGOT16 not implemented.  */
-    HOW (R_PPC64_PLTGOT16, 1, 16, 0xffff, 0, FALSE,signed,
+    HOW (R_PPC64_PLTGOT16, 1, 16, 0xffff, 0, false,signed,
          ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_PLTGOT16, but without overflow.  */
   /* FIXME: R_PPC64_PLTGOT16_LO not implemented.  */
-  HOW (R_PPC64_PLTGOT16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_PLTGOT16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address.  */
   /* FIXME: R_PPC64_PLTGOT16_HI not implemented.  */
-  HOW (R_PPC64_PLTGOT16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_PLTGOT16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address, plus
      1 if the contents of the low 16 bits, treated as a signed number,
      is negative.  */
   /* FIXME: R_PPC64_PLTGOT16_HA not implemented.  */
-  HOW (R_PPC64_PLTGOT16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_PLTGOT16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_ADDR16, but for instructions with a DS field.  */
-  HOW (R_PPC64_ADDR16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_ADDR16_DS, 1, 16, 0xfffc, 0, false, signed,
        bfd_elf_generic_reloc),
 
   /* Like R_PPC64_ADDR16_LO, but for instructions with a DS field.  */
-  HOW (R_PPC64_ADDR16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_ADDR16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Like R_PPC64_GOT16, but for instructions with a DS field.  */
-  HOW (R_PPC64_GOT16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_GOT16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_GOT16_LO, but for instructions with a DS field.  */
-  HOW (R_PPC64_GOT16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_GOT16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_PLT16_LO, but for instructions with a DS field.  */
-  HOW (R_PPC64_PLT16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_PLT16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_SECTOFF, but for instructions with a DS field.  */
-  HOW (R_PPC64_SECTOFF_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_SECTOFF_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_sectoff_reloc),
 
   /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field.  */
-  HOW (R_PPC64_SECTOFF_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_SECTOFF_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_sectoff_reloc),
 
   /* Like R_PPC64_TOC16, but for instructions with a DS field.  */
-  HOW (R_PPC64_TOC16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_TOC16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_toc_reloc),
 
   /* Like R_PPC64_TOC16_LO, but for instructions with a DS field.  */
-  HOW (R_PPC64_TOC16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_TOC16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_toc_reloc),
 
   /* Like R_PPC64_PLTGOT16, but for instructions with a DS field.  */
   /* FIXME: R_PPC64_PLTGOT16_DS not implemented.  */
-  HOW (R_PPC64_PLTGOT16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_PLTGOT16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_PLTGOT16_LO, but for instructions with a DS field.  */
   /* FIXME: R_PPC64_PLTGOT16_LO not implemented.  */
-  HOW (R_PPC64_PLTGOT16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_PLTGOT16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Marker relocs for TLS.  */
-  HOW (R_PPC64_TLS, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_TLS, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_TLSGD, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_TLSGD, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_TLSLD, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_TLSLD, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Marker reloc for optimizing r2 save in prologue rather than on
      each plt call stub.  */
-  HOW (R_PPC64_TOCSAVE, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_TOCSAVE, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Marker relocs on inline plt call instructions.  */
-  HOW (R_PPC64_PLTSEQ, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_PLTSEQ, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_PLTCALL, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_PLTCALL, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
-  HOW (R_PPC64_DTPMOD64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_DTPMOD64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Computes a dtv-relative displacement, the difference between the value
      of sym+add and the base address of the thread-local storage block that
      contains the definition of sym, minus 0x8000.  */
-  HOW (R_PPC64_DTPREL64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_DTPREL64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* A 16 bit dtprel reloc.  */
-  HOW (R_PPC64_DTPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_DTPREL16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16, but no overflow.  */
-  HOW (R_PPC64_DTPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_LO, but next higher group of 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_DTPREL16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_DTPREL16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_HI, but next higher group of 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HIGHER, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGHER, 1, 16, 0xffff, 32, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_HIGHER, but adjust for low 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HIGHERA, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGHERA, 1, 16, 0xffff, 32, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_HIGHER, but next higher group of 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HIGHEST, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGHEST, 1, 16, 0xffff, 48, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_HIGHEST, but adjust for low 16 bits.  */
-  HOW (R_PPC64_DTPREL16_HIGHESTA, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGHESTA, 1, 16, 0xffff, 48, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16, but for insns with a DS field.  */
-  HOW (R_PPC64_DTPREL16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_DTPREL16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like DTPREL16_DS, but no overflow.  */
-  HOW (R_PPC64_DTPREL16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Computes a tp-relative displacement, the difference between the value of
      sym+add and the value of the thread pointer (r13).  */
-  HOW (R_PPC64_TPREL64, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_TPREL64, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* A 16 bit tprel reloc.  */
-  HOW (R_PPC64_TPREL16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_TPREL16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16, but no overflow.  */
-  HOW (R_PPC64_TPREL16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_TPREL16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_LO, but next higher group of 16 bits.  */
-  HOW (R_PPC64_TPREL16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_TPREL16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_TPREL16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_TPREL16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_HI, but next higher group of 16 bits.  */
-  HOW (R_PPC64_TPREL16_HIGHER, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGHER, 1, 16, 0xffff, 32, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_HIGHER, but adjust for low 16 bits.  */
-  HOW (R_PPC64_TPREL16_HIGHERA, 1, 16, 0xffff, 32, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGHERA, 1, 16, 0xffff, 32, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_HIGHER, but next higher group of 16 bits.  */
-  HOW (R_PPC64_TPREL16_HIGHEST, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGHEST, 1, 16, 0xffff, 48, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_HIGHEST, but adjust for low 16 bits.  */
-  HOW (R_PPC64_TPREL16_HIGHESTA, 1, 16, 0xffff, 48, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGHESTA, 1, 16, 0xffff, 48, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16, but for insns with a DS field.  */
-  HOW (R_PPC64_TPREL16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_TPREL16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like TPREL16_DS, but no overflow.  */
-  HOW (R_PPC64_TPREL16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_TPREL16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
      with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
      to the first entry relative to the TOC base (r2).  */
-  HOW (R_PPC64_GOT_TLSGD16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSGD16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16, but no overflow.  */
-  HOW (R_PPC64_GOT_TLSGD16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_GOT_TLSGD16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16_LO, but next higher group of 16 bits.  */
-  HOW (R_PPC64_GOT_TLSGD16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSGD16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_GOT_TLSGD16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSGD16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
      with values (sym+add)@dtpmod and zero, and computes the offset to the
      first entry relative to the TOC base (r2).  */
-  HOW (R_PPC64_GOT_TLSLD16, 1, 16, 0xffff, 0, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSLD16, 1, 16, 0xffff, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16, but no overflow.  */
-  HOW (R_PPC64_GOT_TLSLD16_LO, 1, 16, 0xffff, 0, FALSE, dont,
+  HOW (R_PPC64_GOT_TLSLD16_LO, 1, 16, 0xffff, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16_LO, but next higher group of 16 bits.  */
-  HOW (R_PPC64_GOT_TLSLD16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSLD16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_GOT_TLSLD16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TLSLD16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
      the offset to the entry relative to the TOC base (r2).  */
-  HOW (R_PPC64_GOT_DTPREL16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_GOT_DTPREL16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16_DS, but no overflow.  */
-  HOW (R_PPC64_GOT_DTPREL16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_GOT_DTPREL16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16_LO_DS, but next higher group of 16 bits.  */
-  HOW (R_PPC64_GOT_DTPREL16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_DTPREL16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_GOT_DTPREL16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_DTPREL16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
      offset to the entry relative to the TOC base (r2).  */
-  HOW (R_PPC64_GOT_TPREL16_DS, 1, 16, 0xfffc, 0, FALSE, signed,
+  HOW (R_PPC64_GOT_TPREL16_DS, 1, 16, 0xfffc, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16_DS, but no overflow.  */
-  HOW (R_PPC64_GOT_TPREL16_LO_DS, 1, 16, 0xfffc, 0, FALSE, dont,
+  HOW (R_PPC64_GOT_TPREL16_LO_DS, 1, 16, 0xfffc, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16_LO_DS, but next higher group of 16 bits.  */
-  HOW (R_PPC64_GOT_TPREL16_HI, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TPREL16_HI, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16_HI, but adjust for low 16 bits.  */
-  HOW (R_PPC64_GOT_TPREL16_HA, 1, 16, 0xffff, 16, FALSE, signed,
+  HOW (R_PPC64_GOT_TPREL16_HA, 1, 16, 0xffff, 16, false, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_JMP_IREL, 0, 0, 0, 0, FALSE, dont,
+  HOW (R_PPC64_JMP_IREL, 0, 0, 0, 0, false, dont,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_IRELATIVE, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  HOW (R_PPC64_IRELATIVE, 4, 64, 0xffffffffffffffffULL, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* A 16 bit relative relocation.  */
-  HOW (R_PPC64_REL16, 1, 16, 0xffff, 0, TRUE, signed,
+  HOW (R_PPC64_REL16, 1, 16, 0xffff, 0, true, signed,
        bfd_elf_generic_reloc),
 
   /* A 16 bit relative relocation without overflow.  */
-  HOW (R_PPC64_REL16_LO, 1, 16, 0xffff, 0, TRUE, dont,
+  HOW (R_PPC64_REL16_LO, 1, 16, 0xffff, 0, true, dont,
        bfd_elf_generic_reloc),
 
   /* The high order 16 bits of a relative address.  */
-  HOW (R_PPC64_REL16_HI, 1, 16, 0xffff, 16, TRUE, signed,
+  HOW (R_PPC64_REL16_HI, 1, 16, 0xffff, 16, true, signed,
        bfd_elf_generic_reloc),
 
   /* The high order 16 bits of a relative address, plus 1 if the contents of
      the low 16 bits, treated as a signed number, is negative.  */
-  HOW (R_PPC64_REL16_HA, 1, 16, 0xffff, 16, TRUE, signed,
+  HOW (R_PPC64_REL16_HA, 1, 16, 0xffff, 16, true, signed,
        ppc64_elf_ha_reloc),
 
-  HOW (R_PPC64_REL16_HIGH, 1, 16, 0xffff, 16, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGH, 1, 16, 0xffff, 16, true, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_REL16_HIGHA, 1, 16, 0xffff, 16, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGHA, 1, 16, 0xffff, 16, true, dont,
        ppc64_elf_ha_reloc),
 
-  HOW (R_PPC64_REL16_HIGHER, 1, 16, 0xffff, 32, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGHER, 1, 16, 0xffff, 32, true, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_REL16_HIGHERA, 1, 16, 0xffff, 32, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGHERA, 1, 16, 0xffff, 32, true, dont,
        ppc64_elf_ha_reloc),
 
-  HOW (R_PPC64_REL16_HIGHEST, 1, 16, 0xffff, 48, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGHEST, 1, 16, 0xffff, 48, true, dont,
        bfd_elf_generic_reloc),
 
-  HOW (R_PPC64_REL16_HIGHESTA, 1, 16, 0xffff, 48, TRUE, dont,
+  HOW (R_PPC64_REL16_HIGHESTA, 1, 16, 0xffff, 48, true, dont,
        ppc64_elf_ha_reloc),
 
   /* Like R_PPC64_REL16_HA but for split field in addpcis.  */
-  HOW (R_PPC64_REL16DX_HA, 2, 16, 0x1fffc1, 16, TRUE, signed,
+  HOW (R_PPC64_REL16DX_HA, 2, 16, 0x1fffc1, 16, true, signed,
        ppc64_elf_ha_reloc),
 
   /* A split-field reloc for addpcis, non-relative (gas internal use only).  */
-  HOW (R_PPC64_16DX_HA, 2, 16, 0x1fffc1, 16, FALSE, signed,
+  HOW (R_PPC64_16DX_HA, 2, 16, 0x1fffc1, 16, false, signed,
        ppc64_elf_ha_reloc),
 
   /* Like R_PPC64_ADDR16_HI, but no overflow.  */
-  HOW (R_PPC64_ADDR16_HIGH, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGH, 1, 16, 0xffff, 16, false, dont,
        bfd_elf_generic_reloc),
 
   /* Like R_PPC64_ADDR16_HA, but no overflow.  */
-  HOW (R_PPC64_ADDR16_HIGHA, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_ADDR16_HIGHA, 1, 16, 0xffff, 16, false, dont,
        ppc64_elf_ha_reloc),
 
   /* Like R_PPC64_DTPREL16_HI, but no overflow.  */
-  HOW (R_PPC64_DTPREL16_HIGH, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGH, 1, 16, 0xffff, 16, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_DTPREL16_HA, but no overflow.  */
-  HOW (R_PPC64_DTPREL16_HIGHA, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_DTPREL16_HIGHA, 1, 16, 0xffff, 16, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_TPREL16_HI, but no overflow.  */
-  HOW (R_PPC64_TPREL16_HIGH, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGH, 1, 16, 0xffff, 16, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Like R_PPC64_TPREL16_HA, but no overflow.  */
-  HOW (R_PPC64_TPREL16_HIGHA, 1, 16, 0xffff, 16, FALSE, dont,
+  HOW (R_PPC64_TPREL16_HIGHA, 1, 16, 0xffff, 16, false, dont,
        ppc64_elf_unhandled_reloc),
 
   /* Marker reloc on ELFv2 large-model function entry.  */
-  HOW (R_PPC64_ENTRY, 2, 32, 0, 0, FALSE, dont,
+  HOW (R_PPC64_ENTRY, 2, 32, 0, 0, false, dont,
        bfd_elf_generic_reloc),
 
   /* Like ADDR64, but use local entry point of function.  */
-  HOW (R_PPC64_ADDR64_LOCAL, 4, 64, 0xffffffffffffffffULL, 0, FALSE, dont,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  HOW (R_PPC64_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, false, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, FALSE, signed,
+  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,
+  HOW (R_PPC64_GOT_TLSGD_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, true, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_GOT_TLSLD34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+  HOW (R_PPC64_GOT_TLSLD_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, true, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_GOT_TPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+  HOW (R_PPC64_GOT_TPREL_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, true, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_GOT_DTPREL34, 4, 34, 0x3ffff0000ffffULL, 0, TRUE, signed,
+  HOW (R_PPC64_GOT_DTPREL_PCREL34, 4, 34, 0x3ffff0000ffffULL, 0, true, signed,
        ppc64_elf_unhandled_reloc),
 
-  HOW (R_PPC64_ADDR16_HIGHER34, 1, 16, 0xffff, 34, FALSE, dont,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  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,
+  HOW (R_PPC64_D28, 4, 28, 0xfff0000ffffULL, 0, false, signed,
        ppc64_elf_prefix_reloc),
 
-  HOW (R_PPC64_PCREL28, 4, 28, 0xfff0000ffffULL, 0, TRUE, signed,
+  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,
+  HOW (R_PPC64_GNU_VTINHERIT, 0, 0, 0, 0, false, dont,
        NULL),
 
   /* GNU extension to record C++ vtable member usage.  */
-  HOW (R_PPC64_GNU_VTENTRY, 0, 0, 0, 0, FALSE, dont,
+  HOW (R_PPC64_GNU_VTENTRY, 0, 0, 0, 0, false, dont,
        NULL),
 };
 
@@ -999,8 +1011,7 @@ ppc_howto_init (void)
 }
 
 static reloc_howto_type *
-ppc64_elf_reloc_type_lookup (bfd *abfd,
-                            bfd_reloc_code_real_type code)
+ppc64_elf_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
 {
   enum elf_ppc64_reloc_type r = R_PPC64_NONE;
 
@@ -1045,6 +1056,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
       break;
     case BFD_RELOC_PPC64_REL24_NOTOC:          r = R_PPC64_REL24_NOTOC;
       break;
+    case BFD_RELOC_PPC64_REL24_P9NOTOC:                r = R_PPC64_REL24_P9NOTOC;
+      break;
     case BFD_RELOC_PPC_B16:                    r = R_PPC64_REL14;
       break;
     case BFD_RELOC_PPC_B16_BRTAKEN:            r = R_PPC64_REL14_BRTAKEN;
@@ -1280,13 +1293,13 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
       break;
     case BFD_RELOC_PPC64_DTPREL34:             r = R_PPC64_DTPREL34;
       break;
-    case BFD_RELOC_PPC64_GOT_TLSGD34:          r = R_PPC64_GOT_TLSGD34;
+    case BFD_RELOC_PPC64_GOT_TLSGD_PCREL34:    r = R_PPC64_GOT_TLSGD_PCREL34;
       break;
-    case BFD_RELOC_PPC64_GOT_TLSLD34:          r = R_PPC64_GOT_TLSLD34;
+    case BFD_RELOC_PPC64_GOT_TLSLD_PCREL34:    r = R_PPC64_GOT_TLSLD_PCREL34;
       break;
-    case BFD_RELOC_PPC64_GOT_TPREL34:          r = R_PPC64_GOT_TPREL34;
+    case BFD_RELOC_PPC64_GOT_TPREL_PCREL34:    r = R_PPC64_GOT_TPREL_PCREL34;
       break;
-    case BFD_RELOC_PPC64_GOT_DTPREL34:         r = R_PPC64_GOT_DTPREL34;
+    case BFD_RELOC_PPC64_GOT_DTPREL_PCREL34:   r = R_PPC64_GOT_DTPREL_PCREL34;
       break;
     case BFD_RELOC_PPC64_ADDR16_HIGHER34:      r = R_PPC64_ADDR16_HIGHER34;
       break;
@@ -1318,22 +1331,39 @@ ppc64_elf_reloc_type_lookup (bfd *abfd,
 };
 
 static reloc_howto_type *
-ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-                            const char *r_name)
+ppc64_elf_reloc_name_lookup (bfd *abfd, const char *r_name)
 {
   unsigned int i;
+  static char *compat_map[][2] = {
+    { "R_PPC64_GOT_TLSGD34", "R_PPC64_GOT_TLSGD_PCREL34" },
+    { "R_PPC64_GOT_TLSLD34", "R_PPC64_GOT_TLSLD_PCREL34" },
+    { "R_PPC64_GOT_TPREL34", "R_PPC64_GOT_TPREL_PCREL34" },
+    { "R_PPC64_GOT_DTPREL34", "R_PPC64_GOT_DTPREL_PCREL34" }
+  };
 
   for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++)
     if (ppc64_elf_howto_raw[i].name != NULL
        && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0)
       return &ppc64_elf_howto_raw[i];
 
+  /* Handle old names of relocations in case they were used by
+     .reloc directives.
+     FIXME: Remove this soon.  Mapping the reloc names is very likely
+     completely unnecessary.  */
+  for (i = 0; i < ARRAY_SIZE (compat_map); i++)
+    if (strcasecmp (compat_map[i][0], r_name) == 0)
+      {
+       _bfd_error_handler (_("warning: %s should be used rather than %s"),
+                           compat_map[i][1], compat_map[i][0]);
+       return ppc64_elf_reloc_name_lookup (abfd, compat_map[i][1]);
+      }
+
   return NULL;
 }
 
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
                         Elf_Internal_Rela *dst)
 {
@@ -1350,7 +1380,7 @@ ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                          abfd, type);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
   cache_ptr->howto = ppc64_elf_howto_table[type];
   if (cache_ptr->howto == NULL || cache_ptr->howto->name == NULL)
@@ -1359,10 +1389,10 @@ ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                          abfd, type);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Handle the R_PPC64_ADDR16_HA and similar relocs.  */
@@ -1410,6 +1440,10 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   value = (bfd_signed_vma) value >> 16;
 
   octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+                                 input_section, octets))
+    return bfd_reloc_outofrange;
+
   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn &= ~0x1fffc1;
   insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
@@ -1433,7 +1467,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     {
       bfd_vma dest = opd_entry_value (symbol->section,
                                      symbol->value + reloc_entry->addend,
-                                     NULL, NULL, FALSE);
+                                     NULL, NULL, false);
       if (dest != (bfd_vma) -1)
        reloc_entry->addend = dest - (symbol->value
                                      + symbol->section->output_section->vma
@@ -1475,7 +1509,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   enum elf_ppc64_reloc_type r_type;
   bfd_size_type octets;
   /* Assume 'at' branch hints.  */
-  bfd_boolean is_isa_v2 = TRUE;
+  bool is_isa_v2 = true;
 
   /* If this is a relocatable link (output_bfd test tells us), just
      call the generic function.  Any adjustment will be done at final
@@ -1485,6 +1519,10 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                                  input_section, output_bfd, error_message);
 
   octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+                                 input_section, octets))
+    return bfd_reloc_outofrange;
+
   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn &= ~(0x01 << 21);
   r_type = reloc_entry->howto->type;
@@ -1630,11 +1668,15 @@ ppc64_elf_toc64_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 * OCTETS_PER_BYTE (abfd, input_section);
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+                                 input_section, octets))
+    return bfd_reloc_outofrange;
+
   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
   if (TOCstart == 0)
     TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
 
-  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;
 }
@@ -1646,14 +1688,20 @@ ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 {
   uint64_t insn;
   bfd_vma targ;
+  bfd_size_type octets;
 
   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);
+  octets = reloc_entry->address * OCTETS_PER_BYTE (abfd, input_section);
+  if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
+                                 input_section, octets))
+    return bfd_reloc_outofrange;
+
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn <<= 32;
-  insn |= bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address + 4);
+  insn |= bfd_get_32 (abfd, (bfd_byte *) data + octets + 4);
 
   targ = (symbol->section->output_section->vma
          + symbol->section->output_offset
@@ -1672,8 +1720,8 @@ ppc64_elf_prefix_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   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);
+  bfd_put_32 (abfd, insn >> 32, (bfd_byte *) data + octets);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets + 4);
   if (reloc_entry->howto->complain_on_overflow == complain_overflow_signed
       && (targ + (1ULL << (reloc_entry->howto->bitsize - 1))
          >= 1ULL << reloc_entry->howto->bitsize))
@@ -1695,10 +1743,12 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 
   if (error_message != NULL)
     {
-      static char buf[60];
-      sprintf (buf, "generic linker can't handle %s",
-              reloc_entry->howto->name);
-      *error_message = buf;
+      static char *message;
+      free (message);
+      if (asprintf (&message, _("generic linker can't handle %s"),
+                   reloc_entry->howto->name) < 0)
+       message = NULL;
+      *error_message = message;
     }
   return bfd_reloc_dangerous;
 }
@@ -1801,7 +1851,7 @@ struct ppc64_elf_obj_tdata
 
 /* Override the generic function because we store some extras.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct ppc64_elf_obj_tdata),
@@ -1811,11 +1861,11 @@ ppc64_elf_mkobject (bfd *abfd)
 /* Fix bad default arch selected for a 64 bit input bfd when the
    default is 32 bit.  Also select arch based on apuinfo.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_object_p (bfd *abfd)
 {
   if (!abfd->arch_info->the_default)
-    return TRUE;
+    return true;
 
   if (abfd->arch_info->bits_per_word == 32)
     {
@@ -1833,13 +1883,13 @@ ppc64_elf_object_p (bfd *abfd)
 
 /* Support for core dump NOTE sections.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   size_t offset, size;
 
   if (note->descsz != 504)
-    return FALSE;
+    return false;
 
   /* pr_cursig */
   elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
@@ -1856,11 +1906,11 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
                                          size, note->descpos + offset);
 }
 
-static bfd_boolean
+static bool
 ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
   if (note->descsz != 136)
-    return FALSE;
+    return false;
 
   elf_tdata (abfd)->core->pid
     = bfd_get_32 (abfd, note->descdata + 24);
@@ -1869,7 +1919,7 @@ ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   elf_tdata (abfd)->core->command
     = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
 
-  return TRUE;
+  return true;
 }
 
 static char *
@@ -1995,7 +2045,7 @@ struct _ppc64_elf_section_data
 #define ppc64_elf_section_data(sec) \
   ((struct _ppc64_elf_section_data *) elf_section_data (sec))
 
-static bfd_boolean
+static bool
 ppc64_elf_new_section_hook (bfd *abfd, asection *sec)
 {
   if (!sec->used_by_bfd)
@@ -2005,23 +2055,23 @@ ppc64_elf_new_section_hook (bfd *abfd, asection *sec)
 
       sdata = bfd_zalloc (abfd, amt);
       if (sdata == NULL)
-       return FALSE;
+       return false;
       sec->used_by_bfd = sdata;
     }
 
   return _bfd_elf_new_section_hook (abfd, sec);
 }
 
-static bfd_boolean
+static bool
 ppc64_elf_section_flags (const Elf_Internal_Shdr *hdr)
 {
   const char *name = hdr->bfd_section->name;
 
-  if (strncmp (name, ".sbss", 5) == 0
-      || strncmp (name, ".sdata", 6) == 0)
+  if (startswith (name, ".sbss")
+      || startswith (name, ".sdata"))
     hdr->bfd_section->flags |= SEC_SMALL_DATA;
 
-  return TRUE;
+  return true;
 }
 
 static struct _opd_sec_data *
@@ -2035,8 +2085,8 @@ get_opd_info (asection * sec)
 }
 \f
 /* Parameters for the qsort hook.  */
-static bfd_boolean synthetic_relocatable;
-static asection *synthetic_opd;
+static bool synthetic_relocatable;
+static const asection *synthetic_opd;
 
 /* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
 
@@ -2171,7 +2221,7 @@ sym_exists_at (asymbol **syms, size_t lo, size_t hi, unsigned int id,
   return NULL;
 }
 
-static bfd_boolean
+static bool
 section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
 {
   bfd_vma vma = *(bfd_vma *) ptr;
@@ -2195,7 +2245,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   char *names;
   size_t symcount, codesecsym, codesecsymend, secsymend, opdsymend;
   asection *opd = NULL;
-  bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
+  bool relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
   asymbol **syms;
   int abi = abiversion (abfd);
 
@@ -2277,7 +2327,8 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
         sym->section directly.  With separate debug info files, the
         symbols will be extracted from the debug file while abfd passed
         to this function is the real binary.  */
-      if (strcmp (syms[i]->section->name, ".opd") == 0)
+      if ((syms[i]->flags & BSF_SECTION_SYM) != 0
+         && strcmp (syms[i]->section->name, ".opd") == 0)
        ++i;
       codesecsym = i;
 
@@ -2310,7 +2361,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
   if (relocatable)
     {
-      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+      bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
       arelent *r;
       size_t size;
       size_t relcount;
@@ -2323,7 +2374,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       if (relcount == 0)
        goto done;
 
-      if (!(*slurp_relocs) (abfd, opd, static_syms, FALSE))
+      if (!(*slurp_relocs) (abfd, opd, static_syms, false))
        {
          count = -1;
          goto done;
@@ -2409,7 +2460,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
     }
   else
     {
-      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+      bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
       bfd_byte *contents = NULL;
       size_t size;
       size_t plt_count = 0;
@@ -2422,8 +2473,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        free_contents_and_exit_err:
          count = -1;
        free_contents_and_exit:
-         if (contents)
-           free (contents);
+         free (contents);
          goto done;
        }
 
@@ -2516,7 +2566,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
          if (relplt != NULL)
            {
              slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
-             if (!(*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
+             if (!(*slurp_relocs) (abfd, relplt, dyn_syms, true))
                goto free_contents_and_exit_err;
 
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
@@ -2839,7 +2889,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    Used to call a function in a shared library.  If it so happens that
    the plt entry referenced crosses a 64k boundary, then an extra
    "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr".
-   ppc_stub_plt_call_r2save starts with "std %r2,40(%r1)".
+   An r2save variant starts with "std %r2,40(%r1)".
    .   addis   %r11,%r2,xxx@toc@ha
    .   ld      %r12,xxx+0@toc@l(%r11)
    .   mtctr   %r12
@@ -2868,13 +2918,8 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    variants exist too, simpler for plt calls since a new toc pointer
    and static chain are not loaded by the stub.  In addition, ELFv2
    has some more complex stubs to handle calls marked with NOTOC
-   relocs from functions where r2 is not a valid toc pointer.  These
-   come in two flavours, the ones shown below, and _both variants that
-   start with "std %r2,24(%r1)" to save r2 in the unlikely event that
-   one call is from a function where r2 is used as the toc pointer but
-   needs a toc adjusting stub for small-model multi-toc, and another
-   call is from a function where r2 is not valid.
-   ppc_stub_long_branch_notoc:
+   relocs from functions where r2 is not a valid toc pointer.
+   ppc_stub_long_branch_p9notoc:
    .   mflr    %r12
    .   bcl     20,31,1f
    .  1:
@@ -2884,7 +2929,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    .   addi    %r12,%r12,dest-1b@l
    .   b       dest
 
-   ppc_stub_plt_branch_notoc:
+   ppc_stub_plt_branch_p9notoc:
    .   mflr    %r12
    .   bcl     20,31,1f
    .  1:
@@ -2899,7 +2944,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    .   mtctr   %r12
    .   bctr
 
-   ppc_stub_plt_call_notoc:
+   ppc_stub_plt_call_p9notoc:
    .   mflr    %r12
    .   bcl     20,31,1f
    .  1:
@@ -2914,7 +2959,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    .   mtctr   %r12
    .   bctr
 
-   There are also ELFv1 powerxx variants of these stubs.
+   There are also ELFv1 power10 variants of these stubs.
    ppc_stub_long_branch_notoc:
    .   pla     %r12,dest@pcrel
    .   b       dest
@@ -2937,15 +2982,13 @@ must_be_dyn_reloc (struct bfd_link_info *info,
 
    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
+   For example, a power10 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
-   particular function symbol.  For example, if printf is called from
+   Stub variants may be merged.  For example, if printf is called from
    code with the tocsave optimization (ie. r2 saved in function
    prologue) and therefore calls use a ppc_stub_plt_call linkage stub,
    and from other code without the tocsave optimization requiring a
@@ -2956,33 +2999,36 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    relocations.  These require a ppc_stub_plt_call_notoc linkage stub
    to call an external function like printf.  If other calls to printf
    require a ppc_stub_plt_call linkage stub then a single
-   ppc_stub_plt_call_notoc linkage stub will be used for both types of
-   call.  If other calls to printf require a ppc_stub_plt_call_r2save
-   linkage stub then a single ppc_stub_plt_call_both linkage stub will
-   be created and calls not requiring r2 to be saved will enter the
-   stub after the r2 save instruction.  There is an analogous
-   hierarchy of long branch and plt branch stubs for local call
-   linkage.  */
-
-enum ppc_stub_type
+   ppc_stub_plt_call_notoc linkage stub may be used for both types of
+   call.  */
+
+enum ppc_stub_main_type
 {
   ppc_stub_none,
   ppc_stub_long_branch,
-  ppc_stub_long_branch_r2off,
-  ppc_stub_long_branch_notoc,
-  ppc_stub_long_branch_both, /* r2off and notoc variants both needed.  */
   ppc_stub_plt_branch,
-  ppc_stub_plt_branch_r2off,
-  ppc_stub_plt_branch_notoc,
-  ppc_stub_plt_branch_both,
   ppc_stub_plt_call,
-  ppc_stub_plt_call_r2save,
-  ppc_stub_plt_call_notoc,
-  ppc_stub_plt_call_both,
   ppc_stub_global_entry,
   ppc_stub_save_res
 };
 
+/* ppc_stub_long_branch, ppc_stub_plt_branch and ppc_stub_plt_call have
+   these variations.  */
+
+enum ppc_stub_sub_type
+{
+  ppc_stub_toc,
+  ppc_stub_notoc,
+  ppc_stub_p9notoc
+};
+
+struct ppc_stub_type
+{
+  ENUM_BITFIELD (ppc_stub_main_type) main : 3;
+  ENUM_BITFIELD (ppc_stub_sub_type) sub : 2;
+  unsigned int r2save : 1;
+};
+
 /* Information on stub grouping.  */
 struct map_stub
 {
@@ -3011,7 +3057,7 @@ struct ppc_stub_hash_entry
   /* Base hash table entry structure.  */
   struct bfd_hash_entry root;
 
-  enum ppc_stub_type stub_type;
+  struct ppc_stub_type type;
 
   /* Group information.  */
   struct map_stub *group;
@@ -3047,7 +3093,7 @@ struct ppc_branch_hash_entry
   unsigned int iter;
 };
 
-/* Used to track dynamic relocations for local symbols.  */
+/* Used to track dynamic relocations.  */
 struct ppc_dyn_relocs
 {
   struct ppc_dyn_relocs *next;
@@ -3056,7 +3102,27 @@ struct ppc_dyn_relocs
   asection *sec;
 
   /* Total number of relocs copied for the input section.  */
-  unsigned int count : 31;
+  unsigned int count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  unsigned int pc_count;
+
+  /* Number of relocs that might become R_PPC64_RELATIVE.  */
+  unsigned int rel_count;
+};
+
+struct ppc_local_dyn_relocs
+{
+  struct ppc_local_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  unsigned int count;
+
+  /* Number of relocs that might become R_PPC64_RELATIVE.  */
+  unsigned int rel_count : 31;
 
   /* Whether this entry is for STT_GNU_IFUNC symbols.  */
   unsigned int ifunc : 1;
@@ -3076,9 +3142,6 @@ struct ppc_link_hash_entry
     struct ppc_link_hash_entry *next_dot_sym;
   } u;
 
-  /* Track dynamic relocs copied for this symbol.  */
-  struct elf_dyn_relocs *dyn_relocs;
-
   /* Link between function code and descriptor symbols.  */
   struct ppc_link_hash_entry *oh;
 
@@ -3131,6 +3194,12 @@ ppc_elf_hash_entry (struct elf_link_hash_entry *ent)
   return (struct ppc_link_hash_entry *) ent;
 }
 
+static inline struct elf_link_hash_entry *
+elf_hash_entry (struct ppc_link_hash_entry *ent)
+{
+  return (struct elf_link_hash_entry *) ent;
+}
+
 /* ppc64 ELF linker hash table.  */
 
 struct ppc_link_hash_table
@@ -3200,8 +3269,13 @@ struct ppc_link_hash_table
   /* The size of reliplt used by got entry relocs.  */
   bfd_size_type got_reli_size;
 
+  /* DT_RELR array of r_offset.  */
+  size_t relr_alloc;
+  size_t relr_count;
+  bfd_vma *relr_addr;
+
   /* Statistics.  */
-  unsigned long stub_count[ppc_stub_global_entry];
+  unsigned long stub_count[ppc_stub_save_res];
 
   /* Number of stubs against global syms.  */
   unsigned long stub_globals;
@@ -3221,31 +3295,33 @@ struct ppc_link_hash_table
   /* Set if inline plt calls should be converted to direct calls.  */
   unsigned int can_convert_all_inline_plt:1;
 
+  /* Set if a stub_offset changed.  */
+  unsigned int stub_changed:1;
+
   /* Set on error.  */
   unsigned int stub_error:1;
 
   /* Whether func_desc_adjust needs to be run over symbols.  */
   unsigned int need_func_desc_adj:1;
 
-  /* Whether there exist local gnu indirect function resolvers,
-     referenced by dynamic relocations.  */
-  unsigned int local_ifunc_resolver:1;
-  unsigned int maybe_local_ifunc_resolver:1;
-
   /* 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;
+  /* Whether any code linked seems to be Power10.  */
+  unsigned int has_power10_relocs:1;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
-  /* Small local sym cache.  */
-  struct sym_cache sym_cache;
+/* After 20 iterations of stub sizing we no longer allow stubs to
+   shrink.  This is to break out of a pathological case where adding
+   stubs or increasing their size on one iteration decreases section
+   gaps (perhaps due to alignment), which then results in smaller
+   stubs on the next iteration.  */
+#define STUB_SHRINK_ITER 20
 };
 
 /* Rename some of the generic section flags to better document how they
@@ -3272,8 +3348,9 @@ struct ppc_link_hash_table
 /* Get the ppc64 ELF linker hash table from a link_info structure.  */
 
 #define ppc_hash_table(p) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-  == PPC64_ELF_DATA ? ((struct ppc_link_hash_table *) ((p)->hash)) : NULL)
+  ((is_elf_hash_table ((p)->hash)                                      \
+    && elf_hash_table_id (elf_hash_table (p)) == PPC64_ELF_DATA)       \
+   ? (struct ppc_link_hash_table *) (p)->hash : NULL)
 
 #define ppc_stub_hash_lookup(table, string, create, copy) \
   ((struct ppc_stub_hash_entry *) \
@@ -3307,7 +3384,9 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
 
       /* Initialize the local fields.  */
       eh = (struct ppc_stub_hash_entry *) entry;
-      eh->stub_type = ppc_stub_none;
+      eh->type.main = ppc_stub_none;
+      eh->type.sub = ppc_stub_toc;
+      eh->type.r2save = 0;
       eh->group = NULL;
       eh->stub_offset = 0;
       eh->target_value = 0;
@@ -3508,7 +3587,7 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
 
 /* Create sections for linker generated code.  */
 
-static bfd_boolean
+static bool
 create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -3525,18 +3604,18 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                       flags);
       if (htab->sfpr == NULL
          || !bfd_set_section_alignment (htab->sfpr, 2))
-       return FALSE;
+       return false;
     }
 
   if (bfd_link_relocatable (info))
-    return TRUE;
+    return true;
 
   /* Create .glink for lazy dynamic linking support.  */
   htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
                                                    flags);
   if (htab->glink == NULL
       || !bfd_set_section_alignment (htab->glink, 3))
-    return FALSE;
+    return false;
 
   /* The part of .glink used by global entry stubs, separate so that
      it can be aligned appropriately without affecting htab->glink.  */
@@ -3544,7 +3623,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                           flags);
   if (htab->global_entry == NULL
       || !bfd_set_section_alignment (htab->global_entry, 2))
-    return FALSE;
+    return false;
 
   if (!info->no_ld_generated_unwind_info)
     {
@@ -3555,14 +3634,14 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                                 flags);
       if (htab->glink_eh_frame == NULL
          || !bfd_set_section_alignment (htab->glink_eh_frame, 2))
-       return FALSE;
+       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 (htab->elf.iplt, 3))
-    return FALSE;
+    return false;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@@ -3570,7 +3649,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.iplt", flags);
   if (htab->elf.irelplt == NULL
       || !bfd_set_section_alignment (htab->elf.irelplt, 3))
-    return FALSE;
+    return false;
 
   /* Create branch lookup table for plt_branch stubs.  */
   flags = (SEC_ALLOC | SEC_LOAD
@@ -3579,7 +3658,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                   flags);
   if (htab->brlt == NULL
       || !bfd_set_section_alignment (htab->brlt, 3))
-    return FALSE;
+    return false;
 
   /* Local plt entries, put in .branch_lt but a separate section for
      convenience.  */
@@ -3587,10 +3666,10 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
                                                       flags);
   if (htab->pltlocal == NULL
       || !bfd_set_section_alignment (htab->pltlocal, 3))
-    return FALSE;
+    return false;
 
   if (!bfd_link_pic (info))
-    return TRUE;
+    return true;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@@ -3598,20 +3677,20 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relbrlt == NULL
       || !bfd_set_section_alignment (htab->relbrlt, 3))
-    return FALSE;
+    return false;
 
   htab->relpltlocal
     = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relpltlocal == NULL
       || !bfd_set_section_alignment (htab->relpltlocal, 3))
-    return FALSE;
+    return false;
 
-  return TRUE;
+  return true;
 }
 
 /* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
 
-bfd_boolean
+bool
 ppc64_elf_init_stub_bfd (struct bfd_link_info *info,
                         struct ppc64_elf_params *params)
 {
@@ -3675,6 +3754,46 @@ ppc_stub_name (const asection *input_section,
   return stub_name;
 }
 
+/* If mixing power10 with non-power10 code and --power10-stubs is not
+   specified (or is auto) then there may be multiple stub types for any
+   given symbol.  Up to three classes of stubs are stored in separate
+   stub_hash_table entries having the same key string.  The entries
+   will always be adjacent on entry->root.next chain, even if hash
+   table resizing occurs.  This function selects the correct entry to
+   use.  */
+
+static struct ppc_stub_hash_entry *
+select_alt_stub (struct ppc_stub_hash_entry *entry,
+                enum elf_ppc64_reloc_type r_type)
+{
+  enum ppc_stub_sub_type subt;
+
+  switch (r_type)
+    {
+    case R_PPC64_REL24_NOTOC:
+      subt = ppc_stub_notoc;
+      break;
+    case R_PPC64_REL24_P9NOTOC:
+      subt = ppc_stub_p9notoc;
+      break;
+    default:
+      subt = ppc_stub_toc;
+      break;
+    }
+
+  while (entry != NULL && entry->type.sub != subt)
+    {
+      const char *stub_name = entry->root.string;
+
+      entry = (struct ppc_stub_hash_entry *) entry->root.next;
+      if (entry != NULL
+         && entry->root.string != stub_name)
+       entry = NULL;
+    }
+
+  return entry;
+}
+
 /* Look up an entry in the stub hash.  Stub entries are cached because
    creating the stub name takes a bit of time.  */
 
@@ -3712,13 +3831,16 @@ ppc_get_stub_entry (const asection *input_section,
        return NULL;
 
       stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table,
-                                        stub_name, FALSE, FALSE);
+                                        stub_name, false, false);
       if (h != NULL)
        h->u.stub_cache = stub_entry;
 
       free (stub_name);
     }
 
+  if (stub_entry != NULL && htab->params->power10_stubs == -1)
+    stub_entry = select_alt_stub (stub_entry, ELF64_R_TYPE (rel->r_info));
+
   return stub_entry;
 }
 
@@ -3761,7 +3883,7 @@ ppc_add_stub (const char *stub_name,
 
   /* Enter this entry into the linker stub hash table.  */
   stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name,
-                                    TRUE, FALSE);
+                                    true, false);
   if (stub_entry == NULL)
     {
       /* xgettext:c-format */
@@ -3775,10 +3897,79 @@ ppc_add_stub (const char *stub_name,
   return stub_entry;
 }
 
+/* A stub has already been created, but it may not be the required
+   type.  We shouldn't be transitioning from plt_call to long_branch
+   stubs or vice versa, but we might be upgrading from plt_call to
+   plt_call with r2save for example.  */
+
+static bool
+ppc_merge_stub (struct ppc_link_hash_table *htab,
+               struct ppc_stub_hash_entry *stub_entry,
+               struct ppc_stub_type stub_type,
+               enum elf_ppc64_reloc_type r_type)
+{
+  struct ppc_stub_type old_type = stub_entry->type;
+
+  if (old_type.main == ppc_stub_save_res)
+    return true;
+
+  if (htab->params->power10_stubs == -1)
+    {
+      /* For --power10-stubs=auto, don't merge _notoc and other
+        varieties of stubs.  */
+      struct ppc_stub_hash_entry *alt_stub;
+
+      alt_stub = select_alt_stub (stub_entry, r_type);
+      if (alt_stub == NULL)
+       {
+         alt_stub = ((struct ppc_stub_hash_entry *)
+                     stub_hash_newfunc (NULL,
+                                        &htab->stub_hash_table,
+                                        stub_entry->root.string));
+         if (alt_stub == NULL)
+           return false;
+
+         *alt_stub = *stub_entry;
+         stub_entry->root.next = &alt_stub->root;
+
+         /* Sort notoc stubs first, then toc stubs, then p9notoc.
+            Not that it matters, this just puts smaller stubs first.  */
+         if (stub_type.sub == ppc_stub_notoc)
+           alt_stub = stub_entry;
+         else if (stub_type.sub == ppc_stub_p9notoc
+                  && alt_stub->root.next
+                  && alt_stub->root.next->string == alt_stub->root.string)
+           {
+             struct ppc_stub_hash_entry *next
+               = (struct ppc_stub_hash_entry *) alt_stub->root.next;
+             alt_stub->type = next->type;
+             alt_stub = next;
+           }
+         alt_stub->type = stub_type;
+         return true;
+       }
+      stub_entry = alt_stub;
+    }
+
+  old_type = stub_entry->type;
+  if (old_type.main == ppc_stub_plt_branch)
+    old_type.main += ppc_stub_long_branch - ppc_stub_plt_branch;
+
+  if (old_type.main != stub_type.main
+      || (old_type.sub != stub_type.sub
+         && old_type.sub != ppc_stub_toc
+         && stub_type.sub != ppc_stub_toc))
+    abort ();
+
+  stub_entry->type.sub |= stub_type.sub;
+  stub_entry->type.r2save |= stub_type.r2save;
+  return true;
+}
+
 /* Create .got and .rela.got sections in ABFD, and .got in dynobj if
    not already done.  */
 
-static bfd_boolean
+static bool
 create_got_section (bfd *abfd, struct bfd_link_info *info)
 {
   asection *got, *relgot;
@@ -3786,13 +3977,13 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (!is_ppc64_elf (abfd))
-    return FALSE;
+    return false;
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   if (!htab->elf.sgot
       && !_bfd_elf_create_got_section (htab->elf.dynobj, info))
-    return FALSE;
+    return false;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED);
@@ -3800,17 +3991,17 @@ 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 (got, 3))
-    return FALSE;
+    return false;
 
   relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
                                               flags | SEC_READONLY);
   if (!relgot
       || !bfd_set_section_alignment (relgot, 3))
-    return FALSE;
+    return false;
 
   ppc64_elf_tdata (abfd)->got = got;
   ppc64_elf_tdata (abfd)->relgot = relgot;
-  return TRUE;
+  return true;
 }
 
 /* Follow indirect and warning symbol links.  */
@@ -3907,35 +4098,40 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
     return;
 
   /* Copy over any dynamic relocs we may have on the indirect sym.  */
-  if (eind->dyn_relocs != NULL)
+  if (ind->dyn_relocs != NULL)
     {
-      if (edir->dyn_relocs != NULL)
+      if (dir->dyn_relocs != NULL)
        {
-         struct elf_dyn_relocs **pp;
-         struct elf_dyn_relocs *p;
+         struct ppc_dyn_relocs **pp;
+         struct ppc_dyn_relocs *p;
 
          /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
-         for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+         for (pp = (struct ppc_dyn_relocs **) &ind->dyn_relocs;
+              (p = *pp) != NULL;
+              )
            {
-             struct elf_dyn_relocs *q;
+             struct ppc_dyn_relocs *q;
 
-             for (q = edir->dyn_relocs; q != NULL; q = q->next)
+             for (q = (struct ppc_dyn_relocs *) dir->dyn_relocs;
+                  q != NULL;
+                  q = q->next)
                if (q->sec == p->sec)
                  {
-                   q->pc_count += p->pc_count;
                    q->count += p->count;
+                   q->pc_count += p->pc_count;
+                   q->rel_count += p->rel_count;
                    *pp = p->next;
                    break;
                  }
              if (q == NULL)
                pp = &p->next;
            }
-         *pp = edir->dyn_relocs;
+         *pp = (struct ppc_dyn_relocs *) dir->dyn_relocs;
        }
 
-      edir->dyn_relocs = eind->dyn_relocs;
-      eind->dyn_relocs = NULL;
+      dir->dyn_relocs = ind->dyn_relocs;
+      ind->dyn_relocs = NULL;
     }
 
   /* Copy over got entries that we may have already seen to the
@@ -3998,7 +4194,7 @@ lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
       const char *fd_name = fh->elf.root.root.string + 1;
 
       fdh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, fd_name,
-                                                     FALSE, FALSE, FALSE));
+                                                     false, false, false));
       if (fdh == NULL)
        return fdh;
 
@@ -4030,7 +4226,7 @@ make_fdh (struct bfd_link_info *info,
   if (!_bfd_generic_link_add_one_symbol (info, abfd,
                                         fh->elf.root.root.string + 1,
                                         flags, bfd_und_section_ptr, 0,
-                                        NULL, FALSE, FALSE, &bh))
+                                        NULL, false, false, &bh))
     return NULL;
 
   fdh = (struct ppc_link_hash_entry *) bh;
@@ -4046,7 +4242,7 @@ make_fdh (struct bfd_link_info *info,
 /* Fix function descriptor symbols defined in .opd sections to be
    function type.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_add_symbol_hook (bfd *ibfd,
                           struct bfd_link_info *info,
                           Elf_Internal_Sym *isym,
@@ -4069,7 +4265,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
       if (!bfd_link_relocatable (info)
          && (*sec)->reloc_count != 0
          && opd_entry_value (*sec, *value, &code_sec, NULL,
-                             FALSE) != (bfd_vma) -1
+                             false) != (bfd_vma) -1
          && discarded_section (code_sec))
        {
          *sec = bfd_und_section_ptr;
@@ -4094,42 +4290,42 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
          _bfd_error_handler (_("symbol '%s' has invalid st_other"
                                " for ABI version 1"), *name);
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Merge non-visibility st_other attributes: local entry point.  */
 
 static void
 ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h,
-                                 const Elf_Internal_Sym *isym,
-                                 bfd_boolean definition,
-                                 bfd_boolean dynamic)
+                                 unsigned int st_other,
+                                 bool definition,
+                                 bool dynamic)
 {
   if (definition && (!dynamic || !h->def_regular))
-    h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1))
+    h->other = ((st_other & ~ELF_ST_VISIBILITY (-1))
                | ELF_ST_VISIBILITY (h->other));
 }
 
 /* Hook called on merging a symbol.  We use this to clear "fake" since
    we now have a real symbol.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_merge_symbol (struct elf_link_hash_entry *h,
                        const Elf_Internal_Sym *isym,
                        asection **psec ATTRIBUTE_UNUSED,
-                       bfd_boolean newdef ATTRIBUTE_UNUSED,
-                       bfd_boolean olddef ATTRIBUTE_UNUSED,
+                       bool newdef ATTRIBUTE_UNUSED,
+                       bool olddef ATTRIBUTE_UNUSED,
                        bfd *oldbfd ATTRIBUTE_UNUSED,
                        const asection *oldsec ATTRIBUTE_UNUSED)
 {
   ppc_elf_hash_entry (h)->fake = 0;
   if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
     ppc_elf_hash_entry (h)->non_zero_localentry = 1;
-  return TRUE;
+  return true;
 }
 
 /* This function makes an old ABI object reference to ".bar" cause the
@@ -4137,20 +4333,21 @@ ppc64_elf_merge_symbol (struct elf_link_hash_entry *h,
    NAME is a symbol defined in an archive.  Return a symbol in the hash
    table that might be satisfied by the archive symbols.  */
 
-static struct elf_link_hash_entry *
+static struct bfd_link_hash_entry *
 ppc64_elf_archive_symbol_lookup (bfd *abfd,
                                 struct bfd_link_info *info,
                                 const char *name)
 {
-  struct elf_link_hash_entry *h;
+  struct bfd_link_hash_entry *h;
   char *dot_name;
   size_t len;
 
   h = _bfd_elf_archive_symbol_lookup (abfd, info, name);
   if (h != NULL
+      && ppc_hash_table (info) != NULL
       /* Don't return this sym if it is a fake function descriptor
         created by add_symbol_adjust.  */
-      && !ppc_elf_hash_entry (h)->fake)
+      && !((struct ppc_link_hash_entry *) h)->fake)
     return h;
 
   if (name[0] == '.')
@@ -4159,7 +4356,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
   len = strlen (name);
   dot_name = bfd_alloc (abfd, len + 2);
   if (dot_name == NULL)
-    return (struct elf_link_hash_entry *) -1;
+    return (struct bfd_link_hash_entry *) -1;
   dot_name[0] = '.';
   memcpy (dot_name + 1, name, len + 1);
   h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name);
@@ -4181,7 +4378,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
    most restrictive visibility of the function descriptor and the
    function entry symbol is used.  */
 
-static bfd_boolean
+static bool
 add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -4191,14 +4388,14 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
     eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
 
   if (eh->elf.root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   if (eh->elf.root.root.string[0] != '.')
     abort ();
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   fdh = lookup_fdh (eh, htab);
   if (fdh == NULL
@@ -4212,7 +4409,7 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
         elsewhere.  */
       fdh = make_fdh (info, eh);
       if (fdh == NULL)
-       return FALSE;
+       return false;
     }
 
   if (fdh != NULL)
@@ -4244,17 +4441,17 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
              || eh->elf.def_regular))
        {
          if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
-           return FALSE;
+           return false;
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Set up opd section info and abiversion for IBFD, and process list
    of dot-symbols we made in link_hash_newfunc.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -4274,7 +4471,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
          _bfd_error_handler (_("%pB .opd not allowed in ABI version %d"),
                              ibfd, abiversion (ibfd));
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
        }
     }
 
@@ -4294,7 +4491,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return TRUE;
+    return true;
 
   if (opd != NULL && opd->size != 0
       && (ibfd->flags & DYNAMIC) == 0
@@ -4318,12 +4515,12 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
       amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map);
       opd_sym_map = bfd_zalloc (ibfd, amt);
       if (opd_sym_map == NULL)
-       return FALSE;
+       return false;
       ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map;
       relocs = _bfd_elf_link_read_relocs (ibfd, opd, NULL, NULL,
                                          info->keep_memory);
       if (relocs == NULL)
-       return FALSE;
+       return false;
       symtab_hdr = &elf_symtab_hdr (ibfd);
       rel_end = relocs + opd->reloc_count - 1;
       for (rel = relocs; rel < rel_end; rel++)
@@ -4338,12 +4535,13 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
              Elf_Internal_Sym *isym;
              asection *s;
 
-             isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, r_symndx);
+             isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, ibfd,
+                                           r_symndx);
              if (isym == NULL)
                {
                  if (elf_section_data (opd)->relocs != relocs)
                    free (relocs);
-                 return FALSE;
+                 return false;
                }
 
              s = bfd_section_from_elf_index (ibfd, isym->st_shndx);
@@ -4368,17 +4566,17 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
        {
          htab->need_func_desc_adj = 1;
          if (!add_symbol_adjust (eh, info))
-           return FALSE;
+           return false;
        }
       p = &eh->u.next_dot_sym;
     }
-  return TRUE;
+  return true;
 }
 
 /* Undo hash table changes when an --as-needed input file is determined
    not to be needed.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_notice_as_needed (bfd *ibfd,
                            struct bfd_link_info *info,
                            enum notice_asneeded_action act)
@@ -4388,7 +4586,7 @@ ppc64_elf_notice_as_needed (bfd *ibfd,
       struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
       if (htab == NULL)
-       return FALSE;
+       return false;
 
       htab->dot_syms = NULL;
     }
@@ -4447,12 +4645,12 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
          size_t amt = sizeof (*ent);
          ent = bfd_alloc (abfd, amt);
          if (ent == NULL)
-           return FALSE;
+           return false;
          ent->next = local_got_ents[r_symndx];
          ent->addend = r_addend;
          ent->owner = abfd;
          ent->tls_type = tls_type;
-         ent->is_indirect = FALSE;
+         ent->is_indirect = false;
          ent->got.refcount = 0;
          local_got_ents[r_symndx] = ent;
        }
@@ -4466,7 +4664,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   return local_plt + r_symndx;
 }
 
-static bfd_boolean
+static bool
 update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend)
 {
   struct plt_entry *ent;
@@ -4479,21 +4677,22 @@ update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend)
       size_t amt = sizeof (*ent);
       ent = bfd_alloc (abfd, amt);
       if (ent == NULL)
-       return FALSE;
+       return false;
       ent->next = *plist;
       ent->addend = addend;
       ent->plt.refcount = 0;
       *plist = ent;
     }
   ent->plt.refcount += 1;
-  return TRUE;
+  return true;
 }
 
-static bfd_boolean
+static bool
 is_branch_reloc (enum elf_ppc64_reloc_type r_type)
 {
   return (r_type == R_PPC64_REL24
          || r_type == R_PPC64_REL24_NOTOC
+         || r_type == R_PPC64_REL24_P9NOTOC
          || r_type == R_PPC64_REL14
          || r_type == R_PPC64_REL14_BRTAKEN
          || r_type == R_PPC64_REL14_BRNTAKEN
@@ -4507,7 +4706,7 @@ is_branch_reloc (enum elf_ppc64_reloc_type r_type)
 
 /* Relocs on inline plt call sequence insns prior to the call.  */
 
-static bfd_boolean
+static bool
 is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
 {
   return (r_type == R_PPC64_PLT16_HA
@@ -4520,11 +4719,31 @@ is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
          || r_type == R_PPC64_PLTSEQ_NOTOC);
 }
 
+/* Of relocs which might appear paired with TLSGD and TLSLD marker
+   relocs, return true for those that operate on a dword.  */
+
+static bool
+is_8byte_reloc (enum elf_ppc64_reloc_type r_type)
+{
+  return (r_type == R_PPC64_PLT_PCREL34
+         || r_type == R_PPC64_PLT_PCREL34_NOTOC
+         || r_type == R_PPC64_PLTCALL);
+}
+
+/* Like bfd_reloc_offset_in_range but without a howto.  Return true
+   iff a field of SIZE bytes at OFFSET is within SEC limits.  */
+
+static bool
+offset_in_range (asection *sec, bfd_vma offset, size_t size)
+{
+  return offset <= sec->size && size <= sec->size - offset;
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                        asection *sec, const Elf_Internal_Rela *relocs)
 {
@@ -4535,30 +4754,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
   struct elf_link_hash_entry *tga, *dottga;
-  bfd_boolean is_opd;
+  bool is_opd;
 
   if (bfd_link_relocatable (info))
-    return TRUE;
-
-  /* Don't do anything special with non-loaded, non-alloced sections.
-     In particular, any relocs in such sections should not affect GOT
-     and PLT reference counting (ie. we don't allow them to create GOT
-     or PLT entries), there's no possibility or desire to optimize TLS
-     relocs, and there's not much point in propagating relocs to shared
-     libs that the dynamic linker won't relocate.  */
-  if ((sec->flags & SEC_ALLOC) == 0)
-    return TRUE;
+    return true;
 
   BFD_ASSERT (is_ppc64_elf (abfd));
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
-                             FALSE, FALSE, TRUE);
+                             false, false, true);
   dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
-                                FALSE, FALSE, TRUE);
+                                false, false, true);
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   sreloc = NULL;
@@ -4568,6 +4778,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
     {
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *isym;
       enum elf_ppc64_reloc_type r_type;
       int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
@@ -4575,9 +4786,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
-       h = NULL;
+       {
+         h = NULL;
+         isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
+         if (isym == NULL)
+           return false;
+       }
       else
        {
+         isym = NULL;
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
 
@@ -4597,14 +4814,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        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_GOT_TLSGD_PCREL34:
+       case R_PPC64_GOT_TLSLD_PCREL34:
+       case R_PPC64_GOT_TPREL_PCREL34:
+       case R_PPC64_GOT_DTPREL_PCREL34:
        case R_PPC64_PLT_PCREL34:
        case R_PPC64_PLT_PCREL34_NOTOC:
        case R_PPC64_PCREL28:
-         htab->powerxx_stubs = 1;
+         htab->has_power10_relocs = 1;
          break;
        default:
          break;
@@ -4648,18 +4865,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        }
       else
        {
-         Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                                         abfd, r_symndx);
-         if (isym == NULL)
-           return FALSE;
-
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                             rel->r_addend,
                                             NON_GOT | PLT_IFUNC);
              if (ifunc == NULL)
-               return FALSE;
+               return false;
            }
        }
 
@@ -4676,7 +4888,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                        rel->r_addend,
                                        NON_GOT | TLS_TLS | TLS_MARK))
-             return FALSE;
+             return false;
          sec->has_tls_reloc = 1;
          break;
 
@@ -4684,7 +4896,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:
+       case R_PPC64_GOT_TLSLD_PCREL34:
          tls_type = TLS_TLS | TLS_LD;
          goto dogottls;
 
@@ -4692,7 +4904,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:
+       case R_PPC64_GOT_TLSGD_PCREL34:
          tls_type = TLS_TLS | TLS_GD;
          goto dogottls;
 
@@ -4700,7 +4912,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:
+       case R_PPC64_GOT_TPREL_PCREL34:
          if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
@@ -4710,7 +4922,7 @@ 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:
+       case R_PPC64_GOT_DTPREL_PCREL34:
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
@@ -4739,7 +4951,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
          if (ppc64_elf_tdata (abfd)->got == NULL
              && !create_got_section (abfd, info))
-           return FALSE;
+           return false;
 
          if (h != NULL)
            {
@@ -4757,12 +4969,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  size_t amt = sizeof (*ent);
                  ent = bfd_alloc (abfd, amt);
                  if (ent == NULL)
-                   return FALSE;
+                   return false;
                  ent->next = eh->elf.got.glist;
                  ent->addend = rel->r_addend;
                  ent->owner = abfd;
                  ent->tls_type = tls_type;
-                 ent->is_indirect = FALSE;
+                 ent->is_indirect = false;
                  ent->got.refcount = 0;
                  eh->elf.got.glist = ent;
                }
@@ -4773,15 +4985,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            /* This is a global offset table entry for a local symbol.  */
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                        rel->r_addend, tls_type))
-             return FALSE;
-
-         /* We may also need a plt entry if the symbol turns out to be
-            an ifunc.  */
-         if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
-           {
-             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
-               return FALSE;
-           }
+             return false;
          break;
 
        case R_PPC64_PLT16_HA:
@@ -4808,7 +5012,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                                              rel->r_addend,
                                              NON_GOT | PLT_KEEP);
          if (!update_plt_info (abfd, plt_list, rel->r_addend))
-           return FALSE;
+           return false;
          break;
 
          /* The following relocations don't need to propagate the
@@ -4864,7 +5068,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                                      abfd, sec, rel->r_offset,
                                      ppc64_elf_howto_table[r_type]->name);
              bfd_set_error (bfd_error_bad_value);
-             return FALSE;
+             return false;
            }
          break;
 
@@ -4898,14 +5102,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             Reconstruct it for later use during GC.  */
        case R_PPC64_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return FALSE;
+           return false;
          break;
 
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_PPC64_GNU_VTENTRY:
          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+           return false;
          break;
 
        case R_PPC64_REL14:
@@ -4924,16 +5128,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  dest = h->root.u.def.section;
              }
            else
-             {
-               Elf_Internal_Sym *isym;
-
-               isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                             abfd, r_symndx);
-               if (isym == NULL)
-                 return FALSE;
-
-               dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
-             }
+             dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
            if (dest != sec)
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
@@ -4947,6 +5142,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
        case R_PPC64_REL24:
        case R_PPC64_REL24_NOTOC:
+       case R_PPC64_REL24_P9NOTOC:
        rel24:
          plt_list = ifunc;
          if (h != NULL)
@@ -4976,7 +5172,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
             refers to is in a shared lib.  */
          if (plt_list
              && !update_plt_info (abfd, plt_list, rel->r_addend))
-           return FALSE;
+           return false;
          break;
 
        case R_PPC64_ADDR14:
@@ -5016,7 +5212,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          else
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                        rel->r_addend, tls_type))
-             return FALSE;
+             return false;
 
          ppc64_sec = ppc64_elf_section_data (sec);
          if (ppc64_sec->sec_type != sec_toc)
@@ -5027,11 +5223,11 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
              ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
              if (ppc64_sec->u.toc.symndx == NULL)
-               return FALSE;
+               return false;
              amt = sec->size * sizeof (bfd_vma) / 8;
              ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
              if (ppc64_sec->u.toc.add == NULL)
-               return FALSE;
+               return false;
              BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
              ppc64_sec->sec_type = sec_toc;
            }
@@ -5047,19 +5243,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
          goto dodyn;
 
-       case R_PPC64_TPREL16:
-       case R_PPC64_TPREL16_LO:
        case R_PPC64_TPREL16_HI:
        case R_PPC64_TPREL16_HA:
-       case R_PPC64_TPREL16_DS:
-       case R_PPC64_TPREL16_LO_DS:
        case R_PPC64_TPREL16_HIGH:
        case R_PPC64_TPREL16_HIGHA:
        case R_PPC64_TPREL16_HIGHER:
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
+         sec->has_tls_reloc = 1;
+         /* Fall through.  */
        case R_PPC64_TPREL34:
+       case R_PPC64_TPREL16:
+       case R_PPC64_TPREL16_DS:
+       case R_PPC64_TPREL16_LO:
+       case R_PPC64_TPREL16_LO_DS:
          if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
@@ -5101,7 +5299,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              /* 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, 0))
-               return FALSE;
+               return false;
              h->pointer_equality_needed = 1;
            }
          /* Fall through.  */
@@ -5146,11 +5344,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        dodyn:
          if ((h != NULL
               && (h->root.type == bfd_link_hash_defweak
-                  || !h->def_regular))
+                  || (!h->def_regular && !h->root.ldscript_def)))
              || (h != NULL
-                 && !bfd_link_executable (info)
-                 && !SYMBOLIC_BIND (info, h))
+                 && !SYMBOL_REFERENCES_LOCAL (info, h))
              || (bfd_link_pic (info)
+                 && (h != NULL
+                     ? !bfd_is_abs_symbol (&h->root)
+                     : isym->st_shndx != SHN_ABS)
                  && must_be_dyn_reloc (info, r_type))
              || (!bfd_link_pic (info)
                  && ifunc != NULL))
@@ -5161,59 +5361,56 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (sreloc == NULL)
                {
                  sreloc = _bfd_elf_make_dynamic_reloc_section
-                   (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
+                   (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ true);
 
                  if (sreloc == NULL)
-                   return FALSE;
+                   return false;
                }
 
              /* If this is a global symbol, we count the number of
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
-                 struct elf_dyn_relocs *p;
-                 struct elf_dyn_relocs **head;
+                 struct ppc_dyn_relocs *p;
+                 struct ppc_dyn_relocs **head;
 
-                 head = &ppc_elf_hash_entry (h)->dyn_relocs;
+                 head = (struct ppc_dyn_relocs **) &h->dyn_relocs;
                  p = *head;
                  if (p == NULL || p->sec != sec)
                    {
                      p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                      if (p == NULL)
-                       return FALSE;
+                       return false;
                      p->next = *head;
                      *head = p;
                      p->sec = sec;
                      p->count = 0;
                      p->pc_count = 0;
+                     p->rel_count = 0;
                    }
                  p->count += 1;
                  if (!must_be_dyn_reloc (info, r_type))
                    p->pc_count += 1;
+                 if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
+                     && rel->r_offset % 2 == 0
+                     && sec->alignment_power != 0)
+                   p->rel_count += 1;
                }
              else
                {
-                 /* Track dynamic relocs needed for local syms too.
-                    We really need local syms available to do this
-                    easily.  Oh well.  */
-                 struct ppc_dyn_relocs *p;
-                 struct ppc_dyn_relocs **head;
-                 bfd_boolean is_ifunc;
+                 /* Track dynamic relocs needed for local syms too.  */
+                 struct ppc_local_dyn_relocs *p;
+                 struct ppc_local_dyn_relocs **head;
+                 bool is_ifunc;
                  asection *s;
                  void *vpp;
-                 Elf_Internal_Sym *isym;
-
-                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
-                                               abfd, r_symndx);
-                 if (isym == NULL)
-                   return FALSE;
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
                  if (s == NULL)
                    s = sec;
 
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct ppc_dyn_relocs **) vpp;
+                 head = (struct ppc_local_dyn_relocs **) vpp;
                  is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
                  p = *head;
                  if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
@@ -5222,14 +5419,19 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    {
                      p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                      if (p == NULL)
-                       return FALSE;
+                       return false;
                      p->next = *head;
                      *head = p;
                      p->sec = sec;
-                     p->ifunc = is_ifunc;
                      p->count = 0;
+                     p->rel_count = 0;
+                     p->ifunc = is_ifunc;
                    }
                  p->count += 1;
+                 if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
+                     && rel->r_offset % 2 == 0
+                     && sec->alignment_power != 0)
+                   p->rel_count += 1;
                }
            }
          break;
@@ -5239,26 +5441,26 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
   unsigned long iflags, oflags;
 
   if ((ibfd->flags & BFD_LINKER_CREATED) != 0)
-    return TRUE;
+    return true;
 
   if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd))
-    return TRUE;
+    return true;
 
   if (!_bfd_generic_verify_endian_match (ibfd, info))
-    return FALSE;
+    return false;
 
   iflags = elf_elfheader (ibfd)->e_flags;
   oflags = elf_elfheader (obfd)->e_flags;
@@ -5269,7 +5471,7 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
        /* xgettext:c-format */
        (_("%pB uses unknown e_flags 0x%lx"), ibfd, iflags);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
   else if (iflags != oflags && iflags != 0)
     {
@@ -5278,17 +5480,17 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
        (_("%pB: ABI version %ld is not compatible with ABI version %ld output"),
         ibfd, iflags, oflags);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
   if (!_bfd_elf_ppc_merge_fp_attributes (ibfd, info))
-    return FALSE;
+    return false;
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
   return _bfd_elf_merge_object_attributes (ibfd, info);
 }
 
-static bfd_boolean
+static bool
 ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr)
 {
   /* Print normal ELF private data.  */
@@ -5307,7 +5509,7 @@ ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr)
       fputc ('\n', file);
     }
 
-  return TRUE;
+  return true;
 }
 
 /* OFFSET in OPD_SEC specifies a function descriptor.  Return the address
@@ -5319,7 +5521,7 @@ opd_entry_value (asection *opd_sec,
                 bfd_vma offset,
                 asection **code_sec,
                 bfd_vma *code_off,
-                bfd_boolean in_code_sec)
+                bool in_code_sec)
 {
   bfd *opd_bfd = opd_sec->owner;
   Elf_Internal_Rela *relocs;
@@ -5377,7 +5579,7 @@ opd_entry_value (asection *opd_sec,
 
   relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
   if (relocs == NULL)
-    relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
+    relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, true);
   /* PR 17512: file: df8e1fd6.  */
   if (relocs == NULL)
     return (bfd_vma) -1;
@@ -5488,14 +5690,25 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
                              bfd_vma *code_off)
 {
   bfd_size_type size;
+  elf_symbol_type * elf_sym = (elf_symbol_type *) sym;
 
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
                     | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
     return 0;
 
-  size = 0;
-  if (!(sym->flags & BSF_SYNTHETIC))
-    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  size = (sym->flags & BSF_SYNTHETIC) ? 0 : elf_sym->internal_elf_sym.st_size;
+
+  /* In theory we should check that the symbol's type satisfies
+     _bfd_elf_is_function_type(), but there are some function-like
+     symbols which would fail this test.  (eg _start).  Instead
+     we check for hidden, local, notype symbols with zero size.
+     This type of symbol is generated by the annobin plugin for gcc
+     and clang, and should not be considered to be a function symbol.  */
+  if (size == 0
+      && ((sym->flags & (BSF_SYNTHETIC | BSF_LOCAL)) == BSF_LOCAL)
+      && ELF_ST_TYPE (elf_sym->internal_elf_sym.st_info) == STT_NOTYPE
+      && ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other) == STV_HIDDEN)
+    return 0;
 
   if (strcmp (sym->section->name, ".opd") == 0)
     {
@@ -5516,7 +5729,7 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
        }
 
       if (opd_entry_value (sym->section, symval,
-                          &sec, code_off, TRUE) == (bfd_vma) -1)
+                          &sec, code_off, true) == (bfd_vma) -1)
        return 0;
       /* An old ABI binary with dot-syms has a size of 24 on the .opd
         symbol.  This size has nothing to do with the code size of the
@@ -5539,16 +5752,16 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
        return 0;
       *code_off = sym->value;
     }
-  if (size == 0)
-    size = 1;
-  return size;
+
+  /* Do not return 0 for the function's size.  */
+  return size ? size : 1;
 }
 
 /* Return true if symbol is a strong function defined in an ELFv2
    object with st_other localentry bits of zero, ie. its local entry
    point coincides with its global entry point.  */
 
-static bfd_boolean
+static bool
 is_elfv2_localentry0 (struct elf_link_hash_entry *h)
 {
   return (h != NULL
@@ -5562,7 +5775,7 @@ is_elfv2_localentry0 (struct elf_link_hash_entry *h)
 
 /* Return true if symbol is defined in a regular object file.  */
 
-static bfd_boolean
+static bool
 is_static_defined (struct elf_link_hash_entry *h)
 {
   return ((h->root.type == bfd_link_hash_defined
@@ -5617,19 +5830,21 @@ defined_sym_val (struct elf_link_hash_entry *h)
 
 /* Return true if H matches __tls_get_addr or one of its variants.  */
 
-static bfd_boolean
+static bool
 is_tls_get_addr (struct elf_link_hash_entry *h,
                 struct ppc_link_hash_table *htab)
 {
-  return (h == &htab->tls_get_addr_fd->elf || h == &htab->tga_desc_fd->elf
-         || h == &htab->tls_get_addr->elf || h == &htab->tga_desc->elf);
+  return (h == elf_hash_entry (htab->tls_get_addr_fd)
+         || h == elf_hash_entry (htab->tga_desc_fd)
+         || h == elf_hash_entry (htab->tls_get_addr)
+         || h == elf_hash_entry (htab->tga_desc));
 }
 
-static bfd_boolean func_desc_adjust (struct elf_link_hash_entry *, void *);
+static bool func_desc_adjust (struct elf_link_hash_entry *, void *);
 
 /* Garbage collect sections, after first dealing with dot-symbols.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
@@ -5659,7 +5874,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
       asection *sec;
 
       eh = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym->name,
-                                                    FALSE, FALSE, TRUE));
+                                                    false, false, true));
       if (eh == NULL)
        continue;
       if (eh->elf.root.type != bfd_link_hash_defined
@@ -5675,7 +5890,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &sec, NULL, FALSE) != (bfd_vma) -1)
+                                  &sec, NULL, false) != (bfd_vma) -1)
        sec->flags |= SEC_KEEP;
 
       sec = eh->elf.root.u.def.section;
@@ -5687,7 +5902,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
    building shared libraries, we must assume that any visible symbol is
    referenced.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
@@ -5702,6 +5917,9 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
 
   if ((eh->elf.root.type == bfd_link_hash_defined
        || eh->elf.root.type == bfd_link_hash_defweak)
+      && (!eh->elf.start_stop
+         || eh->elf.root.ldscript_def
+         || !info->start_stop_gc)
       && ((eh->elf.ref_dynamic && !eh->elf.forced_local)
          || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
@@ -5733,11 +5951,11 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &code_sec, NULL, FALSE) != (bfd_vma) -1)
+                                  &code_sec, NULL, false) != (bfd_vma) -1)
        code_sec->flags |= SEC_KEEP;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Return the section that should be marked against GC for a given
@@ -5801,7 +6019,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                       && opd_entry_value (eh->elf.root.u.def.section,
                                           eh->elf.root.u.def.value,
-                                          &rsec, NULL, FALSE) != (bfd_vma) -1)
+                                          &rsec, NULL, false) != (bfd_vma) -1)
                eh->elf.root.u.def.section->gc_mark = 1;
              else
                rsec = h->root.u.def.section;
@@ -5848,7 +6066,7 @@ struct sfpr_def_parms
    If STUB_SEC is non-null, define alias symbols in STUB_SEC
    instead.  */
 
-static bfd_boolean
+static bool
 sfpr_define (struct bfd_link_info *info,
             const struct sfpr_def_parms *parm,
             asection *stub_sec)
@@ -5856,11 +6074,11 @@ sfpr_define (struct bfd_link_info *info,
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   unsigned int i;
   size_t len = strlen (parm->name);
-  bfd_boolean writing = FALSE;
+  bool writing = false;
   char sym[16];
 
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   memcpy (sym, parm->name, len);
   sym[len + 2] = 0;
@@ -5872,7 +6090,7 @@ sfpr_define (struct bfd_link_info *info,
       sym[len + 0] = i / 10 + '0';
       sym[len + 1] = i % 10 + '0';
       h = ppc_elf_hash_entry (elf_link_hash_lookup (&htab->elf, sym,
-                                                   writing, TRUE, TRUE));
+                                                   writing, true, true));
       if (stub_sec != NULL)
        {
          if (h != NULL
@@ -5882,9 +6100,9 @@ sfpr_define (struct bfd_link_info *info,
              struct elf_link_hash_entry *s;
              char buf[32];
              sprintf (buf, "%08x.%s", stub_sec->id & 0xffffffff, sym);
-             s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE);
+             s = elf_link_hash_lookup (&htab->elf, buf, true, true, false);
              if (s == NULL)
-               return FALSE;
+               return false;
              if (s->root.type == bfd_link_hash_new)
                {
                  s->root.type = bfd_link_hash_defined;
@@ -5912,14 +6130,14 @@ sfpr_define (struct bfd_link_info *info,
              h->elf.type = STT_FUNC;
              h->elf.def_regular = 1;
              h->elf.non_elf = 0;
-             _bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE);
-             writing = TRUE;
+             _bfd_elf_link_hash_hide_symbol (info, &h->elf, true);
+             writing = true;
              if (htab->sfpr->contents == NULL)
                {
                  htab->sfpr->contents
                    = bfd_alloc (htab->elf.dynobj, SFPR_MAX);
                  if (htab->sfpr->contents == NULL)
-                   return FALSE;
+                   return false;
                }
            }
        }
@@ -5934,7 +6152,7 @@ sfpr_define (struct bfd_link_info *info,
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 static bfd_byte *
@@ -6179,32 +6397,33 @@ tls_get_addr_epilogue (bfd *obfd, bfd_byte *p, struct ppc_link_hash_table *htab)
 
 /* Called via elf_link_hash_traverse to transfer dynamic linking
    information on function code symbol entries to their corresponding
-   function descriptor symbol entries.  */
+   function descriptor symbol entries.  Must not be called twice for
+   any given code symbol.  */
 
-static bfd_boolean
+static bool
 func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry *fh;
   struct ppc_link_hash_entry *fdh;
-  bfd_boolean force_local;
+  bool force_local;
 
   fh = ppc_elf_hash_entry (h);
   if (fh->elf.root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   if (!fh->is_func)
-    return TRUE;
+    return true;
 
   if (fh->elf.root.root.string[0] != '.'
       || fh->elf.root.root.string[1] == '\0')
-    return TRUE;
+    return true;
 
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* Find the corresponding function descriptor symbol.  */
   fdh = lookup_fdh (fh, htab);
@@ -6221,7 +6440,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
                          &fh->elf.root.u.def.section,
-                         &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1)
+                         &fh->elf.root.u.def.value, false) != (bfd_vma) -1)
     {
       fh->elf.root.type = fdh->elf.root.type;
       fh->elf.forced_local = 1;
@@ -6237,7 +6456,11 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL)
-       return TRUE;
+       {
+         if (fdh != NULL && fdh->fake)
+           _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, true);
+         return true;
+       }
     }
 
   /* Create a descriptor as undefined if necessary.  */
@@ -6248,7 +6471,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
     {
       fdh = make_fdh (info, fh);
       if (fdh == NULL)
-       return FALSE;
+       return false;
     }
 
   /* We can't support overriding of symbols on a fake descriptor.  */
@@ -6256,7 +6479,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       && fdh->fake
       && (fh->elf.root.type == bfd_link_hash_defined
          || fh->elf.root.type == bfd_link_hash_defweak))
-    _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
+    _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, true);
 
   /* Transfer dynamic linking information to the function descriptor.  */
   if (fdh != NULL)
@@ -6274,7 +6497,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       if (!fdh->elf.forced_local
          && fh->elf.dynindx != -1)
        if (!bfd_elf_link_record_dynamic_symbol (info, &fdh->elf))
-         return FALSE;
+         return false;
     }
 
   /* Now that the info is on the function descriptor, clear the
@@ -6290,7 +6513,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
                 || fdh->elf.forced_local);
   _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
 
-  return TRUE;
+  return true;
 }
 
 static const struct sfpr_def_parms save_res_funcs[] =
@@ -6310,19 +6533,22 @@ static const struct sfpr_def_parms save_res_funcs[] =
   };
 
 /* Called near the start of bfd_elf_size_dynamic_sections.  We use
-   this hook to a) provide some gcc support functions, and b) transfer
-   dynamic linking information gathered so far on function code symbol
-   entries, to their corresponding function descriptor symbol entries.  */
+   this hook to a) run the edit functions in this file, b) provide
+   some gcc support functions, and c) transfer dynamic linking
+   information gathered so far on function code symbol entries, to
+   their corresponding function descriptor symbol entries.  */
 
-static bfd_boolean
-ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
-                           struct bfd_link_info *info)
+static bool
+ppc64_elf_edit (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
+
+  /* Call back into the linker, which then runs the edit functions.  */
+  htab->params->edit ();
 
   /* Provide any missing _save* and _rest* functions.  */
   if (htab->sfpr != NULL)
@@ -6332,17 +6558,17 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
       htab->sfpr->size = 0;
       for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
        if (!sfpr_define (info, &save_res_funcs[i], NULL))
-         return FALSE;
+         return false;
       if (htab->sfpr->size == 0)
        htab->sfpr->flags |= SEC_EXCLUDE;
     }
 
   if (bfd_link_relocatable (info))
-    return TRUE;
+    return true;
 
   if (htab->elf.hgot != NULL)
     {
-      _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
+      _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, true);
       /* Make .TOC. defined so as to prevent it being made dynamic.
         The wrong value here is fixed later in ppc64_elf_set_toc.  */
       if (!htab->elf.hgot->def_regular
@@ -6359,83 +6585,59 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
        = (htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
     }
 
-  if (htab->need_func_desc_adj)
-    {
-      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
-      htab->need_func_desc_adj = 0;
-    }
-
-  return TRUE;
-}
-
-/* Find dynamic relocs for H that apply to read-only sections.  */
-
-static asection *
-readonly_dynrelocs (struct elf_link_hash_entry *h)
-{
-  struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
-  struct elf_dyn_relocs *p;
-
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection *s = p->sec->output_section;
-
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
-       return p->sec;
-    }
-  return NULL;
+  return true;
 }
 
 /* Return true if we have dynamic relocs against H or any of its weak
    aliases, that apply to read-only sections.  Cannot be used after
    size_dynamic_sections.  */
 
-static bfd_boolean
+static bool
 alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
 {
   struct ppc_link_hash_entry *eh = ppc_elf_hash_entry (h);
   do
     {
-      if (readonly_dynrelocs (&eh->elf))
-       return TRUE;
+      if (_bfd_elf_readonly_dynrelocs (&eh->elf))
+       return true;
       eh = ppc_elf_hash_entry (eh->elf.u.alias);
     }
   while (eh != NULL && &eh->elf != h);
 
-  return FALSE;
+  return false;
 }
 
 /* Return whether EH has pc-relative dynamic relocs.  */
 
-static bfd_boolean
+static bool
 pc_dynrelocs (struct ppc_link_hash_entry *eh)
 {
-  struct elf_dyn_relocs *p;
+  struct ppc_dyn_relocs *p;
 
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  for (p = (struct ppc_dyn_relocs *) eh->elf.dyn_relocs; p != NULL; p = p->next)
     if (p->pc_count != 0)
-      return TRUE;
-  return FALSE;
+      return true;
+  return false;
 }
 
 /* Return true if a global entry stub will be created for H.  Valid
    for ELFv2 before plt entries have been allocated.  */
 
-static bfd_boolean
+static bool
 global_entry_stub (struct elf_link_hash_entry *h)
 {
   struct plt_entry *pent;
 
   if (!h->pointer_equality_needed
       || h->def_regular)
-    return FALSE;
+    return false;
 
   for (pent = h->plt.plist; pent != NULL; pent = pent->next)
     if (pent->plt.refcount > 0
        && pent->addend == 0)
-      return TRUE;
+      return true;
 
-  return FALSE;
+  return false;
 }
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
@@ -6444,7 +6646,7 @@ global_entry_stub (struct elf_link_hash_entry *h)
    change the definition to something the rest of the link can
    understand.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h)
 {
@@ -6453,16 +6655,16 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
       || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
-      bfd_boolean local = (ppc_elf_hash_entry (h)->save_res
-                          || SYMBOL_CALLS_LOCAL (info, h)
-                          || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
+      bool local = (ppc_elf_hash_entry (h)->save_res
+                   || SYMBOL_CALLS_LOCAL (info, h)
+                   || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
       /* Discard dyn_relocs when non-pic if we've decided that a
         function symbol is local and not an ifunc.  We keep dynamic
         relocs for ifuncs when local rather than always emitting a
@@ -6475,7 +6677,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       if (!bfd_link_pic (info)
          && h->type != STT_GNU_IFUNC
          && local)
-       ppc_elf_hash_entry (h)->dyn_relocs = NULL;
+       h->dyn_relocs = NULL;
 
       /* Clear procedure linkage table information for any symbol that
         won't need a .plt entry.  */
@@ -6505,7 +6707,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             extra work in ld.so when resolving these symbols.  */
          if (global_entry_stub (h))
            {
-             if (!readonly_dynrelocs (h))
+             if (!_bfd_elf_readonly_dynrelocs (h))
                {
                  h->pointer_equality_needed = 0;
                  /* If we haven't seen a branch reloc and the symbol
@@ -6516,20 +6718,20 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
              else if (!bfd_link_pic (info))
                /* We are going to be defining the function symbol on the
                   plt stub, so no dyn_relocs needed when non-pic.  */
-               ppc_elf_hash_entry (h)->dyn_relocs = NULL;
+               h->dyn_relocs = NULL;
            }
 
          /* ELFv2 function symbols can't have copy relocs.  */
-         return TRUE;
+         return true;
        }
       else if (!h->needs_plt
-              && !readonly_dynrelocs (h))
+              && !_bfd_elf_readonly_dynrelocs (h))
        {
          /* If we haven't seen a branch reloc and the symbol isn't an
             ifunc then we don't need a plt entry.  */
          h->plt.plist = NULL;
          h->pointer_equality_needed = 0;
-         return TRUE;
+         return true;
        }
     }
   else
@@ -6546,8 +6748,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->root.u.def.value = def->root.u.def.value;
       if (def->root.u.def.section == htab->elf.sdynbss
          || def->root.u.def.section == htab->elf.sdynrelro)
-       ppc_elf_hash_entry (h)->dyn_relocs = NULL;
-      return TRUE;
+       h->dyn_relocs = NULL;
+      return true;
     }
 
   /* If we are creating a shared library, we must presume that the
@@ -6555,12 +6757,12 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
   if (!bfd_link_executable (info))
-    return TRUE;
+    return true;
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
   if (!h->non_got_ref)
-    return TRUE;
+    return true;
 
   /* Don't generate a copy reloc for symbols defined in the executable.  */
   if (!h->def_dynamic || !h->ref_regular || h->def_regular
@@ -6579,7 +6781,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         definition for the variable.  Text relocations are preferable
         to an incorrect program.  */
       || h->protected_def)
-    return TRUE;
+    return true;
 
   if (h->type == STT_FUNC
       || h->type == STT_GNU_IFUNC)
@@ -6591,7 +6793,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         That's wrong for copying a descriptor.  */
       if (ppc_elf_hash_entry (h)->oh == NULL
          || !(h->size == 24 || h->size == 16))
-       return TRUE;
+       return true;
 
       /* We should never get here, but unfortunately there are old
         versions of gcc (circa gcc-3.2) that improperly for the
@@ -6636,7 +6838,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     }
 
   /* We no longer want dyn_relocs.  */
-  ppc_elf_hash_entry (h)->dyn_relocs = NULL;
+  h->dyn_relocs = NULL;
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
@@ -6645,7 +6847,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 static void
 ppc64_elf_hide_symbol (struct bfd_link_info *info,
                       struct elf_link_hash_entry *h,
-                      bfd_boolean force_local)
+                      bool force_local)
 {
   struct ppc_link_hash_entry *eh;
   _bfd_elf_link_hash_hide_symbol (info, h, force_local);
@@ -6676,8 +6878,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
          p = eh->elf.root.root.string - 1;
          save = *p;
          *(char *) p = '.';
-         fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE,
-                                                        FALSE, FALSE));
+         fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, false,
+                                                        false, false));
          *(char *) p = save;
 
          /* Unfortunately, if it so happens that the string we were
@@ -6690,8 +6892,8 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
              while (q >= eh->elf.root.root.string && *q == *p)
                --q, --p;
              if (q < eh->elf.root.root.string && *p == '.')
-               fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, FALSE,
-                                                              FALSE, FALSE));
+               fh = ppc_elf_hash_entry (elf_link_hash_lookup (htab, p, false,
+                                                              false, false));
            }
          if (fh != NULL)
            {
@@ -6704,7 +6906,7 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
     }
 }
 
-static bfd_boolean
+static bool
 get_sym_h (struct elf_link_hash_entry **hp,
           Elf_Internal_Sym **symp,
           asection **symsecp,
@@ -6754,7 +6956,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
                                            symtab_hdr->sh_info,
                                            0, NULL, NULL, NULL);
          if (locsyms == NULL)
-           return FALSE;
+           return false;
          *locsymsp = locsyms;
        }
       sym = locsyms + r_symndx;
@@ -6786,7 +6988,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
          *tls_maskp = tls_mask;
        }
     }
-  return TRUE;
+  return true;
 }
 
 /* Returns TLS_MASKP for the given REL symbol.  Function return is 0 on
@@ -6896,7 +7098,7 @@ tocsave_find (struct ppc_link_hash_table *htab,
 /* Adjust all global syms defined in opd sections.  In gcc generated
    code for the old ABI, these will already have been done.  */
 
-static bfd_boolean
+static bool
 adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
 {
   struct ppc_link_hash_entry *eh;
@@ -6904,15 +7106,15 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   struct _opd_sec_data *opd;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   if (h->root.type != bfd_link_hash_defined
       && h->root.type != bfd_link_hash_defweak)
-    return TRUE;
+    return true;
 
   eh = ppc_elf_hash_entry (h);
   if (eh->adjust_done)
-    return TRUE;
+    return true;
 
   sym_sec = eh->elf.root.u.def.section;
   opd = get_opd_info (sym_sec);
@@ -6939,15 +7141,15 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
        eh->elf.root.u.def.value += adjust;
       eh->adjust_done = 1;
     }
-  return TRUE;
+  return true;
 }
 
 /* Handles decrementing dynamic reloc counts for the reloc specified by
    R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM
    have already been determined.  */
 
-static bfd_boolean
-dec_dynrel_count (bfd_vma r_info,
+static bool
+dec_dynrel_count (const Elf_Internal_Rela *rel,
                  asection *sec,
                  struct bfd_link_info *info,
                  Elf_Internal_Sym **local_syms,
@@ -6959,11 +7161,11 @@ dec_dynrel_count (bfd_vma r_info,
 
   /* Can this reloc be dynamic?  This switch, and later tests here
      should be kept in sync with the code in check_relocs.  */
-  r_type = ELF64_R_TYPE (r_info);
+  r_type = ELF64_R_TYPE (rel->r_info);
   switch (r_type)
     {
     default:
-      return TRUE;
+      return true;
 
     case R_PPC64_TOC16:
     case R_PPC64_TOC16_DS:
@@ -6972,7 +7174,7 @@ dec_dynrel_count (bfd_vma r_info,
     case R_PPC64_TOC16_HA:
     case R_PPC64_TOC16_LO_DS:
       if (h == NULL)
-       return TRUE;
+       return true;
       break;
 
     case R_PPC64_TPREL16:
@@ -7033,18 +7235,20 @@ dec_dynrel_count (bfd_vma r_info,
       unsigned long r_symndx;
       bfd *ibfd = sec->owner;
 
-      r_symndx = ELF64_R_SYM (r_info);
+      r_symndx = ELF64_R_SYM (rel->r_info);
       if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
-       return FALSE;
+       return false;
     }
 
   if ((h != NULL
        && (h->root.type == bfd_link_hash_defweak
-          || !h->def_regular))
+          || (!h->def_regular && !h->root.ldscript_def)))
       || (h != NULL
-         && !bfd_link_executable (info)
-         && !SYMBOLIC_BIND (info, h))
+         && !SYMBOL_REFERENCES_LOCAL (info, h))
       || (bfd_link_pic (info)
+         && (h != NULL
+             ? !bfd_is_abs_symbol (&h->root)
+             : sym_sec != bfd_abs_section_ptr)
          && must_be_dyn_reloc (info, r_type))
       || (!bfd_link_pic (info)
          && (h != NULL
@@ -7052,20 +7256,20 @@ dec_dynrel_count (bfd_vma r_info,
              : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
     ;
   else
-    return TRUE;
+    return true;
 
   if (h != NULL)
     {
-      struct elf_dyn_relocs *p;
-      struct elf_dyn_relocs **pp;
-      pp = &ppc_elf_hash_entry (h)->dyn_relocs;
+      struct ppc_dyn_relocs *p;
+      struct ppc_dyn_relocs **pp;
+      pp = (struct ppc_dyn_relocs **) &h->dyn_relocs;
 
       /* elf_gc_sweep may have already removed all dyn relocs associated
         with local syms for a given section.  Also, symbol flags are
         changed by elf_gc_sweep_symbol, confusing the test above.  Don't
         report a dynreloc miscount.  */
       if (*pp == NULL && info->gc_sections)
-       return TRUE;
+       return true;
 
       while ((p = *pp) != NULL)
        {
@@ -7073,20 +7277,24 @@ dec_dynrel_count (bfd_vma r_info,
            {
              if (!must_be_dyn_reloc (info, r_type))
                p->pc_count -= 1;
+             if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
+                 && rel->r_offset % 2 == 0
+                 && sec->alignment_power != 0)
+               p->rel_count -= 1;
              p->count -= 1;
              if (p->count == 0)
                *pp = p->next;
-             return TRUE;
+             return true;
            }
          pp = &p->next;
        }
     }
   else
     {
-      struct ppc_dyn_relocs *p;
-      struct ppc_dyn_relocs **pp;
+      struct ppc_local_dyn_relocs *p;
+      struct ppc_local_dyn_relocs **pp;
       void *vpp;
-      bfd_boolean is_ifunc;
+      bool is_ifunc;
 
       if (local_syms == NULL)
        sym_sec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
@@ -7094,20 +7302,24 @@ dec_dynrel_count (bfd_vma r_info,
        sym_sec = sec;
 
       vpp = &elf_section_data (sym_sec)->local_dynrel;
-      pp = (struct ppc_dyn_relocs **) vpp;
+      pp = (struct ppc_local_dyn_relocs **) vpp;
 
       if (*pp == NULL && info->gc_sections)
-       return TRUE;
+       return true;
 
       is_ifunc = ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC;
       while ((p = *pp) != NULL)
        {
          if (p->sec == sec && p->ifunc == is_ifunc)
            {
+             if ((r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
+                 && rel->r_offset % 2 == 0
+                 && sec->alignment_power != 0)
+               p->rel_count -= 1;
              p->count -= 1;
              if (p->count == 0)
                *pp = p->next;
-             return TRUE;
+             return true;
            }
          pp = &p->next;
        }
@@ -7117,7 +7329,7 @@ dec_dynrel_count (bfd_vma r_info,
   _bfd_error_handler (_("dynreloc miscount for %pB, section %pA"),
                      sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
-  return FALSE;
+  return false;
 }
 
 /* Remove unused Official Procedure Descriptor entries.  Currently we
@@ -7126,17 +7338,17 @@ dec_dynrel_count (bfd_vma r_info,
    would be possible to remove many more entries for statically linked
    applications.  */
 
-bfd_boolean
+bool
 ppc64_elf_edit_opd (struct bfd_link_info *info)
 {
   bfd *ibfd;
-  bfd_boolean some_edited = FALSE;
+  bool some_edited = false;
   asection *need_pad = NULL;
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
@@ -7145,7 +7357,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
       struct _opd_sec_data *opd;
-      bfd_boolean need_edit, add_aux_fields, broken;
+      bool need_edit, add_aux_fields, broken;
       bfd_size_type cnt_16b = 0;
 
       if (!is_ppc64_elf (ibfd))
@@ -7172,12 +7384,12 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
       relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
                                            info->keep_memory);
       if (relstart == NULL)
-       return FALSE;
+       return false;
 
       /* First run through the relocs to check they are sane, and to
         determine whether we need to edit this opd section.  */
-      need_edit = FALSE;
-      broken = FALSE;
+      need_edit = false;
+      broken = false;
       need_pad = sec;
       relend = relstart + sec->reloc_count;
       for (rel = relstart; rel < relend; )
@@ -7204,7 +7416,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
            broken_opd:
              _bfd_error_handler
                (_("%pB: .opd is not a regular array of opd entries"), ibfd);
-             broken = TRUE;
+             broken = true;
              break;
            }
 
@@ -7215,7 +7427,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                /* xgettext:c-format */
                (_("%pB: unexpected reloc type %u in .opd section"),
                 ibfd, r_type);
-             broken = TRUE;
+             broken = true;
              break;
            }
 
@@ -7237,7 +7449,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                /* xgettext:c-format */
                (_("%pB: undefined sym `%s' in .opd section"),
                 ibfd, sym_name);
-             broken = TRUE;
+             broken = true;
              break;
            }
 
@@ -7250,7 +7462,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
             which we test for via the output_section.  */
          if (sym_sec->owner != ibfd
              || sym_sec->output_section == bfd_abs_section_ptr)
-           need_edit = TRUE;
+           need_edit = true;
 
          rel += 2;
          if (rel + 1 == relend
@@ -7300,7 +7512,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
          opd = &ppc64_elf_section_data (sec)->u.opd;
          opd->adjust = bfd_zalloc (sec->owner, amt);
          if (opd->adjust == NULL)
-           return FALSE;
+           return false;
 
          /* This seems a waste of time as input .opd sections are all
             zeros as generated by gcc, but I suppose there's no reason
@@ -7311,15 +7523,13 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
              bfd_byte *loc;
              if (!bfd_malloc_and_get_section (ibfd, sec, &loc))
                {
-                 if (loc != NULL)
-                   free (loc);
+                 free (loc);
                error_ret:
-                 if (local_syms != NULL
-                     && symtab_hdr->contents != (unsigned char *) local_syms)
+                 if (symtab_hdr->contents != (unsigned char *) local_syms)
                    free (local_syms);
                  if (elf_section_data (sec)->relocs != relstart)
                    free (relstart);
-                 return FALSE;
+                 return false;
                }
              sec->contents = loc;
              sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
@@ -7332,7 +7542,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
            {
              new_contents = bfd_malloc (sec->size + cnt_16b * 8);
              if (new_contents == NULL)
-               return FALSE;
+               return false;
              need_pad = NULL;
            }
          wptr = new_contents;
@@ -7347,7 +7557,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
              Elf_Internal_Sym *sym;
              long opd_ent_size;
              Elf_Internal_Rela *next_rel;
-             bfd_boolean skip;
+             bool skip;
 
              r_symndx = ELF64_R_SYM (rel->r_info);
              if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
@@ -7403,7 +7613,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                  else
                    while (1)
                      {
-                       if (!dec_dynrel_count (rel->r_info, sec, info,
+                       if (!dec_dynrel_count (rel, sec, info,
                                               NULL, h, sym))
                          goto error_ret;
 
@@ -7478,7 +7688,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
             elf_bfd_final_link if we are emitting relocs.  */
          rel_hdr = _bfd_elf_single_rel_hdr (sec);
          rel_hdr->sh_size = sec->reloc_count * rel_hdr->sh_entsize;
-         some_edited = TRUE;
+         some_edited = true;
        }
       else if (elf_section_data (sec)->relocs != relstart)
        free (relstart);
@@ -7508,11 +7718,11 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
 
          p = bfd_malloc (need_pad->size + 8);
          if (p == NULL)
-           return FALSE;
+           return false;
 
          if (!bfd_get_section_contents (need_pad->owner, need_pad,
                                         p, 0, need_pad->size))
-           return FALSE;
+           return false;
 
          need_pad->contents = p;
          need_pad->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
@@ -7521,7 +7731,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
        {
          p = bfd_realloc (need_pad->contents, need_pad->size + 8);
          if (p == NULL)
-           return FALSE;
+           return false;
 
          need_pad->contents = p;
        }
@@ -7530,13 +7740,13 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
       need_pad->size += 8;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Analyze inline PLT call relocations to see whether calls to locally
    defined functions can be converted to direct calls.  */
 
-bfd_boolean
+bool
 ppc64_elf_inline_plt (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -7546,7 +7756,7 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* A bl insn can reach -0x2000000 to 0x1fffffc.  The limit is
      reduced somewhat to cater for possible stubs that might be added
@@ -7581,7 +7791,7 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
   if (high_vma - low_vma < limit)
     {
       htab->can_convert_all_inline_plt = 1;
-      return TRUE;
+      return true;
     }
 
   /* Otherwise, go looking through relocs for cases where a direct
@@ -7618,10 +7828,10 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
            relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
                                                  info->keep_memory);
            if (relstart == NULL)
-             return FALSE;
+             return false;
 
            relend = relstart + sec->reloc_count;
-           for (rel = relstart; rel < relend; )
+           for (rel = relstart; rel < relend; rel++)
              {
                enum elf_ppc64_reloc_type r_type;
                unsigned long r_symndx;
@@ -7641,10 +7851,9 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
                  {
                    if (elf_section_data (sec)->relocs != relstart)
                      free (relstart);
-                   if (local_syms != NULL
-                       && symtab_hdr->contents != (bfd_byte *) local_syms)
+                   if (symtab_hdr->contents != (bfd_byte *) local_syms)
                      free (local_syms);
-                   return FALSE;
+                   return false;
                  }
 
                if (sym_sec != NULL && sym_sec->output_section != NULL)
@@ -7682,12 +7891,14 @@ ppc64_elf_inline_plt (struct bfd_link_info *info)
        }
     }
 
-  return TRUE;
+  return true;
 }
 
-/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
+/* Set htab->tls_get_addr and various other info specific to TLS.
+   This needs to run before dynamic symbols are processed in
+   bfd_elf_size_dynamic_sections.  */
 
-asection *
+bool
 ppc64_elf_tls_setup (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -7695,7 +7906,14 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return NULL;
+    return false;
+
+  /* Move dynamic linking info to the function descriptor sym.  */
+  if (htab->need_func_desc_adj)
+    {
+      elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
+      htab->need_func_desc_adj = 0;
+    }
 
   if (abiversion (info->output_bfd) == 1)
     htab->opd_abi = 1;
@@ -7721,31 +7939,38 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
      --plt-localentry can cause trouble.  */
   if (htab->params->plt_localentry0 < 0)
     htab->params->plt_localentry0 = 0;
+  if (htab->params->plt_localentry0 && htab->has_power10_relocs)
+    {
+      /* The issue is that __glink_PLTresolve saves r2, which is done
+        because glibc ld.so _dl_runtime_resolve restores r2 to support
+        a glibc plt call optimisation where global entry code is
+        skipped on calls that resolve to the same binary.  The
+        __glink_PLTresolve save of r2 is incompatible with code
+        making tail calls, because the tail call might go via the
+        resolver and thus overwrite the proper saved r2.  */
+      _bfd_error_handler (_("warning: --plt-localentry is incompatible with "
+                           "power10 pc-relative code"));
+      htab->params->plt_localentry0 = 0;
+    }
   if (htab->params->plt_localentry0
       && elf_link_hash_lookup (&htab->elf, "GLIBC_2.26",
-                              FALSE, FALSE, FALSE) == NULL)
+                              false, false, false) == NULL)
     _bfd_error_handler
       (_("warning: --plt-localentry is especially dangerous without "
         "ld.so support to detect ABI violations"));
 
   tga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
-                             FALSE, FALSE, TRUE);
+                             false, false, true);
   htab->tls_get_addr = ppc_elf_hash_entry (tga);
-
-  /* Move dynamic linking info to the function descriptor sym.  */
-  if (tga != NULL)
-    func_desc_adjust (tga, info);
   tga_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
-                                FALSE, FALSE, TRUE);
+                                false, false, true);
   htab->tls_get_addr_fd = ppc_elf_hash_entry (tga_fd);
 
   desc = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_desc",
-                              FALSE, FALSE, TRUE);
+                              false, false, true);
   htab->tga_desc = ppc_elf_hash_entry (desc);
-  if (desc != NULL)
-    func_desc_adjust (desc, info);
   desc_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_desc",
-                                 FALSE, FALSE, TRUE);
+                                 false, false, true);
   htab->tga_desc_fd = ppc_elf_hash_entry (desc_fd);
 
   if (htab->params->tls_get_addr_opt)
@@ -7753,11 +7978,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
       struct elf_link_hash_entry *opt, *opt_fd;
 
       opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt",
-                                 FALSE, FALSE, TRUE);
-      if (opt != NULL)
-       func_desc_adjust (opt, info);
+                                 false, false, true);
       opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
-                                    FALSE, FALSE, TRUE);
+                                    false, false, true);
       if (opt_fd != NULL
          && (opt_fd->root.type == bfd_link_hash_defined
              || opt_fd->root.type == bfd_link_hash_defweak))
@@ -7817,12 +8040,12 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
                      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
                                              opt_fd->dynstr_index);
                      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
-                       return NULL;
+                       return false;
                    }
                  if (tga_fd != NULL)
                    {
                      htab->tls_get_addr_fd = ppc_elf_hash_entry (opt_fd);
-                     tga = &htab->tls_get_addr->elf;
+                     tga = elf_hash_entry (htab->tls_get_addr);
                      if (opt != NULL && tga != NULL)
                        {
                          tga->root.type = bfd_link_hash_indirect;
@@ -7876,19 +8099,19 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
       && htab->params->no_tls_get_addr_regsave == -1)
     htab->params->no_tls_get_addr_regsave = 0;
 
-  return _bfd_elf_tls_setup (info->output_bfd, info);
+  return true;
 }
 
 /* Return TRUE iff REL is a branch reloc with a global symbol matching
    any of HASH1, HASH2, HASH3, or HASH4.  */
 
-static bfd_boolean
-branch_reloc_hash_match (const bfd *ibfd,
-                        const Elf_Internal_Rela *rel,
-                        const struct ppc_link_hash_entry *hash1,
-                        const struct ppc_link_hash_entry *hash2,
-                        const struct ppc_link_hash_entry *hash3,
-                        const struct ppc_link_hash_entry *hash4)
+static bool
+branch_reloc_hash_match (bfd *ibfd,
+                        Elf_Internal_Rela *rel,
+                        struct ppc_link_hash_entry *hash1,
+                        struct ppc_link_hash_entry *hash2,
+                        struct ppc_link_hash_entry *hash3,
+                        struct ppc_link_hash_entry *hash4)
 {
   Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
   enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
@@ -7901,11 +8124,13 @@ branch_reloc_hash_match (const bfd *ibfd,
 
       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
       h = elf_follow_link (h);
-      if (h == &hash1->elf || h == &hash2->elf
-         || h == &hash3->elf || h == &hash4->elf)
-       return TRUE;
+      if (h == elf_hash_entry (hash1)
+         || h == elf_hash_entry (hash2)
+         || h == elf_hash_entry (hash3)
+         || h == elf_hash_entry (hash4))
+       return true;
     }
-  return FALSE;
+  return false;
 }
 
 /* Run through all the TLS relocs looking for optimization
@@ -7915,7 +8140,7 @@ branch_reloc_hash_match (const bfd *ibfd,
    to know the tp offset, and we need to optimize before allocating
    dynamic relocations.  */
 
-bfd_boolean
+bool
 ppc64_elf_tls_optimize (struct bfd_link_info *info)
 {
   bfd *ibfd;
@@ -7925,11 +8150,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
   int pass;
 
   if (!bfd_link_executable (info))
-    return TRUE;
+    return true;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
+
+  htab->do_tls_opt = 1;
 
   /* Make two passes over the relocs.  On the first pass, mark toc
      entries involved with tls relocs, and check that tls relocs
@@ -7949,7 +8176,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
            {
              Elf_Internal_Rela *relstart, *rel, *relend;
-             bfd_boolean found_tls_get_addr_arg = 0;
+             bool found_tls_get_addr_arg = 0;
 
              /* Read the relocations.  */
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -7957,7 +8184,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
              if (relstart == NULL)
                {
                  free (toc_ref);
-                 return FALSE;
+                 return false;
                }
 
              relend = relstart + sec->reloc_count;
@@ -7971,10 +8198,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                  unsigned char *tls_mask;
                  unsigned int tls_set, tls_clear, tls_type = 0;
                  bfd_vma value;
-                 bfd_boolean ok_tprel, is_local;
+                 bool ok_tprel, is_local;
                  long toc_ref_index = 0;
                  int expecting_tls_get_addr = 0;
-                 bfd_boolean ret = FALSE;
+                 bool ret = false;
 
                  r_symndx = ELF64_R_SYM (rel->r_info);
                  if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms,
@@ -7983,11 +8210,9 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    err_free_rel:
                      if (elf_section_data (sec)->relocs != relstart)
                        free (relstart);
-                     if (toc_ref != NULL)
-                       free (toc_ref);
-                     if (locsyms != NULL
-                         && (elf_symtab_hdr (ibfd).contents
-                             != (unsigned char *) locsyms))
+                     free (toc_ref);
+                     if (elf_symtab_hdr (ibfd).contents
+                         != (unsigned char *) locsyms)
                        free (locsyms);
                      return ret;
                    }
@@ -8010,13 +8235,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                       STT_TLS.  So no need for .opd local sym adjust.  */
                    value = sym->st_value;
 
-                 ok_tprel = FALSE;
+                 ok_tprel = false;
                  is_local = SYMBOL_REFERENCES_LOCAL (info, h);
                  if (is_local)
                    {
                      if (h != NULL
                          && h->root.type == bfd_link_hash_undefweak)
-                       ok_tprel = TRUE;
+                       ok_tprel = true;
                      else if (sym_sec != NULL
                               && sym_sec->output_section != NULL)
                        {
@@ -8050,7 +8275,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      info->callbacks->minfo (_("%H __tls_get_addr lost arg, "
                                                "TLS optimization disabled\n"),
                                              ibfd, sec, rel->r_offset);
-                     ret = TRUE;
+                     ret = true;
                      goto err_free_rel;
                    }
 
@@ -8059,7 +8284,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:
+                   case R_PPC64_GOT_TLSLD_PCREL34:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                      /* Fall through.  */
@@ -8080,7 +8305,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:
+                   case R_PPC64_GOT_TLSGD_PCREL34:
                      expecting_tls_get_addr = 1;
                      found_tls_get_addr_arg = 1;
                      /* Fall through. */
@@ -8097,7 +8322,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      tls_type = TLS_TLS | TLS_GD;
                      break;
 
-                   case R_PPC64_GOT_TPREL34:
+                   case R_PPC64_GOT_TPREL_PCREL34:
                    case R_PPC64_GOT_TPREL16_DS:
                    case R_PPC64_GOT_TPREL16_LO_DS:
                    case R_PPC64_GOT_TPREL16_HI:
@@ -8237,6 +8462,42 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                        }
                      break;
 
+                   case R_PPC64_TPREL16_HA:
+                     if (pass == 0)
+                       {
+                         unsigned char buf[4];
+                         unsigned int insn;
+                         bfd_vma off = rel->r_offset & ~3;
+                         if (!bfd_get_section_contents (ibfd, sec, buf,
+                                                        off, 4))
+                           goto err_free_rel;
+                         insn = bfd_get_32 (ibfd, buf);
+                         /* addis rt,13,imm */
+                         if ((insn & ((0x3fu << 26) | 0x1f << 16))
+                             != ((15u << 26) | (13 << 16)))
+                           {
+                             /* xgettext:c-format */
+                             info->callbacks->minfo
+                               (_("%H: warning: %s unexpected insn %#x.\n"),
+                                ibfd, sec, off, "R_PPC64_TPREL16_HA", insn);
+                             htab->do_tls_opt = 0;
+                           }
+                       }
+                     continue;
+
+                   case R_PPC64_TPREL16_HI:
+                   case R_PPC64_TPREL16_HIGH:
+                   case R_PPC64_TPREL16_HIGHA:
+                   case R_PPC64_TPREL16_HIGHER:
+                   case R_PPC64_TPREL16_HIGHERA:
+                   case R_PPC64_TPREL16_HIGHEST:
+                   case R_PPC64_TPREL16_HIGHESTA:
+                     /* These can all be used in sequences along with
+                        TPREL16_LO or TPREL16_LO_DS in ways we aren't
+                        able to verify easily.  */
+                     htab->do_tls_opt = 0;
+                     continue;
+
                    default:
                      continue;
                    }
@@ -8285,7 +8546,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
                                                "TLS optimization disabled\n"),
                                              ibfd, sec, rel->r_offset);
-                     ret = TRUE;
+                     ret = true;
                      goto err_free_rel;
                    }
 
@@ -8372,15 +8633,15 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    {
                      /* If we got rid of a DTPMOD/DTPREL reloc pair then
                         we'll lose one or two dyn relocs.  */
-                     if (!dec_dynrel_count (rel->r_info, sec, info,
+                     if (!dec_dynrel_count (rel, sec, info,
                                             NULL, h, sym))
-                       return FALSE;
+                       return false;
 
                      if (tls_set == (TLS_EXPLICIT | TLS_GD))
                        {
-                         if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
+                         if (!dec_dynrel_count (rel + 1, sec, info,
                                                 NULL, h, sym))
-                           return FALSE;
+                           return false;
                        }
                    }
 
@@ -8402,10 +8663,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
          }
       }
 
-  if (toc_ref != NULL)
-    free (toc_ref);
-  htab->do_tls_opt = 1;
-  return TRUE;
+  free (toc_ref);
+  return true;
 }
 
 /* Called via elf_link_hash_traverse from ppc64_elf_edit_toc to adjust
@@ -8418,12 +8677,12 @@ struct adjust_toc_info
 {
   asection *toc;
   unsigned long *skip;
-  bfd_boolean global_toc_syms;
+  bool global_toc_syms;
 };
 
 enum toc_skip_enum { ref_from_discarded = 1, can_optimize = 2 };
 
-static bfd_boolean
+static bool
 adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 {
   struct ppc_link_hash_entry *eh;
@@ -8432,11 +8691,11 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 
   if (h->root.type != bfd_link_hash_defined
       && h->root.type != bfd_link_hash_defweak)
-    return TRUE;
+    return true;
 
   eh = ppc_elf_hash_entry (h);
   if (eh->adjust_done)
-    return TRUE;
+    return true;
 
   if (eh->elf.root.u.def.section == toc_inf->toc)
     {
@@ -8459,15 +8718,15 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
       eh->adjust_done = 1;
     }
   else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
-    toc_inf->global_toc_syms = TRUE;
+    toc_inf->global_toc_syms = true;
 
-  return TRUE;
+  return true;
 }
 
 /* Return TRUE iff INSN with a relocation of R_TYPE is one we expect
    on a _LO variety toc/got reloc.  */
 
-static bfd_boolean
+static bool
 ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
 {
   return ((insn & (0x3fu << 26)) == 12u << 26 /* addic */
@@ -8517,7 +8776,7 @@ ok_lo_toc_insn (unsigned int insn, enum elf_ppc64_reloc_type r_type)
    the pld can be replaced with pla: *PINSN1 is that pla insn,
    while *PINSN2 is the second instruction.  */
 
-static bfd_boolean
+static bool
 xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
 {
   uint64_t insn1 = *pinsn1;
@@ -8528,29 +8787,29 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
     {
       /* Check that regs match.  */
       if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
-       return FALSE;
+       return false;
 
       /* P8LS or PMLS form, non-pcrel.  */
       if ((insn2 & (-1ULL << 50) & ~(1ULL << 56)) != (1ULL << 58))
-       return FALSE;
+       return false;
 
       *pinsn1 = (insn2 & ~(31 << 16) & ~0x3ffff0000ffffULL) | (1ULL << 52);
       *pinsn2 = PNOP;
       off = ((insn2 >> 16) & 0x3ffff0000ULL) | (insn2 & 0xffff);
       *poff = (off ^ 0x200000000ULL) - 0x200000000ULL;
-      return TRUE;
+      return true;
     }
 
   insn2 >>= 32;
 
   /* Check that regs match.  */
   if (((insn2 >> 16) & 31) != ((insn1 >> 21) & 31))
-    return FALSE;
+    return false;
 
   switch ((insn2 >> 26) & 63)
     {
     default:
-      return FALSE;
+      return false;
 
     case 32: /* lwz */
     case 34: /* lbz */
@@ -8572,7 +8831,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
 
     case 58: /* lwa, ld */
       if ((insn2 & 1) != 0)
-       return FALSE;
+       return false;
       insn1 = ((1ULL << 58) | (1ULL << 52)
               | (insn2 & 2 ? 41ULL << 26 : 57ULL << 26)
               | (insn2 & (31ULL << 21)));
@@ -8581,7 +8840,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
 
     case 57: /* lxsd, lxssp */
       if ((insn2 & 3) < 2)
-       return FALSE;
+       return false;
       insn1 = ((1ULL << 58) | (1ULL << 52)
               | ((40ULL | (insn2 & 3)) << 26)
               | (insn2 & (31ULL << 21)));
@@ -8590,7 +8849,7 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
 
     case 61: /* stxsd, stxssp, lxv, stxv  */
       if ((insn2 & 3) == 0)
-       return FALSE;
+       return false;
       else if ((insn2 & 3) >= 2)
        {
          insn1 = ((1ULL << 58) | (1ULL << 52)
@@ -8613,9 +8872,18 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
       off = insn2 & 0xffff;
       break;
 
+    case 6: /* lxvp, stxvp */
+      if ((insn2 & 0xe) != 0)
+       return false;
+      insn1 = ((1ULL << 58) | (1ULL << 52)
+              | ((insn2 & 1) == 0 ? 58ULL << 26 : 62ULL << 26)
+              | (insn2 & (31ULL << 21)));
+      off = insn2 & 0xfff0;
+      break;
+
     case 62: /* std, stq */
       if ((insn2 & 1) != 0)
-       return FALSE;
+       return false;
       insn1 = ((1ULL << 58) | (1ULL << 52)
               | ((insn2 & 2) == 0 ? 61ULL << 26 : 60ULL << 26)
               | (insn2 & (31ULL << 21)));
@@ -8626,13 +8894,13 @@ xlate_pcrel_opt (uint64_t *pinsn1, uint64_t *pinsn2, bfd_signed_vma *poff)
   *pinsn1 = insn1;
   *pinsn2 = (uint64_t) NOP << 32;
   *poff = (off ^ 0x8000) - 0x8000;
-  return TRUE;
+  return true;
 }
 
 /* Examine all relocs referencing .toc sections in order to remove
    unused .toc entries.  */
 
-bfd_boolean
+bool
 ppc64_elf_edit_toc (struct bfd_link_info *info)
 {
   bfd *ibfd;
@@ -8640,7 +8908,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   htab->do_toc_opt = 1;
-  toc_inf.global_toc_syms = TRUE;
+  toc_inf.global_toc_syms = true;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       asection *toc, *sec;
@@ -8677,7 +8945,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
              || (sec->flags & SEC_DEBUGGING) != 0)
            continue;
 
-         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, FALSE);
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, false);
          if (relstart == NULL)
            goto error_ret;
 
@@ -8785,7 +9053,9 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  || discarded_section (sym_sec))
                continue;
 
-             if (!SYMBOL_REFERENCES_LOCAL (info, h))
+             if (!SYMBOL_REFERENCES_LOCAL (info, h)
+                 || (bfd_link_pic (info)
+                     && sym_sec == bfd_abs_section_ptr))
                continue;
 
              if (h != NULL)
@@ -8834,19 +9104,15 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
       if (used == NULL)
        {
        error_ret:
-         if (local_syms != NULL
-             && symtab_hdr->contents != (unsigned char *) local_syms)
+         if (symtab_hdr->contents != (unsigned char *) local_syms)
            free (local_syms);
          if (sec != NULL
-             && relstart != NULL
              && elf_section_data (sec)->relocs != relstart)
            free (relstart);
-         if (toc_relocs != NULL
-             && elf_section_data (toc)->relocs != toc_relocs)
+         if (elf_section_data (toc)->relocs != toc_relocs)
            free (toc_relocs);
-         if (skip != NULL)
-           free (skip);
-         return FALSE;
+         free (skip);
+         return false;
        }
 
       /* Now check all kept sections that might reference the toc.
@@ -9007,7 +9273,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
          bfd_byte *contents, *src;
          unsigned long off;
          Elf_Internal_Sym *sym;
-         bfd_boolean local_toc_syms = FALSE;
+         bool local_toc_syms = false;
 
          /* Shuffle the toc contents, and at the same time convert the
             skip array from booleans into offsets.  */
@@ -9083,7 +9349,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                    {
                      val = sym->st_value;
                      if (val != 0)
-                       local_toc_syms = TRUE;
+                       local_toc_syms = true;
                    }
 
                  val += rel->r_addend;
@@ -9173,7 +9439,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
            {
              toc_inf.toc = toc;
              toc_inf.skip = skip;
-             toc_inf.global_toc_syms = FALSE;
+             toc_inf.global_toc_syms = false;
              elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
                                      &toc_inf);
            }
@@ -9201,7 +9467,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                    wrel->r_addend = rel->r_addend;
                    ++wrel;
                  }
-               else if (!dec_dynrel_count (rel->r_info, toc, info,
+               else if (!dec_dynrel_count (rel, toc, info,
                                            &local_syms, NULL, NULL))
                  goto error_ret;
 
@@ -9212,8 +9478,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
              rel_hdr->sh_size = toc->reloc_count * sz;
            }
        }
-      else if (toc_relocs != NULL
-              && elf_section_data (toc)->relocs != toc_relocs)
+      else if (elf_section_data (toc)->relocs != toc_relocs)
        free (toc_relocs);
 
       if (local_syms != NULL
@@ -9264,14 +9529,12 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
          if (relstart == NULL)
            {
            got_error_ret:
-             if (local_syms != NULL
-                 && symtab_hdr->contents != (unsigned char *) local_syms)
+             if (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;
+             return false;
            }
 
          for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
@@ -9371,7 +9634,12 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                  || discarded_section (sym_sec))
                continue;
 
-             if (!SYMBOL_REFERENCES_LOCAL (info, h))
+             if ((h ? h->type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC)
+               continue;
+
+             if (!SYMBOL_REFERENCES_LOCAL (info, h)
+                 || (bfd_link_pic (info)
+                     && sym_sec == bfd_abs_section_ptr))
                continue;
 
              if (h != NULL)
@@ -9465,13 +9733,13 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Return true iff input section I references the TOC using
    instructions limited to +/-32k offsets.  */
 
-bfd_boolean
+bool
 ppc64_elf_has_small_toc_reloc (asection *i)
 {
   return (is_ppc64_elf (i->owner)
@@ -9502,9 +9770,11 @@ allocate_got (struct elf_link_hash_entry *h,
       htab->got_reli_size += rentsize;
     }
   else if (((bfd_link_pic (info)
-            && !(gent->tls_type != 0
-                 && bfd_link_executable (info)
-                 && SYMBOL_REFERENCES_LOCAL (info, h)))
+            && (gent->tls_type == 0
+                ? !info->enable_dt_relr
+                : !(bfd_link_executable (info)
+                    && SYMBOL_REFERENCES_LOCAL (info, h)))
+            && !bfd_is_abs_symbol (&h->root))
            || (htab->elf.dynamic_sections_created
                && h->dynindx != -1
                && !SYMBOL_REFERENCES_LOCAL (info, h)))
@@ -9530,14 +9800,14 @@ merge_got_entries (struct got_entry **pent)
            && ent2->tls_type == ent->tls_type
            && elf_gp (ent2->owner) == elf_gp (ent->owner))
          {
-           ent2->is_indirect = TRUE;
+           ent2->is_indirect = true;
            ent2->got.ent = ent;
          }
 }
 
 /* If H is undefined, make it dynamic if that makes sense.  */
 
-static bfd_boolean
+static bool
 ensure_undef_dynamic (struct bfd_link_info *info,
                      struct elf_link_hash_entry *h)
 {
@@ -9551,13 +9821,25 @@ ensure_undef_dynamic (struct bfd_link_info *info,
       && !h->forced_local
       && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
     return bfd_elf_link_record_dynamic_symbol (info, h);
-  return TRUE;
+  return true;
+}
+
+/* Choose whether to use htab->iplt or htab->pltlocal rather than the
+   usual htab->elf.splt section for a PLT entry.  */
+
+static inline
+bool use_local_plt (struct bfd_link_info *info,
+                          struct elf_link_hash_entry *h)
+{
+  return (h == NULL
+         || h->dynindx == -1
+         || !elf_hash_table (info)->dynamic_sections_created);
 }
 
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
-static bfd_boolean
+static bool
 allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
@@ -9567,12 +9849,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct got_entry **pgent, *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   info = (struct bfd_link_info *) inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   eh = ppc_elf_hash_entry (h);
   /* Run through the TLS GD got entries first if we're changing them
@@ -9628,7 +9910,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        /* Ensure we catch all the cases where this symbol should
           be made dynamic.  */
        if (!ensure_undef_dynamic (info, h))
-         return FALSE;
+         return false;
 
        if (!is_ppc64_elf (gent->owner))
          abort ();
@@ -9640,21 +9922,21 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      IFUNCs which are handled even in static executables.  */
   if (!htab->elf.dynamic_sections_created
       && h->type != STT_GNU_IFUNC)
-    eh->dyn_relocs = NULL;
+    h->dyn_relocs = NULL;
 
   /* Discard relocs on undefined symbols that must be local.  */
   else if (h->root.type == bfd_link_hash_undefined
           && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-    eh->dyn_relocs = NULL;
+    h->dyn_relocs = NULL;
 
   /* Also discard relocs on undefined weak syms with non-default
      visibility, or when dynamic_undefined_weak says so.  */
   else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
-    eh->dyn_relocs = NULL;
+    h->dyn_relocs = NULL;
 
-  if (eh->dyn_relocs != NULL)
+  if (h->dyn_relocs != NULL)
     {
-      struct elf_dyn_relocs *p, **pp;
+      struct ppc_dyn_relocs *p, **pp;
 
       /* In the shared -Bsymbolic case, discard space allocated for
         dynamic pc-relative relocs against symbols which turn out to
@@ -9672,7 +9954,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
             avoid writing weird assembly.  */
          if (SYMBOL_CALLS_LOCAL (info, h))
            {
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+             for (pp = (struct ppc_dyn_relocs **) &h->dyn_relocs;
+                  (p = *pp) != NULL;
+                  )
                {
                  p->count -= p->pc_count;
                  p->pc_count = 0;
@@ -9683,12 +9967,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                }
            }
 
-         if (eh->dyn_relocs != NULL)
+         if (h->dyn_relocs != NULL)
            {
              /* Ensure we catch all the cases where this symbol
                 should be made dynamic.  */
              if (!ensure_undef_dynamic (info, h))
-               return FALSE;
+               return false;
            }
        }
 
@@ -9696,30 +9980,42 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         relocs against symbols which are not dynamic.  */
       else if (h->type != STT_GNU_IFUNC)
        {
-         if (h->dynamic_adjusted
+         if ((h->dynamic_adjusted
+              || (h->ref_regular
+                  && h->root.type == bfd_link_hash_undefweak
+                  && (info->dynamic_undefined_weak > 0
+                      || !_bfd_elf_readonly_dynrelocs (h))))
              && !h->def_regular
              && !ELF_COMMON_DEF_P (h))
            {
              /* Ensure we catch all the cases where this symbol
                 should be made dynamic.  */
              if (!ensure_undef_dynamic (info, h))
-               return FALSE;
+               return false;
 
              /* But if that didn't work out, discard dynamic relocs.  */
              if (h->dynindx == -1)
-               eh->dyn_relocs = NULL;
+               h->dyn_relocs = NULL;
            }
          else
-           eh->dyn_relocs = NULL;
+           h->dyn_relocs = NULL;
        }
 
       /* Finally, allocate space.  */
-      for (p = eh->dyn_relocs; p != NULL; p = p->next)
+      for (p = (struct ppc_dyn_relocs *) h->dyn_relocs; p != NULL; p = p->next)
        {
+         unsigned int count;
          asection *sreloc = elf_section_data (p->sec)->sreloc;
          if (eh->elf.type == STT_GNU_IFUNC)
            sreloc = htab->elf.irelplt;
-         sreloc->size += p->count * sizeof (Elf64_External_Rela);
+         count = p->count;
+         if (info->enable_dt_relr
+             && ((!NO_OPD_RELOCS
+                  && ppc64_elf_section_data (p->sec)->sec_type == sec_opd)
+                 || (eh->elf.type != STT_GNU_IFUNC
+                     && SYMBOL_REFERENCES_LOCAL (info, h))))
+           count -= p->rel_count;
+         sreloc->size += count * sizeof (Elf64_External_Rela);
        }
     }
 
@@ -9739,12 +10035,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
     {
       struct plt_entry *pent;
-      bfd_boolean doneone = FALSE;
+      bool doneone = false;
       for (pent = h->plt.plist; pent != NULL; pent = pent->next)
        if (pent->plt.refcount > 0)
          {
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
+           if (!ensure_undef_dynamic (info, h))
+             return false;
+
+           if (use_local_plt (info, h))
              {
                if (h->type == STT_GNU_IFUNC)
                  {
@@ -9758,7 +10056,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                    s = htab->pltlocal;
                    pent->plt.offset = s->size;
                    s->size += LOCAL_PLT_ENTRY_SIZE (htab);
-                   s = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                   s = NULL;
+                   if (bfd_link_pic (info)
+                       && !(info->enable_dt_relr && !htab->opd_abi))
+                     s = htab->relpltlocal;
                  }
              }
            else
@@ -9793,7 +10094,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              }
            if (s != NULL)
              s->size += sizeof (Elf64_External_Rela);
-           doneone = TRUE;
+           doneone = true;
          }
        else
          pent->plt.offset = (bfd_vma) -1;
@@ -9809,7 +10110,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       h->needs_plt = 0;
     }
 
-  return TRUE;
+  return true;
 }
 
 #define PPC_LO(v) ((v) & 0xffff)
@@ -9823,7 +10124,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
    to set up space for global entry stubs.  These are put in glink,
    after the branch table.  */
 
-static bfd_boolean
+static bool
 size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
@@ -9832,18 +10133,18 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
   asection *s, *plt;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   if (!h->pointer_equality_needed)
-    return TRUE;
+    return true;
 
   if (h->def_regular)
-    return TRUE;
+    return true;
 
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   s = htab->global_entry;
   plt = htab->elf.splt;
@@ -9890,52 +10191,25 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
        s->size = stub_off + stub_size;
        break;
       }
-  return TRUE;
-}
-
-/* Set DF_TEXTREL if we find any dynamic relocs that apply to
-   read-only sections.  */
-
-static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *h, void *inf)
-{
-  asection *sec;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  sec = readonly_dynrelocs (h);
-  if (sec != NULL)
-    {
-      struct bfd_link_info *info = (struct bfd_link_info *) inf;
-
-      info->flags |= DF_TEXTREL;
-      info->callbacks->minfo (_("%pB: dynamic relocation against `%pT'"
-                               " in read-only section `%pA'\n"),
-                             sec->owner, h->root.root.string, sec);
-
-      /* Not an error, just cut short the traversal.  */
-      return FALSE;
-    }
-  return TRUE;
+  return true;
 }
 
 /* Set the sizes of the dynamic sections.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                                 struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
-  bfd_boolean relocs;
+  bool relocs;
   bfd *ibfd;
   struct got_entry *first_tlsld;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
@@ -9965,13 +10239,15 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       unsigned char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Sym *isym;
 
       if (!is_ppc64_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct ppc_dyn_relocs *p;
+         struct ppc_local_dyn_relocs *p;
 
          for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
@@ -9985,10 +10261,20 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                }
              else if (p->count != 0)
                {
-                 asection *srel = elf_section_data (p->sec)->sreloc;
+                 unsigned int count;
+                 asection *srel;
+
+                 count = p->count;
+                 if (info->enable_dt_relr
+                     && ((!NO_OPD_RELOCS
+                          && (ppc64_elf_section_data (p->sec)->sec_type
+                              == sec_opd))
+                         || !p->ifunc))
+                   count -= p->rel_count;
+                 srel = elf_section_data (p->sec)->sreloc;
                  if (p->ifunc)
                    srel = htab->elf.irelplt;
-                 srel->size += p->count * sizeof (Elf64_External_Rela);
+                 srel->size += count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                }
@@ -10005,8 +10291,18 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       local_plt = (struct plt_entry **) end_lgot_ents;
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (unsigned char *) end_local_plt;
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (local_syms == NULL && locsymcount != 0)
+       {
+         local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+                                            0, NULL, NULL, NULL);
+         if (local_syms == NULL)
+           return false;
+       }
       s = ppc64_elf_tdata (ibfd)->got;
-      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+      for (isym = local_syms;
+          lgot_ents < end_lgot_ents;
+          ++lgot_ents, ++lgot_masks, isym++)
        {
          struct got_entry **pent, *ent;
 
@@ -10037,8 +10333,10 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        htab->got_reli_size += rel_size;
                      }
                    else if (bfd_link_pic (info)
-                            && !(ent->tls_type != 0
-                                 && bfd_link_executable (info)))
+                            && (ent->tls_type == 0
+                                ? !info->enable_dt_relr
+                                : !bfd_link_executable (info))
+                            && isym->st_shndx != SHN_ABS)
                      {
                        asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                        srel->size += rel_size;
@@ -10049,6 +10347,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            else
              *pent = ent->next;
        }
+      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;
+       }
 
       /* Allocate space for plt calls to local syms.  */
       lgot_masks = (unsigned char *) end_local_plt;
@@ -10074,7 +10380,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                    s = htab->pltlocal;
                    ent->plt.offset = s->size;
                    s->size += LOCAL_PLT_ENTRY_SIZE (htab);
-                   if (bfd_link_pic (info))
+                   if (bfd_link_pic (info)
+                       && !(info->enable_dt_relr && !htab->opd_abi))
                      htab->relpltlocal->size += sizeof (Elf64_External_Rela);
                  }
              }
@@ -10103,7 +10410,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
        {
          if (!htab->do_multi_toc && first_tlsld != NULL)
            {
-             ent->is_indirect = TRUE;
+             ent->is_indirect = true;
              ent->got.ent = first_tlsld;
            }
          else
@@ -10127,13 +10434,13 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
-  relocs = FALSE;
+  relocs = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
-      if (s == htab->brlt || s == htab->relbrlt)
+      if (s == htab->brlt || s == htab->relbrlt || s == htab->elf.srelrdyn)
        /* These haven't been allocated yet;  don't strip.  */
        continue;
       else if (s == htab->elf.sgot
@@ -10154,12 +10461,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            /* Not sized yet.  */
            continue;
        }
-      else if (CONST_STRNEQ (s->name, ".rela"))
+      else if (startswith (s->name, ".rela"))
        {
          if (s->size != 0)
            {
              if (s != htab->elf.srelplt)
-               relocs = TRUE;
+               relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -10203,7 +10510,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
         the GOT and .dynrelro.  */
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
-       return FALSE;
+       return false;
     }
 
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
@@ -10220,7 +10527,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            {
              s->contents = bfd_zalloc (ibfd, s->size);
              if (s->contents == NULL)
-               return FALSE;
+               return false;
            }
        }
       s = ppc64_elf_tdata (ibfd)->relgot;
@@ -10232,8 +10539,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
            {
              s->contents = bfd_zalloc (ibfd, s->size);
              if (s->contents == NULL)
-               return FALSE;
-             relocs = TRUE;
+               return false;
+             relocs = true;
              s->reloc_count = 0;
            }
        }
@@ -10241,7 +10548,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
 
   if (htab->elf.dynamic_sections_created)
     {
-      bfd_boolean tls_opt;
+      bool tls_opt;
 
       /* Add some entries to the .dynamic section.  We fill in the
         values later, in ppc64_elf_finish_dynamic_sections, but we
@@ -10254,7 +10561,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
-           return FALSE;
+           return false;
        }
 
       if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
@@ -10264,14 +10571,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0)
              || !add_dynamic_entry (DT_PPC64_GLINK, 0))
-           return FALSE;
+           return false;
        }
 
       if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1)
        {
          if (!add_dynamic_entry (DT_PPC64_OPD, 0)
              || !add_dynamic_entry (DT_PPC64_OPDSZ, 0))
-           return FALSE;
+           return false;
        }
 
       tls_opt = (htab->params->tls_get_addr_opt
@@ -10282,7 +10589,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       if (tls_opt || !htab->opd_abi)
        {
          if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0))
-           return FALSE;
+           return false;
        }
 
       if (relocs)
@@ -10290,41 +10597,42 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
          if (!add_dynamic_entry (DT_RELA, 0)
              || !add_dynamic_entry (DT_RELASZ, 0)
              || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
-           return FALSE;
+           return false;
 
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
          if ((info->flags & DF_TEXTREL) == 0)
-           elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info);
+           elf_link_hash_traverse (&htab->elf,
+                                   _bfd_elf_maybe_set_textrel, info);
 
          if ((info->flags & DF_TEXTREL) != 0)
            {
              if (!add_dynamic_entry (DT_TEXTREL, 0))
-               return FALSE;
+               return false;
            }
        }
     }
 #undef add_dynamic_entry
 
-  return TRUE;
+  return true;
 }
 
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_hash_symbol (struct elf_link_hash_entry *h)
 {
   if (h->plt.plist != NULL
       && !h->def_regular
       && !h->pointer_equality_needed)
-    return FALSE;
+    return false;
 
   return _bfd_elf_hash_symbol (h);
 }
 
 /* Determine the type of stub needed, if any, for a call.  */
 
-static inline enum ppc_stub_type
+static inline enum ppc_stub_main_type
 ppc_type_of_stub (asection *input_sec,
                  const Elf_Internal_Rela *rel,
                  struct ppc_link_hash_entry **hash,
@@ -10423,7 +10731,7 @@ ppc_type_of_stub (asection *input_sec,
    .   add/ldx %r12,%r11,%r12  */
 
 static bfd_byte *
-build_offset (bfd *abfd, bfd_byte *p, bfd_vma off, bfd_boolean load)
+build_offset (bfd *abfd, bfd_byte *p, bfd_vma off, bool load)
 {
   bfd_put_32 (abfd, MFLR_R12, p);
   p += 4;
@@ -10602,8 +10910,8 @@ emit_relocs_for_offset (struct bfd_link_info *info, Elf_Internal_Rela *r,
 }
 
 static bfd_byte *
-build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
-                     bfd_boolean load)
+build_power10_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
+                     bool load)
 {
   uint64_t insn;
   if (off - odd + (1ULL << 33) < 1ULL << 34)
@@ -10684,7 +10992,7 @@ build_powerxx_offset (bfd *abfd, bfd_byte *p, bfd_vma off, int odd,
 }
 
 static unsigned int
-size_powerxx_offset (bfd_vma off, int odd)
+size_power10_offset (bfd_vma off, int odd)
 {
   if (off - odd + (1ULL << 33) < 1ULL << 34)
     return odd + 8;
@@ -10695,7 +11003,7 @@ size_powerxx_offset (bfd_vma off, int odd)
 }
 
 static unsigned int
-num_relocs_for_powerxx_offset (bfd_vma off, int odd)
+num_relocs_for_power10_offset (bfd_vma off, int odd)
 {
   if (off - odd + (1ULL << 33) < 1ULL << 34)
     return 1;
@@ -10706,7 +11014,7 @@ num_relocs_for_powerxx_offset (bfd_vma off, int odd)
 }
 
 static Elf_Internal_Rela *
-emit_relocs_for_powerxx_offset (struct bfd_link_info *info,
+emit_relocs_for_power10_offset (struct bfd_link_info *info,
                                Elf_Internal_Rela *r, bfd_vma roff,
                                bfd_vma targ, bfd_vma off, int odd)
 {
@@ -10812,62 +11120,60 @@ eh_advance_size (unsigned int delta)
 static inline unsigned int
 plt_stub_size (struct ppc_link_hash_table *htab,
               struct ppc_stub_hash_entry *stub_entry,
-              bfd_vma off)
+              bfd_vma off,
+              unsigned int odd)
 {
   unsigned size;
 
-  if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+  if (stub_entry->type.sub == ppc_stub_notoc)
     {
-      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 = 8 + size_power10_offset (off, odd);
+      if (stub_entry->type.r2save)
        size += 4;
-      return size;
     }
-
-  size = 12;
-  if (ALWAYS_EMIT_R2SAVE
-      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-    size += 4;
-  if (PPC_HA (off) != 0)
-    size += 4;
-  if (htab->opd_abi)
+  else if (stub_entry->type.sub == ppc_stub_p9notoc)
     {
-      size += 4;
-      if (htab->params->plt_static_chain)
+      size = 8 + size_offset (off - 8);
+      if (stub_entry->type.r2save)
+       size += 4;
+    }
+  else
+    {
+      size = 12;
+      if (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
        size += 4;
-      if (htab->params->plt_thread_safe
-         && htab->elf.dynamic_sections_created
-         && stub_entry->h != NULL
-         && stub_entry->h->elf.dynindx != -1)
-       size += 8;
-      if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
+      if (PPC_HA (off) != 0)
        size += 4;
+      if (htab->opd_abi)
+       {
+         size += 4;
+         if (htab->params->plt_static_chain)
+           size += 4;
+         if (htab->params->plt_thread_safe
+             && htab->elf.dynamic_sections_created
+             && stub_entry->h != NULL
+             && stub_entry->h->elf.dynindx != -1)
+           size += 8;
+         if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain)
+             != PPC_HA (off))
+           size += 4;
+       }
     }
   if (stub_entry->h != NULL
       && is_tls_get_addr (&stub_entry->h->elf, htab)
       && htab->params->tls_get_addr_opt)
     {
-      if (htab->params->no_tls_get_addr_regsave)
+      if (!htab->params->no_tls_get_addr_regsave)
        {
-         size += 7 * 4;
-         if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
-           size += 6 * 4;
+         size += 30 * 4;
+         if (stub_entry->type.r2save)
+           size += 4;
        }
       else
        {
-         size += 30 * 4;
-         if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
-           size += 4;
+         size += 7 * 4;
+         if (stub_entry->type.r2save)
+           size += 6 * 4;
        }
     }
   return size;
@@ -10882,11 +11188,12 @@ plt_stub_size (struct ppc_link_hash_table *htab,
 static inline unsigned int
 plt_stub_pad (struct ppc_link_hash_table *htab,
              struct ppc_stub_hash_entry *stub_entry,
-             bfd_vma plt_off)
+             bfd_vma stub_off,
+             bfd_vma plt_off,
+             unsigned int odd)
 {
   int stub_align;
   unsigned stub_size;
-  bfd_vma stub_off = stub_entry->group->stub_sec->size;
 
   if (htab->params->plt_stub_align >= 0)
     {
@@ -10897,14 +11204,14 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
     }
 
   stub_align = 1 << -htab->params->plt_stub_align;
-  stub_size = plt_stub_size (htab, stub_entry, plt_off);
+  stub_size = plt_stub_size (htab, stub_entry, plt_off, odd);
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
     return stub_align - (stub_off & (stub_align - 1));
   return 0;
 }
 
-/* Build a .plt call stub.  */
+/* Build a toc using .plt call stub.  */
 
 static inline bfd_byte *
 build_plt_stub (struct ppc_link_hash_table *htab,
@@ -10912,19 +11219,20 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
   bfd *obfd = htab->params->stub_bfd;
-  bfd_boolean plt_load_toc = htab->opd_abi;
-  bfd_boolean plt_static_chain = htab->params->plt_static_chain;
-  bfd_boolean plt_thread_safe = (htab->params->plt_thread_safe
-                                && htab->elf.dynamic_sections_created
-                                && stub_entry->h != NULL
-                                && stub_entry->h->elf.dynindx != -1);
-  bfd_boolean use_fake_dep = plt_thread_safe;
+  bool plt_load_toc = htab->opd_abi;
+  bool plt_static_chain = htab->params->plt_static_chain;
+  bool plt_thread_safe = (htab->params->plt_thread_safe
+                         && htab->elf.dynamic_sections_created
+                         && stub_entry->h != NULL
+                         && stub_entry->h->elf.dynindx != -1);
+  bool use_fake_dep = plt_thread_safe;
   bfd_vma cmp_branch_off = 0;
 
   if (!ALWAYS_USE_FAKE_DEP
       && plt_load_toc
       && plt_thread_safe
-      && !(is_tls_get_addr (&stub_entry->h->elf, htab)
+      && !(stub_entry->h != NULL
+          && is_tls_get_addr (&stub_entry->h->elf, htab)
           && htab->params->tls_get_addr_opt))
     {
       bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
@@ -10939,8 +11247,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
            + htab->glink->output_offset
            + htab->glink->output_section->vma);
       from = (p - stub_entry->group->stub_sec->contents
-             + 4 * (ALWAYS_EMIT_R2SAVE
-                    || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+             + 4 * (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
              + 4 * (PPC_HA (offset) != 0)
              + 4 * (PPC_HA (offset + 8 + 8 * plt_static_chain)
                     != PPC_HA (offset))
@@ -10956,8 +11263,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
     {
       if (r != NULL)
        {
-         if (ALWAYS_EMIT_R2SAVE
-             || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+         if (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
            r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
          r[1].r_offset = r[0].r_offset + 4;
@@ -10985,8 +11291,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                }
            }
        }
-      if (ALWAYS_EMIT_R2SAVE
-         || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+      if (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
        bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p),      p += 4;
       if (plt_load_toc)
        {
@@ -11021,8 +11326,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
     {
       if (r != NULL)
        {
-         if (ALWAYS_EMIT_R2SAVE
-             || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+         if (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
            r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
          if (plt_load_toc)
@@ -11047,8 +11351,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
                }
            }
        }
-      if (ALWAYS_EMIT_R2SAVE
-         || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+      if (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save)
        bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p),      p += 4;
       bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p),      p += 4;
       if (plt_load_toc
@@ -11092,14 +11395,12 @@ build_plt_stub (struct ppc_link_hash_table *htab,
 #define MR_R3_R0       0x7c030378
 #define BCTRL          0x4e800421
 
-static inline bfd_byte *
-build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
+static bfd_byte *
+build_tls_get_addr_head (struct ppc_link_hash_table *htab,
                         struct ppc_stub_hash_entry *stub_entry,
-                        bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
+                        bfd_byte *p)
 {
   bfd *obfd = htab->params->stub_bfd;
-  bfd_byte *loc = p;
-  unsigned int i;
 
   bfd_put_32 (obfd, LD_R0_0R3 + 0, p),         p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
@@ -11108,50 +11409,51 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   bfd_put_32 (obfd, ADD_R3_R12_R13, p),                p += 4;
   bfd_put_32 (obfd, BEQLR, p),                 p += 4;
   bfd_put_32 (obfd, MR_R3_R0, p),              p += 4;
-  if (htab->params->no_tls_get_addr_regsave)
-    {
-      if (r != NULL)
-       r[0].r_offset += 7 * 4;
-      if (stub_entry->stub_type != ppc_stub_plt_call_r2save)
-       return build_plt_stub (htab, stub_entry, p, offset, r);
 
+  if (!htab->params->no_tls_get_addr_regsave)
+    p = tls_get_addr_prologue (obfd, p, htab);
+  else if (stub_entry->type.r2save)
+    {
       bfd_put_32 (obfd, MFLR_R0, p);
       p += 4;
       bfd_put_32 (obfd, STD_R0_0R1 + STK_LINKER (htab), p);
       p += 4;
+    }
+  return p;
+}
 
-      if (r != NULL)
-       r[0].r_offset += 2 * 4;
-      p = build_plt_stub (htab, stub_entry, p, offset, r);
-      bfd_put_32 (obfd, BCTRL, p - 4);
-
-      bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
-      p += 4;
-      bfd_put_32 (obfd, LD_R0_0R1 + STK_LINKER (htab), p);
-      p += 4;
-      bfd_put_32 (obfd, MTLR_R0, p);
-      p += 4;
-      bfd_put_32 (obfd, BLR, p);
-      p += 4;
-    }
-  else
-    {
-      p = tls_get_addr_prologue (obfd, p, htab);
-
-      if (r != NULL)
-       r[0].r_offset += 18 * 4;
+static bfd_byte *
+build_tls_get_addr_tail (struct ppc_link_hash_table *htab,
+                        struct ppc_stub_hash_entry *stub_entry,
+                        bfd_byte *p,
+                        bfd_byte *loc)
+{
+  bfd *obfd = htab->params->stub_bfd;
 
-      p = build_plt_stub (htab, stub_entry, p, offset, r);
+  if (!htab->params->no_tls_get_addr_regsave)
+    {
       bfd_put_32 (obfd, BCTRL, p - 4);
 
-      if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
+      if (stub_entry->type.r2save)
        {
          bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
          p += 4;
        }
-
       p = tls_get_addr_epilogue (obfd, p, htab);
     }
+  else if (stub_entry->type.r2save)
+    {
+      bfd_put_32 (obfd, BCTRL, p - 4);
+
+      bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p);
+      p += 4;
+      bfd_put_32 (obfd, LD_R0_0R1 + STK_LINKER (htab), p);
+      p += 4;
+      bfd_put_32 (obfd, MTLR_R0, p);
+      p += 4;
+      bfd_put_32 (obfd, BLR, p);
+      p += 4;
+    }
 
   if (htab->glink_eh_frame != NULL
       && htab->glink_eh_frame->size != 0)
@@ -11160,21 +11462,11 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
 
       base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17;
       eh = base + stub_entry->group->eh_size;
-      if (htab->params->no_tls_get_addr_regsave)
-       {
-         unsigned int lr_used, delta;
-         lr_used = stub_entry->stub_offset + (p - 20 - loc);
-         delta = lr_used - stub_entry->group->lr_restore;
-         stub_entry->group->lr_restore = lr_used + 16;
-         eh = eh_advance (htab->elf.dynobj, eh, delta);
-         *eh++ = DW_CFA_offset_extended_sf;
-         *eh++ = 65;
-         *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
-         *eh++ = DW_CFA_advance_loc + 4;
-       }
-      else
+
+      if (!htab->params->no_tls_get_addr_regsave)
        {
-         unsigned int cfa_updt, delta;
+         unsigned int cfa_updt, delta, i;
+
          /* After the bctrl, lr has been modified so we need to emit
             .eh_frame info saying the return address is on the stack.  In
             fact we must put the EH info at or before the call rather
@@ -11213,10 +11505,26 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
          for (i = 4; i < 12; i++)
            *eh++ = DW_CFA_restore + i;
          *eh++ = DW_CFA_advance_loc + 2;
+         *eh++ = DW_CFA_restore_extended;
+         *eh++ = 65;
+         stub_entry->group->eh_size = eh - base;
+       }
+      else if (stub_entry->type.r2save)
+       {
+         unsigned int lr_used, delta;
+
+         lr_used = stub_entry->stub_offset + (p - 20 - loc);
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->lr_restore = lr_used + 16;
+         eh = eh_advance (htab->elf.dynobj, eh, delta);
+         *eh++ = DW_CFA_offset_extended_sf;
+         *eh++ = 65;
+         *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
+         *eh++ = DW_CFA_advance_loc + 4;
+         *eh++ = DW_CFA_restore_extended;
+         *eh++ = 65;
+         stub_entry->group->eh_size = eh - base;
        }
-      *eh++ = DW_CFA_restore_extended;
-      *eh++ = 65;
-      stub_entry->group->eh_size = eh - base;
     }
   return p;
 }
@@ -11255,7 +11563,7 @@ get_relocs (asection *sec, int count)
    forms, to the equivalent relocs against the global symbol given by
    STUB_ENTRY->H.  */
 
-static bfd_boolean
+static bool
 use_global_in_relocs (struct ppc_link_hash_table *htab,
                      struct ppc_stub_hash_entry *stub_entry,
                      Elf_Internal_Rela *r, unsigned int num_rel)
@@ -11279,7 +11587,7 @@ use_global_in_relocs (struct ppc_link_hash_table *htab,
       hsize = (htab->stub_globals + 1) * sizeof (*hashes);
       hashes = bfd_zalloc (htab->params->stub_bfd, hsize);
       if (hashes == NULL)
-       return FALSE;
+       return false;
       elf_sym_hashes (htab->params->stub_bfd) = hashes;
       htab->stub_globals = 1;
     }
@@ -11305,7 +11613,7 @@ use_global_in_relocs (struct ppc_link_hash_table *htab,
        r->r_addend -= symval;
       --r;
     }
-  return TRUE;
+  return true;
 }
 
 static bfd_vma
@@ -11343,13 +11651,14 @@ get_r2off (struct bfd_link_info *info,
   return r2off;
 }
 
-static bfd_boolean
+static bool
 ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 {
   struct ppc_stub_hash_entry *stub_entry;
   struct ppc_branch_hash_entry *br_entry;
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
+  bfd *obfd;
   bfd_byte *loc;
   bfd_byte *p, *relp;
   bfd_vma targ, off;
@@ -11357,23 +11666,42 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   asection *plt;
   int num_rel;
   int odd;
+  bool is_tga;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
   info = in_arg;
 
+  /* Fail if the target section could not be assigned to an output
+     section.  The user should fix his linker script.  */
+  if (stub_entry->target_section != NULL
+      && stub_entry->target_section->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
+                             "Retry without --enable-non-contiguous-regions.\n"),
+                           stub_entry->target_section);
+
+  /* Same for the group.  */
+  if (stub_entry->group->stub_sec != NULL
+      && stub_entry->group->stub_sec->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an "
+                             "output section. Retry without "
+                             "--enable-non-contiguous-regions.\n"),
+                           stub_entry->group->stub_sec,
+                           stub_entry->target_section);
+
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   BFD_ASSERT (stub_entry->stub_offset >= stub_entry->group->stub_sec->size);
   loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset;
 
-  htab->stub_count[stub_entry->stub_type - 1] += 1;
-  switch (stub_entry->stub_type)
+  htab->stub_count[stub_entry->type.main - 1] += 1;
+  if (stub_entry->type.main == ppc_stub_long_branch
+      && stub_entry->type.sub == ppc_stub_toc)
     {
-    case ppc_stub_long_branch:
-    case ppc_stub_long_branch_r2off:
       /* Branches are relative.  This is where we are going to.  */
       targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
@@ -11387,32 +11715,31 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       off = targ - off;
 
       p = loc;
-      if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
+      obfd = htab->params->stub_bfd;
+      if (stub_entry->type.r2save)
        {
          bfd_vma r2off = get_r2off (info, stub_entry);
 
          if (r2off == (bfd_vma) -1)
            {
-             htab->stub_error = TRUE;
-             return FALSE;
+             htab->stub_error = true;
+             return false;
            }
-         bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+         bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
          p += 4;
          if (PPC_HA (r2off) != 0)
            {
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDIS_R2_R2 | PPC_HA (r2off), p);
+             bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p);
              p += 4;
            }
          if (PPC_LO (r2off) != 0)
            {
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDI_R2_R2 | PPC_LO (r2off), p);
+             bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p);
              p += 4;
            }
          off -= p - loc;
        }
-      bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), p);
+      bfd_put_32 (obfd, B_DOT | (off & 0x3fffffc), p);
       p += 4;
 
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
@@ -11420,41 +11747,41 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          _bfd_error_handler
            (_("long branch stub `%s' offset overflow"),
             stub_entry->root.string);
-         htab->stub_error = TRUE;
-         return FALSE;
+         htab->stub_error = true;
+         return false;
        }
 
       if (info->emitrelocations)
        {
          r = get_relocs (stub_entry->group->stub_sec, 1);
          if (r == NULL)
-           return FALSE;
+           return false;
          r->r_offset = p - 4 - stub_entry->group->stub_sec->contents;
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
          r->r_addend = targ;
          if (stub_entry->h != NULL
              && !use_global_in_relocs (htab, stub_entry, r, 1))
-           return FALSE;
+           return false;
        }
-      break;
-
-    case ppc_stub_plt_branch:
-    case ppc_stub_plt_branch_r2off:
+    }
+  else if (stub_entry->type.main == ppc_stub_plt_branch
+          && stub_entry->type.sub == ppc_stub_toc)
+    {
       br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                         stub_entry->root.string + 9,
-                                        FALSE, FALSE);
+                                        false, false);
       if (br_entry == NULL)
        {
          _bfd_error_handler (_("can't find branch stub `%s'"),
                              stub_entry->root.string);
-         htab->stub_error = TRUE;
-         return FALSE;
+         htab->stub_error = true;
+         return false;
        }
 
       targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
              + stub_entry->target_section->output_section->vma);
-      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+      if (!stub_entry->type.r2save)
        targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
 
       bfd_put_64 (htab->brlt->owner, targ,
@@ -11464,7 +11791,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        {
          br_entry->iter = 0;
 
-         if (htab->relbrlt != NULL)
+         if (htab->relbrlt != NULL && !info->enable_dt_relr)
            {
              /* Create a reloc for the branch lookup table entry.  */
              Elf_Internal_Rela rela;
@@ -11485,7 +11812,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            {
              r = get_relocs (htab->brlt, 1);
              if (r == NULL)
-               return FALSE;
+               return false;
              /* brlt, being SEC_LINKER_CREATED does not go through the
                 normal reloc processing.  Symbols and offsets are not
                 translated from input file to output file form, so
@@ -11512,19 +11839,19 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            (_("%P: linkage table error against `%pT'\n"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
-         htab->stub_error = TRUE;
-         return FALSE;
+         htab->stub_error = true;
+         return false;
        }
 
       if (info->emitrelocations)
        {
          r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0));
          if (r == NULL)
-           return FALSE;
+           return false;
          r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
-         if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
+         if (stub_entry->type.r2save)
            r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
          r[0].r_addend = targ;
@@ -11538,19 +11865,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
 
       p = loc;
-      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+      obfd = htab->params->stub_bfd;
+      if (!stub_entry->type.r2save)
        {
          if (PPC_HA (off) != 0)
            {
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDIS_R12_R2 | PPC_HA (off), p);
+             bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p);
              p += 4;
-             bfd_put_32 (htab->params->stub_bfd,
-                         LD_R12_0R12 | PPC_LO (off), p);
+             bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p);
            }
          else
-           bfd_put_32 (htab->params->stub_bfd,
-                       LD_R12_0R2 | PPC_LO (off), p);
+           bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p);
        }
       else
        {
@@ -11558,71 +11883,69 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
          if (r2off == (bfd_vma) -1)
            {
-             htab->stub_error = TRUE;
-             return FALSE;
+             htab->stub_error = true;
+             return false;
            }
 
-         bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+         bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
          p += 4;
          if (PPC_HA (off) != 0)
            {
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDIS_R12_R2 | PPC_HA (off), p);
+             bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (off), p);
              p += 4;
-             bfd_put_32 (htab->params->stub_bfd,
-                         LD_R12_0R12 | PPC_LO (off), p);
+             bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (off), p);
            }
          else
-           bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), p);
+           bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (off), p);
 
          if (PPC_HA (r2off) != 0)
            {
              p += 4;
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDIS_R2_R2 | PPC_HA (r2off), p);
+             bfd_put_32 (obfd, ADDIS_R2_R2 | PPC_HA (r2off), p);
            }
          if (PPC_LO (r2off) != 0)
            {
              p += 4;
-             bfd_put_32 (htab->params->stub_bfd,
-                         ADDI_R2_R2 | PPC_LO (r2off), p);
+             bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (r2off), p);
            }
        }
       p += 4;
-      bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+      bfd_put_32 (obfd, MTCTR_R12, p);
       p += 4;
-      bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+      bfd_put_32 (obfd, BCTR, p);
       p += 4;
-      break;
-
-    case ppc_stub_long_branch_notoc:
-    case ppc_stub_long_branch_both:
-    case ppc_stub_plt_branch_notoc:
-    case ppc_stub_plt_branch_both:
-    case ppc_stub_plt_call_notoc:
-    case ppc_stub_plt_call_both:
+    }
+  else if (stub_entry->type.sub >= ppc_stub_notoc)
+    {
+      bool is_plt = stub_entry->type.main == ppc_stub_plt_call;
       p = loc;
       off = (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_long_branch_both
-         || stub_entry->stub_type == ppc_stub_plt_branch_both
-         || stub_entry->stub_type == ppc_stub_plt_call_both)
+      obfd = htab->params->stub_bfd;
+      is_tga = (is_plt
+               && stub_entry->h != NULL
+               && is_tls_get_addr (&stub_entry->h->elf, htab)
+               && htab->params->tls_get_addr_opt);
+      if (is_tga)
+       {
+         p = build_tls_get_addr_head (htab, stub_entry, p);
+         off += p - loc;
+       }
+      if (stub_entry->type.r2save)
        {
          off += 4;
-         bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+         bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p);
          p += 4;
        }
-      if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+      if (is_plt)
        {
          targ = stub_entry->plt_ent->plt.offset & ~1;
          if (targ >= (bfd_vma) -2)
            abort ();
 
          plt = htab->elf.splt;
-         if (!htab->elf.dynamic_sections_created
-             || stub_entry->h == NULL
-             || stub_entry->h->elf.dynindx == -1)
+         if (use_local_plt (info, elf_hash_entry (stub_entry->h)))
            {
              if (stub_entry->symtype == STT_GNU_IFUNC)
                plt = htab->elf.iplt;
@@ -11640,24 +11963,42 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       relp = p;
       num_rel = 0;
-      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);
-       }
+      if (stub_entry->type.sub == ppc_stub_notoc)
+       p = build_power10_offset (obfd, p, off, odd, is_plt);
       else
        {
+         if (htab->glink_eh_frame != NULL
+             && htab->glink_eh_frame->size != 0)
+           {
+             bfd_byte *base, *eh;
+             unsigned int lr_used, delta;
+
+             base = (htab->glink_eh_frame->contents
+                     + stub_entry->group->eh_base + 17);
+             eh = base + stub_entry->group->eh_size;
+             lr_used = stub_entry->stub_offset + (p - loc) + 8;
+             delta = lr_used - stub_entry->group->lr_restore;
+             stub_entry->group->lr_restore = lr_used + 8;
+             eh = eh_advance (htab->elf.dynobj, eh, delta);
+             *eh++ = DW_CFA_register;
+             *eh++ = 65;
+             *eh++ = 12;
+             *eh++ = DW_CFA_advance_loc + 2;
+             *eh++ = DW_CFA_restore_extended;
+             *eh++ = 65;
+             stub_entry->group->eh_size = eh - base;
+           }
+
          /* 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);
+         p = build_offset (obfd, p, off, is_plt);
        }
 
-      if (stub_entry->stub_type <= ppc_stub_long_branch_both)
+      if (stub_entry->type.main == ppc_stub_long_branch)
        {
          bfd_vma from;
          num_rel = 1;
@@ -11665,22 +12006,24 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                  + stub_entry->group->stub_sec->output_offset
                  + stub_entry->group->stub_sec->output_section->vma
                  + (p - loc));
-         bfd_put_32 (htab->params->stub_bfd,
-                     B_DOT | ((targ - from) & 0x3fffffc), p);
+         bfd_put_32 (obfd, B_DOT | ((targ - from) & 0x3fffffc), p);
        }
       else
        {
-         bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+         bfd_put_32 (obfd, MTCTR_R12, p);
          p += 4;
-         bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+         bfd_put_32 (obfd, BCTR, p);
        }
       p += 4;
 
+      if (is_tga)
+       p = build_tls_get_addr_tail (htab, stub_entry, p, loc);
+
       if (info->emitrelocations)
        {
          bfd_vma roff = relp - stub_entry->group->stub_sec->contents;
-         if (htab->powerxx_stubs)
-           num_rel += num_relocs_for_powerxx_offset (off, odd);
+         if (stub_entry->type.sub == ppc_stub_notoc)
+           num_rel += num_relocs_for_power10_offset (off, odd);
          else
            {
              num_rel += num_relocs_for_offset (off);
@@ -11688,13 +12031,12 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            }
          r = get_relocs (stub_entry->group->stub_sec, num_rel);
          if (r == NULL)
-           return FALSE;
-         if (htab->powerxx_stubs)
-           r = emit_relocs_for_powerxx_offset (info, r, roff, targ, off, odd);
+           return false;
+         if (stub_entry->type.sub == ppc_stub_notoc)
+           r = emit_relocs_for_power10_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)
+         if (stub_entry->type.main == ppc_stub_long_branch)
            {
              ++r;
              roff = p - 4 - stub_entry->group->stub_sec->contents;
@@ -11703,40 +12045,12 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              r->r_addend = targ;
              if (stub_entry->h != NULL
                  && !use_global_in_relocs (htab, stub_entry, r, num_rel))
-               return FALSE;
+               return false;
            }
        }
-
-      if (!htab->powerxx_stubs
-         && htab->glink_eh_frame != NULL
-         && htab->glink_eh_frame->size != 0)
-       {
-         bfd_byte *base, *eh;
-         unsigned int lr_used, delta;
-
-         base = (htab->glink_eh_frame->contents
-                 + stub_entry->group->eh_base + 17);
-         eh = base + stub_entry->group->eh_size;
-         lr_used = stub_entry->stub_offset + 8;
-         if (stub_entry->stub_type == ppc_stub_long_branch_both
-             || stub_entry->stub_type == ppc_stub_plt_branch_both
-             || stub_entry->stub_type == ppc_stub_plt_call_both)
-           lr_used += 4;
-         delta = lr_used - stub_entry->group->lr_restore;
-         stub_entry->group->lr_restore = lr_used + 8;
-         eh = eh_advance (htab->elf.dynobj, eh, delta);
-         *eh++ = DW_CFA_register;
-         *eh++ = 65;
-         *eh++ = 12;
-         *eh++ = DW_CFA_advance_loc + 2;
-         *eh++ = DW_CFA_restore_extended;
-         *eh++ = 65;
-         stub_entry->group->eh_size = eh - base;
-       }
-      break;
-
-    case ppc_stub_plt_call:
-    case ppc_stub_plt_call_r2save:
+    }
+  else if (stub_entry->type.main == ppc_stub_plt_call)
+    {
       if (stub_entry->h != NULL
          && stub_entry->h->is_func_descriptor
          && stub_entry->h->oh != NULL)
@@ -11757,9 +12071,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        abort ();
 
       plt = htab->elf.splt;
-      if (!htab->elf.dynamic_sections_created
-         || stub_entry->h == NULL
-         || stub_entry->h->elf.dynindx == -1)
+      if (use_local_plt (info, elf_hash_entry (stub_entry->h)))
        {
          if (stub_entry->symtype == STT_GNU_IFUNC)
            plt = htab->elf.iplt;
@@ -11781,8 +12093,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
             ? stub_entry->h->elf.root.root.string
             : "<local sym>");
          bfd_set_error (bfd_error_bad_value);
-         htab->stub_error = TRUE;
-         return FALSE;
+         htab->stub_error = true;
+         return false;
        }
 
       r = NULL;
@@ -11795,26 +12107,33 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                                     && PPC_HA (off + 16) == PPC_HA (off))
                              : 1)));
          if (r == NULL)
-           return FALSE;
+           return false;
          r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
          r[0].r_addend = targ;
        }
-      if (stub_entry->h != NULL
-         && is_tls_get_addr (&stub_entry->h->elf, htab)
-         && htab->params->tls_get_addr_opt)
-       p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
-      else
-       p = build_plt_stub (htab, stub_entry, loc, off, r);
-      break;
-
-    case ppc_stub_save_res:
-      return TRUE;
-
-    default:
+      p = loc;
+      obfd = htab->params->stub_bfd;
+      is_tga = (stub_entry->h != NULL
+               && is_tls_get_addr (&stub_entry->h->elf, htab)
+               && htab->params->tls_get_addr_opt);
+      if (is_tga)
+       {
+         p = build_tls_get_addr_head (htab, stub_entry, p);
+         if (r != NULL)
+           r[0].r_offset += p - loc;
+       }
+      p = build_plt_stub (htab, stub_entry, p, off, r);
+      if (is_tga)
+       p = build_tls_get_addr_tail (htab, stub_entry, p, loc);
+    }
+  else if (stub_entry->type.main == ppc_stub_save_res)
+    return true;
+  else
+    {
       BFD_FAIL ();
-      return FALSE;
+      return false;
     }
 
   stub_entry->group->stub_sec->size = stub_entry->stub_offset + (p - loc);
@@ -11825,29 +12144,20 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       size_t len1, len2;
       char *name;
       const char *const stub_str[] = { "long_branch",
-                                      "long_branch",
-                                      "long_branch",
-                                      "long_branch",
-                                      "plt_branch",
-                                      "plt_branch",
-                                      "plt_branch",
                                       "plt_branch",
-                                      "plt_call",
-                                      "plt_call",
-                                      "plt_call",
                                       "plt_call" };
 
-      len1 = strlen (stub_str[stub_entry->stub_type - 1]);
+      len1 = strlen (stub_str[stub_entry->type.main - 1]);
       len2 = strlen (stub_entry->root.string);
       name = bfd_malloc (len1 + len2 + 2);
       if (name == NULL)
-       return FALSE;
+       return false;
       memcpy (name, stub_entry->root.string, 9);
-      memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1);
+      memcpy (name + 9, stub_str[stub_entry->type.main - 1], len1);
       memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1);
-      h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
+      h = elf_link_hash_lookup (&htab->elf, name, true, false, false);
       if (h == NULL)
-       return FALSE;
+       return false;
       if (h->root.type == bfd_link_hash_new)
        {
          h->root.type = bfd_link_hash_defined;
@@ -11862,14 +12172,14 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 /* As above, but don't actually build the stub.  Just bump offset so
    we know stub section sizes, and select plt_branch stubs where
    long_branch stubs won't do.  */
 
-static bfd_boolean
+static bool
 ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 {
   struct ppc_stub_hash_entry *stub_entry;
@@ -11878,6 +12188,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   asection *plt;
   bfd_vma targ, off, r2off;
   unsigned int size, extra, lr_used, delta, odd;
+  bfd_vma stub_offset;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
@@ -11885,10 +12196,32 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
+
+  /* Fail if the target section could not be assigned to an output
+     section.  The user should fix his linker script.  */
+  if (stub_entry->target_section != NULL
+      && stub_entry->target_section->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign %pA to an output section. "
+                             "Retry without --enable-non-contiguous-regions.\n"),
+                           stub_entry->target_section);
+
+  /* Same for the group.  */
+  if (stub_entry->group->stub_sec != NULL
+      && stub_entry->group->stub_sec->output_section == NULL
+      && info->non_contiguous_regions)
+    info->callbacks->einfo (_("%F%P: Could not assign group %pA target %pA to an "
+                             "output section. Retry without "
+                             "--enable-non-contiguous-regions.\n"),
+                           stub_entry->group->stub_sec,
+                           stub_entry->target_section);
 
   /* Make a note of the offset within the stubs for this entry.  */
-  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+  stub_offset = stub_entry->group->stub_sec->size;
+  if (htab->stub_iteration > STUB_SHRINK_ITER
+      && stub_entry->stub_offset > stub_offset)
+    stub_offset = stub_entry->stub_offset;
 
   if (stub_entry->h != NULL
       && stub_entry->h->save_res
@@ -11898,37 +12231,39 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       /* Don't make stubs to out-of-line register save/restore
         functions.  Instead, emit copies of the functions.  */
       stub_entry->group->needs_save_res = 1;
-      stub_entry->stub_type = ppc_stub_save_res;
-      return TRUE;
+      stub_entry->type.main = ppc_stub_save_res;
+      stub_entry->type.sub = ppc_stub_toc;
+      stub_entry->type.r2save = 0;
+      return true;
     }
 
-  switch (stub_entry->stub_type)
+  if (stub_entry->type.main == ppc_stub_plt_branch)
     {
-    case ppc_stub_plt_branch:
-    case ppc_stub_plt_branch_r2off:
       /* Reset the stub type from the plt branch variant in case we now
         can reach with a shorter stub.  */
-      stub_entry->stub_type += ppc_stub_long_branch - ppc_stub_plt_branch;
-      /* Fall through.  */
-    case ppc_stub_long_branch:
-    case ppc_stub_long_branch_r2off:
+      stub_entry->type.main += ppc_stub_long_branch - ppc_stub_plt_branch;
+    }
+
+  if (stub_entry->type.main == ppc_stub_long_branch
+      && stub_entry->type.sub == ppc_stub_toc)
+    {
       targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
              + stub_entry->target_section->output_section->vma);
       targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
-      off = (stub_entry->stub_offset
+      off = (stub_offset
             + stub_entry->group->stub_sec->output_offset
             + stub_entry->group->stub_sec->output_section->vma);
 
       size = 4;
       r2off = 0;
-      if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
+      if (stub_entry->type.r2save)
        {
          r2off = get_r2off (info, stub_entry);
          if (r2off == (bfd_vma) -1)
            {
-             htab->stub_error = TRUE;
-             return FALSE;
+             htab->stub_error = true;
+             return false;
            }
          size = 8;
          if (PPC_HA (r2off) != 0)
@@ -11941,7 +12276,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       /* If the branch offset is too big, use a ppc_stub_plt_branch.
         Do the same for -R objects without function descriptors.  */
-      if ((stub_entry->stub_type == ppc_stub_long_branch_r2off
+      if ((stub_entry->type.r2save
           && r2off == 0
           && htab->sec_info[stub_entry->target_section->id].toc_off == 0)
          || off + (1 << 25) >= (bfd_vma) (1 << 26))
@@ -11950,13 +12285,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
          br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                             stub_entry->root.string + 9,
-                                            TRUE, FALSE);
+                                            true, false);
          if (br_entry == NULL)
            {
              _bfd_error_handler (_("can't build branch stub `%s'"),
                                  stub_entry->root.string);
-             htab->stub_error = TRUE;
-             return FALSE;
+             htab->stub_error = true;
+             return false;
            }
 
          if (br_entry->iter != htab->stub_iteration)
@@ -11965,7 +12300,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              br_entry->offset = htab->brlt->size;
              htab->brlt->size += 8;
 
-             if (htab->relbrlt != NULL)
+             if (htab->relbrlt != NULL && !info->enable_dt_relr)
                htab->relbrlt->size += sizeof (Elf64_External_Rela);
              else if (info->emitrelocations)
                {
@@ -11988,8 +12323,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              stub_entry->group->stub_sec->flags |= SEC_RELOC;
            }
 
-         stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch;
-         if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+         stub_entry->type.main += ppc_stub_plt_branch - ppc_stub_long_branch;
+         if (!stub_entry->type.r2save)
            {
              size = 12;
              if (PPC_HA (off) != 0)
@@ -12012,19 +12347,14 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          stub_entry->group->stub_sec->reloc_count += 1;
          stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
-      break;
-
-    case ppc_stub_plt_branch_notoc:
-    case ppc_stub_plt_branch_both:
-      stub_entry->stub_type += ppc_stub_long_branch - ppc_stub_plt_branch;
-      /* Fall through.  */
-    case ppc_stub_long_branch_notoc:
-    case ppc_stub_long_branch_both:
-      off = (stub_entry->stub_offset
+    }
+  else if (stub_entry->type.main == ppc_stub_long_branch)
+    {
+      off = (stub_offset
             + stub_entry->group->stub_sec->output_offset
             + stub_entry->group->stub_sec->output_section->vma);
       size = 0;
-      if (stub_entry->stub_type == ppc_stub_long_branch_both)
+      if (stub_entry->type.r2save)
        size = 4;
       off += size;
       targ = (stub_entry->target_value
@@ -12036,16 +12366,16 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
        {
          unsigned int num_rel;
-         if (htab->powerxx_stubs)
-           num_rel = num_relocs_for_powerxx_offset (off, odd);
+         if (stub_entry->type.sub == ppc_stub_notoc)
+           num_rel = num_relocs_for_power10_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;
        }
 
-      if (htab->powerxx_stubs)
-       extra = size_powerxx_offset (off, odd);
+      if (stub_entry->type.sub == ppc_stub_notoc)
+       extra = size_power10_offset (off, odd);
       else
        extra = size_offset (off - 8);
       /* Include branch insn plus those in the offset sequence.  */
@@ -12055,12 +12385,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
         calculated.  */
       off -= extra;
 
-      if (!htab->powerxx_stubs)
+      if (stub_entry->type.sub != ppc_stub_notoc)
        {
          /* 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 = stub_offset + 8;
+         if (stub_entry->type.r2save)
            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,
@@ -12073,29 +12403,34 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       /* If the branch can't reach, use a plt_branch.  */
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
-         stub_entry->stub_type += (ppc_stub_plt_branch_notoc
-                                   - ppc_stub_long_branch_notoc);
+         stub_entry->type.main += ppc_stub_plt_branch - ppc_stub_long_branch;
          size += 4;
        }
       else if (info->emitrelocations)
        stub_entry->group->stub_sec->reloc_count +=1;
-      break;
-
-    case ppc_stub_plt_call_notoc:
-    case ppc_stub_plt_call_both:
-      off = (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_both)
-       off += 4;
+    }
+  else if (stub_entry->type.sub >= ppc_stub_notoc)
+    {
+      BFD_ASSERT (stub_entry->type.main == ppc_stub_plt_call);
+      lr_used = 0;
+      if (stub_entry->h != NULL
+         && is_tls_get_addr (&stub_entry->h->elf, htab)
+         && htab->params->tls_get_addr_opt)
+       {
+         lr_used += 7 * 4;
+         if (!htab->params->no_tls_get_addr_regsave)
+           lr_used += 11 * 4;
+         else if (stub_entry->type.r2save)
+           lr_used += 2 * 4;
+       }
+      if (stub_entry->type.r2save)
+       lr_used += 4;
       targ = stub_entry->plt_ent->plt.offset & ~1;
       if (targ >= (bfd_vma) -2)
        abort ();
 
       plt = htab->elf.splt;
-      if (!htab->elf.dynamic_sections_created
-         || stub_entry->h == NULL
-         || stub_entry->h->elf.dynindx == -1)
+      if (use_local_plt (info, elf_hash_entry (stub_entry->h)))
        {
          if (stub_entry->symtype == STT_GNU_IFUNC)
            plt = htab->elf.iplt;
@@ -12103,38 +12438,40 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            plt = htab->pltlocal;
        }
       targ += plt->output_offset + plt->output_section->vma;
+      off = (stub_offset
+            + stub_entry->group->stub_sec->output_offset
+            + stub_entry->group->stub_sec->output_section->vma
+            + lr_used);
       odd = off & 4;
       off = targ - off;
 
       if (htab->params->plt_stub_align != 0)
        {
-         unsigned pad = plt_stub_pad (htab, stub_entry, off);
+         unsigned pad = plt_stub_pad (htab, stub_entry, stub_offset, off, odd);
 
-         stub_entry->group->stub_sec->size += pad;
-         stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+         stub_offset += pad;
          off -= pad;
+         odd ^= pad & 4;
        }
 
       if (info->emitrelocations)
        {
          unsigned int num_rel;
-         if (htab->powerxx_stubs)
-           num_rel = num_relocs_for_powerxx_offset (off, odd);
+         if (stub_entry->type.sub == ppc_stub_notoc)
+           num_rel = num_relocs_for_power10_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);
+      size = plt_stub_size (htab, stub_entry, off, odd);
 
-      if (!htab->powerxx_stubs)
+      if (stub_entry->type.sub != ppc_stub_notoc)
        {
          /* 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;
+         lr_used += stub_offset + 8;
          /* 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.  */
@@ -12142,17 +12479,34 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          stub_entry->group->eh_size += eh_advance_size (delta) + 6;
          stub_entry->group->lr_restore = lr_used + 8;
        }
-      break;
-
-    case ppc_stub_plt_call:
-    case ppc_stub_plt_call_r2save:
+      if (stub_entry->h != NULL
+         && is_tls_get_addr (&stub_entry->h->elf, htab)
+         && htab->params->tls_get_addr_opt)
+       {
+         if (!htab->params->no_tls_get_addr_regsave)
+           {
+             unsigned int cfa_updt = stub_offset + 18 * 4;
+             delta = cfa_updt - stub_entry->group->lr_restore;
+             stub_entry->group->eh_size += eh_advance_size (delta);
+             stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
+             stub_entry->group->lr_restore = stub_offset + size - 4;
+           }
+         else if (stub_entry->type.r2save)
+           {
+             lr_used = stub_offset + size - 20;
+             delta = lr_used - stub_entry->group->lr_restore;
+             stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+             stub_entry->group->lr_restore = stub_offset + size - 4;
+           }
+       }
+    }
+  else if (stub_entry->type.main == ppc_stub_plt_call)
+    {
       targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
       if (targ >= (bfd_vma) -2)
        abort ();
       plt = htab->elf.splt;
-      if (!htab->elf.dynamic_sections_created
-         || stub_entry->h == NULL
-         || stub_entry->h->elf.dynindx == -1)
+      if (use_local_plt (info, elf_hash_entry (stub_entry->h)))
        {
          if (stub_entry->symtype == STT_GNU_IFUNC)
            plt = htab->elf.iplt;
@@ -12167,10 +12521,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (htab->params->plt_stub_align != 0)
        {
-         unsigned pad = plt_stub_pad (htab, stub_entry, off);
+         unsigned pad = plt_stub_pad (htab, stub_entry, stub_offset, off, 0);
 
-         stub_entry->group->stub_sec->size += pad;
-         stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+         stub_offset += pad;
        }
 
       if (info->emitrelocations)
@@ -12184,41 +12537,44 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
 
-      size = plt_stub_size (htab, stub_entry, off);
+      size = plt_stub_size (htab, stub_entry, off, 0);
 
       if (stub_entry->h != NULL
          && is_tls_get_addr (&stub_entry->h->elf, htab)
          && htab->params->tls_get_addr_opt
-         && stub_entry->stub_type == ppc_stub_plt_call_r2save)
+         && stub_entry->type.r2save)
        {
-         if (htab->params->no_tls_get_addr_regsave)
+         if (!htab->params->no_tls_get_addr_regsave)
+           {
+             /* Adjustments to r1 need to be described.  */
+             unsigned int cfa_updt = stub_offset + 18 * 4;
+             delta = cfa_updt - stub_entry->group->lr_restore;
+             stub_entry->group->eh_size += eh_advance_size (delta);
+             stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
+           }
+         else
            {
-             lr_used = stub_entry->stub_offset + size - 20;
+             lr_used = stub_offset + size - 20;
              /* The eh_frame info will consist of a DW_CFA_advance_loc
                 or variant, DW_CFA_offset_externed_sf, 65, -stackoff,
                 DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65.  */
              delta = lr_used - stub_entry->group->lr_restore;
              stub_entry->group->eh_size += eh_advance_size (delta) + 6;
            }
-         else
-           {
-             /* Adjustments to r1 need to be described.  */
-             unsigned int cfa_updt = stub_entry->stub_offset + 18 * 4;
-             delta = cfa_updt - stub_entry->group->lr_restore;
-             stub_entry->group->eh_size += eh_advance_size (delta);
-             stub_entry->group->eh_size += htab->opd_abi ? 36 : 35;
-           }
-         stub_entry->group->lr_restore = size - 4;
+         stub_entry->group->lr_restore = stub_offset + size - 4;
        }
-      break;
-
-    default:
+    }
+  else
+    {
       BFD_FAIL ();
-      return FALSE;
+      return false;
     }
 
-  stub_entry->group->stub_sec->size += size;
-  return TRUE;
+  if (stub_entry->stub_offset != stub_offset)
+    htab->stub_changed = true;
+  stub_entry->stub_offset = stub_offset;
+  stub_entry->group->stub_sec->size = stub_offset + size;
+  return true;
 }
 
 /* Set up various things so that we can make a list of input sections
@@ -12264,19 +12620,19 @@ ppc64_elf_start_multitoc_partition (struct bfd_link_info *info)
    and linker generated GOT section.  Group input bfds such that the toc
    within a group is less than 64k in size.  */
 
-bfd_boolean
+bool
 ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   bfd_vma addr, off, limit;
 
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   if (!htab->second_toc_pass)
     {
       /* Keep track of the first .toc or .got section for this input bfd.  */
-      bfd_boolean new_bfd = htab->toc_bfd != isec->owner;
+      bool new_bfd = htab->toc_bfd != isec->owner;
 
       if (new_bfd)
        {
@@ -12310,17 +12666,17 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
       if (new_bfd
          && elf_gp (isec->owner) != 0
          && elf_gp (isec->owner) != off)
-       return FALSE;
+       return false;
 
       elf_gp (isec->owner) = off;
-      return TRUE;
+      return true;
     }
 
   /* During the second pass toc_first_sec points to the start of
      a toc group, and toc_curr is used to track the old elf_gp.
      We use toc_bfd to ensure we only look at each bfd once.  */
   if (htab->toc_bfd == isec->owner)
-    return TRUE;
+    return true;
   htab->toc_bfd = isec->owner;
 
   if (htab->toc_first_sec == NULL
@@ -12334,55 +12690,55 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
   off = addr - elf_gp (info->output_bfd) + TOC_BASE_OFF;
   elf_gp (isec->owner) = off;
 
-  return TRUE;
+  return true;
 }
 
 /* Called via elf_link_hash_traverse to merge GOT entries for global
    symbol H.  */
 
-static bfd_boolean
+static bool
 merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
 {
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   merge_got_entries (&h->got.glist);
 
-  return TRUE;
+  return true;
 }
 
 /* Called via elf_link_hash_traverse to allocate GOT entries for global
    symbol H.  */
 
-static bfd_boolean
+static bool
 reallocate_got (struct elf_link_hash_entry *h, void *inf)
 {
   struct got_entry *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   for (gent = h->got.glist; gent != NULL; gent = gent->next)
     if (!gent->is_indirect)
       allocate_got (h, (struct bfd_link_info *) inf, gent);
-  return TRUE;
+  return true;
 }
 
 /* Called on the first multitoc pass after the last call to
    ppc64_elf_next_toc_section.  This function removes duplicate GOT
    entries.  */
 
-bfd_boolean
+bool
 ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   struct bfd *ibfd, *ibfd2;
-  bfd_boolean done_something;
+  bool done_something;
 
   htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd);
 
   if (!htab->do_multi_toc)
-    return FALSE;
+    return false;
 
   /* Merge global sym got entries within a toc group.  */
   elf_link_hash_traverse (&htab->elf, merge_global_got, info);
@@ -12409,7 +12765,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  && ent2->got.offset != (bfd_vma) -1
                  && elf_gp (ibfd2) == elf_gp (ibfd))
                {
-                 ent2->is_indirect = TRUE;
+                 ent2->is_indirect = true;
                  ent2->got.ent = ent;
                }
            }
@@ -12451,6 +12807,8 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *s;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Sym *isym;
 
       if (!is_ppc64_elf (ibfd))
        continue;
@@ -12465,8 +12823,18 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       local_plt = (struct plt_entry **) end_lgot_ents;
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (unsigned char *) end_local_plt;
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (local_syms == NULL && locsymcount != 0)
+       {
+         local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+                                            0, NULL, NULL, NULL);
+         if (local_syms == NULL)
+           return false;
+       }
       s = ppc64_elf_tdata (ibfd)->got;
-      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+      for (isym = local_syms;
+          lgot_ents < end_lgot_ents;
+          ++lgot_ents, ++lgot_masks, isym++)
        {
          struct got_entry *ent;
 
@@ -12488,8 +12856,10 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  htab->got_reli_size += rel_size;
                }
              else if (bfd_link_pic (info)
-                      && !(ent->tls_type != 0
-                           && bfd_link_executable (info)))
+                      && (ent->tls_type == 0
+                          ? !info->enable_dt_relr
+                          : !bfd_link_executable (info))
+                      && isym->st_shndx != SHN_ABS)
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += rel_size;
@@ -12547,7 +12917,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
      on input sections.  */
   htab->toc_bfd = NULL;
   htab->toc_first_sec = NULL;
-  htab->second_toc_pass = TRUE;
+  htab->second_toc_pass = true;
   return done_something;
 }
 
@@ -12622,6 +12992,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
          r_type = ELF64_R_TYPE (rel->r_info);
          if (r_type != R_PPC64_REL24
              && r_type != R_PPC64_REL24_NOTOC
+             && r_type != R_PPC64_REL24_P9NOTOC
              && r_type != R_PPC64_REL14
              && r_type != R_PPC64_REL14_BRTAKEN
              && r_type != R_PPC64_REL14_BRNTAKEN
@@ -12688,7 +13059,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
                }
 
              dest = opd_entry_value (sym_sec, sym_value,
-                                     &sym_sec, NULL, FALSE);
+                                     &sym_sec, NULL, false);
              if (dest == (bfd_vma) -1)
                continue;
            }
@@ -12750,9 +13121,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
            }
        }
 
-      if (local_syms != NULL
-         && (elf_symtab_hdr (isec->owner).contents
-             != (unsigned char *) local_syms))
+      if (elf_symtab_hdr (isec->owner).contents
+         != (unsigned char *) local_syms)
        free (local_syms);
       if (elf_section_data (isec)->relocs != relstart)
        free (relstart);
@@ -12788,13 +13158,13 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
    Build lists of input sections to determine groupings between which
    we may insert linker stubs.  */
 
-bfd_boolean
+bool
 ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   if ((isec->output_section->flags & SEC_CODE) != 0
       && isec->output_section->id < htab->sec_info_arr_size)
@@ -12818,7 +13188,7 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
            || isec->call_check_done))
        {
          if (toc_adjusting_stub_needed (info, isec) < 0)
-           return FALSE;
+           return false;
        }
       /* Make all sections use the TOC assigned for this object file.
         This will be wrong for pasted sections;  We fix that in
@@ -12828,13 +13198,13 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
     }
 
   htab->sec_info[isec->id].toc_off = htab->toc_curr;
-  return TRUE;
+  return true;
 }
 
 /* Check that all .init and .fini sections use the same toc, if they
    have toc relocs.  */
 
-static bfd_boolean
+static bool
 check_pasted_section (struct bfd_link_info *info, const char *name)
 {
   asection *o = bfd_get_section_by_name (info->output_bfd, name);
@@ -12851,7 +13221,7 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
            if (toc_off == 0)
              toc_off = htab->sec_info[i->id].toc_off;
            else if (toc_off != htab->sec_info[i->id].toc_off)
-             return FALSE;
+             return false;
          }
 
       if (toc_off == 0)
@@ -12867,14 +13237,16 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
        for (i = o->map_head.s; i != NULL; i = i->map_head.s)
          htab->sec_info[i->id].toc_off = toc_off;
     }
-  return TRUE;
+  return true;
 }
 
-bfd_boolean
+bool
 ppc64_elf_check_init_fini (struct bfd_link_info *info)
 {
-  return (check_pasted_section (info, ".init")
-         & check_pasted_section (info, ".fini"));
+  bool ret1 = check_pasted_section (info, ".init");
+  bool ret2 = check_pasted_section (info, ".fini");
+
+  return ret1 && ret2;
 }
 
 /* See whether we can group stub sections together.  Grouping stub
@@ -12884,20 +13256,20 @@ ppc64_elf_check_init_fini (struct bfd_link_info *info)
    _init and _fini functions into multiple parts.  Putting a stub in
    the middle of a function is not a good idea.  */
 
-static bfd_boolean
+static bool
 group_sections (struct bfd_link_info *info,
                bfd_size_type stub_group_size,
-               bfd_boolean stubs_always_before_branch)
+               bool stubs_always_before_branch)
 {
   struct ppc_link_hash_table *htab;
   asection *osec;
-  bfd_boolean suppress_size_errors;
+  bool suppress_size_errors;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
-  suppress_size_errors = FALSE;
+  suppress_size_errors = false;
   if (stub_group_size == 1)
     {
       /* Default values.  */
@@ -12905,7 +13277,7 @@ group_sections (struct bfd_link_info *info,
        stub_group_size = 0x1e00000;
       else
        stub_group_size = 0x1c00000;
-      suppress_size_errors = TRUE;
+      suppress_size_errors = true;
     }
 
   for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next)
@@ -12921,7 +13293,7 @@ group_sections (struct bfd_link_info *info,
          asection *curr;
          asection *prev;
          bfd_size_type total;
-         bfd_boolean big_sec;
+         bool big_sec;
          bfd_vma curr_toc;
          struct map_stub *group;
          bfd_size_type group_size;
@@ -12959,7 +13331,7 @@ group_sections (struct bfd_link_info *info,
             than 2097152 bytes, or nearly 75000 plt call stubs.  */
          group = bfd_alloc (curr->owner, sizeof (*group));
          if (group == NULL)
-           return FALSE;
+           return false;
          group->link_sec = curr;
          group->stub_sec = NULL;
          group->needs_save_res = 0;
@@ -13000,7 +13372,7 @@ group_sections (struct bfd_link_info *info,
          tail = prev;
        }
     }
-  return TRUE;
+  return true;
 }
 
 static const unsigned char glink_eh_frame_cie[] =
@@ -13038,21 +13410,198 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec)
     }
 }
 
+static int
+compare_relr_address (const void *arg1, const void *arg2)
+{
+  bfd_vma a = *(bfd_vma *) arg1;
+  bfd_vma b = *(bfd_vma *) arg2;
+  return a < b ? -1 : a > b ? 1 : 0;
+}
+
+static bool
+append_relr_off (struct ppc_link_hash_table *htab, bfd_vma off)
+{
+  if (htab->relr_count >= htab->relr_alloc)
+    {
+      if (htab->relr_alloc == 0)
+       htab->relr_alloc = 4096;
+      else
+       htab->relr_alloc *= 2;
+      htab->relr_addr
+       = bfd_realloc (htab->relr_addr,
+                      htab->relr_alloc * sizeof (htab->relr_addr[0]));
+      if (htab->relr_addr == NULL)
+       return false;
+    }
+  htab->relr_addr[htab->relr_count++] = off;
+  return true;
+}
+
+static bool
+got_and_plt_relr_for_local_syms (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      struct got_entry **lgot_ents, **lgot, **end_lgot_ents;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Sym *isym;
+      struct plt_entry *pent;
+      struct got_entry *gent;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+      if (local_syms == NULL && locsymcount != 0)
+       {
+         local_syms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, locsymcount,
+                                            0, NULL, NULL, NULL);
+         if (local_syms == NULL)
+           return false;
+       }
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      for (lgot = lgot_ents, isym = local_syms;
+          lgot < end_lgot_ents;
+          ++lgot, ++isym)
+       for (gent = *lgot; gent != NULL; gent = gent->next)
+         if (!gent->is_indirect
+             && gent->tls_type == 0
+             && gent->got.offset != (bfd_vma) -1
+             && isym->st_shndx != SHN_ABS)
+           {
+             asection *got = ppc64_elf_tdata (gent->owner)->got;
+             bfd_vma r_offset = (got->output_section->vma
+                                 + got->output_offset
+                                 + gent->got.offset);
+             if (!append_relr_off (htab, r_offset))
+               {
+                 htab->stub_error = true;
+                 return false;
+               }
+           }
+
+      if (!htab->opd_abi)
+       for (lplt = local_plt, isym = local_syms;
+            lplt < end_local_plt;
+            ++lplt, ++isym)
+         for (pent = *lplt; pent != NULL; pent = pent->next)
+           if (pent->plt.offset != (bfd_vma) -1
+               && ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC)
+             {
+               bfd_vma r_offset = (pent->plt.offset
+                                   + htab->pltlocal->output_offset
+                                   + htab->pltlocal->output_section->vma);
+               if (!append_relr_off (htab, r_offset))
+                 {
+                   if (symtab_hdr->contents != (unsigned char *) local_syms)
+                     free (local_syms);
+                   return false;
+                 }
+             }
+
+      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;
+}
+
+static bool
+got_and_plt_relr (struct elf_link_hash_entry *h, void *inf)
+{
+  struct bfd_link_info *info;
+  struct ppc_link_hash_table *htab;
+  struct plt_entry *pent;
+  struct got_entry *gent;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+
+  info = (struct bfd_link_info *) inf;
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return false;
+
+  if (h->type != STT_GNU_IFUNC
+      && h->def_regular
+      && (h->root.type == bfd_link_hash_defined
+         || h->root.type == bfd_link_hash_defweak))
+    {
+      if ((!htab->elf.dynamic_sections_created
+          || h->dynindx == -1
+          || SYMBOL_REFERENCES_LOCAL (info, h))
+         && !bfd_is_abs_symbol (&h->root))
+       for (gent = h->got.glist; gent != NULL; gent = gent->next)
+         if (!gent->is_indirect
+             && gent->tls_type == 0
+             && gent->got.offset != (bfd_vma) -1)
+           {
+             asection *got = ppc64_elf_tdata (gent->owner)->got;
+             bfd_vma r_offset = (got->output_section->vma
+                                 + got->output_offset
+                                 + gent->got.offset);
+             if (!append_relr_off (htab, r_offset))
+               {
+                 htab->stub_error = true;
+                 return false;
+               }
+           }
+
+      if (!htab->opd_abi
+         && use_local_plt (info, h))
+       for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+         if (pent->plt.offset != (bfd_vma) -1)
+           {
+             bfd_vma r_offset = (htab->pltlocal->output_section->vma
+                                 + htab->pltlocal->output_offset
+                                 + pent->plt.offset);
+             if (!append_relr_off (htab, r_offset))
+               {
+                 htab->stub_error = true;
+                 return false;
+               }
+           }
+    }
+  return true;
+}
+
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
    PC-relative calls to a target that is unreachable with a "bl"
    instruction.  */
 
-bfd_boolean
+bool
 ppc64_elf_size_stubs (struct bfd_link_info *info)
 {
   bfd_size_type stub_group_size;
-  bfd_boolean stubs_always_before_branch;
+  bool stubs_always_before_branch;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   if (htab == NULL)
-    return FALSE;
+    return false;
+
+  if (htab->params->power10_stubs == -1 && !htab->has_power10_relocs)
+    htab->params->power10_stubs = 0;
 
   if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
     htab->params->plt_thread_safe = 1;
@@ -13092,7 +13641,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
        {
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, thread_starter[i],
-                                   FALSE, FALSE, TRUE);
+                                   false, false, true);
          htab->params->plt_thread_safe = h != NULL && h->ref_regular;
          if (htab->params->plt_thread_safe)
            break;
@@ -13105,7 +13654,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
     stub_group_size = htab->params->group_size;
 
   if (!group_sections (info, stub_group_size, stubs_always_before_branch))
-    return FALSE;
+    return false;
 
   htab->tga_group = NULL;
   if (!htab->params->no_tls_get_addr_regsave
@@ -13124,12 +13673,12 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       code_sec = sym_sec;
       opd = get_opd_info (sym_sec);
       if (opd != NULL)
-       opd_entry_value (sym_sec, sym_value, &code_sec, NULL, FALSE);
+       opd_entry_value (sym_sec, sym_value, &code_sec, NULL, false);
       htab->tga_group = htab->sec_info[code_sec->id].u.group;
       stub_sec = (*htab->params->add_stub_section) (".tga_desc.stub",
                                                    htab->tga_group->link_sec);
       if (stub_sec == NULL)
-       return FALSE;
+       return false;
       htab->tga_group->stub_sec = stub_sec;
 
       htab->tga_desc_fd->elf.root.type = bfd_link_hash_defined;
@@ -13138,15 +13687,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       htab->tga_desc_fd->elf.type = STT_FUNC;
       htab->tga_desc_fd->elf.def_regular = 1;
       htab->tga_desc_fd->elf.non_elf = 0;
-      _bfd_elf_link_hash_hide_symbol (info, &htab->tga_desc_fd->elf, TRUE);
+      _bfd_elf_link_hash_hide_symbol (info, &htab->tga_desc_fd->elf, true);
     }
 
-#define STUB_SHRINK_ITER 20
   /* Loop until no stubs added.  After iteration 20 of this loop we may
-     exit on a stub section shrinking.  This is to break out of a
-     pathological case where adding stubs on one iteration decreases
-     section gaps (perhaps due to alignment), which then requires
-     fewer or smaller stubs on the next iteration.  */
+     exit on a stub section shrinking.  */
 
   while (1)
     {
@@ -13155,6 +13700,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       struct map_stub *group;
 
       htab->stub_iteration += 1;
+      htab->relr_count = 0;
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
@@ -13178,16 +13724,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
               section = section->next)
            {
              Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+             bool is_opd;
 
              /* If there aren't any relocs, then there's nothing more
                 to do.  */
              if ((section->flags & SEC_RELOC) == 0
                  || (section->flags & SEC_ALLOC) == 0
                  || (section->flags & SEC_LOAD) == 0
-                 || (section->flags & SEC_CODE) == 0
                  || section->reloc_count == 0)
                continue;
 
+             if (!info->enable_dt_relr
+                 && (section->flags & SEC_CODE) == 0)
+               continue;
+
              /* If this section is a link-once section that will be
                 discarded, then don't create any stubs.  */
              if (section->output_section == NULL
@@ -13201,6 +13751,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
              if (internal_relocs == NULL)
                goto error_ret_free_local;
 
+             is_opd = ppc64_elf_section_data (section)->sec_type == sec_opd;
+
              /* Now examine each relocation.  */
              irela = internal_relocs;
              irelaend = irela + section->reloc_count;
@@ -13208,13 +13760,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                {
                  enum elf_ppc64_reloc_type r_type;
                  unsigned int r_indx;
-                 enum ppc_stub_type stub_type;
+                 struct ppc_stub_type stub_type;
                  struct ppc_stub_hash_entry *stub_entry;
                  asection *sym_sec, *code_sec;
                  bfd_vma sym_value, code_value;
                  bfd_vma destination;
                  unsigned long local_off;
-                 bfd_boolean ok_dest;
+                 bool ok_dest;
                  struct ppc_link_hash_entry *hash;
                  struct ppc_link_hash_entry *fdh;
                  struct elf_link_hash_entry *h;
@@ -13234,21 +13786,81 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    }
 
                  /* Only look for stubs on branch instructions.  */
-                 if (r_type != R_PPC64_REL24
-                     && r_type != R_PPC64_REL24_NOTOC
-                     && r_type != R_PPC64_REL14
-                     && r_type != R_PPC64_REL14_BRTAKEN
-                     && r_type != R_PPC64_REL14_BRNTAKEN)
-                   continue;
+                 switch (r_type)
+                   {
+                   default:
+                     continue;
+
+                   case R_PPC64_REL24:
+                   case R_PPC64_REL24_NOTOC:
+                   case R_PPC64_REL24_P9NOTOC:
+                   case R_PPC64_REL14:
+                   case R_PPC64_REL14_BRTAKEN:
+                   case R_PPC64_REL14_BRNTAKEN:
+                     if ((section->flags & SEC_CODE) != 0)
+                       break;
+                     continue;
+
+                   case R_PPC64_ADDR64:
+                   case R_PPC64_TOC:
+                     if (info->enable_dt_relr
+                         && irela->r_offset % 2 == 0
+                         && section->alignment_power != 0)
+                       break;
+                     continue;
+                   }
 
                  /* Now determine the call target, its name, value,
                     section.  */
                  if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
                                  r_indx, input_bfd))
                    goto error_ret_free_internal;
-                 hash = ppc_elf_hash_entry (h);
 
-                 ok_dest = FALSE;
+                 if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
+                   {
+                     /* Only locally defined symbols can possibly use
+                        relative relocations.  */
+                     bfd_vma r_offset;
+                     if ((sym_sec == NULL
+                          || sym_sec->output_section == NULL)
+                         /* No symbol is OK too.  */
+                         && !(sym != NULL && sym->st_shndx == 0)
+                         /* Hack for __ehdr_start, which is undefined
+                            at this point.  */
+                         && !(h != NULL && h->root.linker_def))
+                       continue;
+                     if (NO_OPD_RELOCS && is_opd)
+                       continue;
+                     if (!is_opd
+                         && r_type == R_PPC64_ADDR64)
+                       {
+                         if (h != NULL
+                             ? h->type == STT_GNU_IFUNC
+                             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                           continue;
+                         if (h != NULL
+                             ? bfd_is_abs_symbol (&h->root)
+                             : sym->st_shndx == SHN_ABS)
+                           continue;
+                         if (h != NULL
+                             && !SYMBOL_REFERENCES_LOCAL (info, h))
+                           continue;
+                       }
+                     r_offset = _bfd_elf_section_offset (info->output_bfd,
+                                                         info,
+                                                         section,
+                                                         irela->r_offset);
+                     if (r_offset >= (bfd_vma) -2)
+                       continue;
+                     r_offset += (section->output_section->vma
+                                  + section->output_offset);
+                     if (!append_relr_off (htab, r_offset))
+                       goto error_ret_free_internal;
+                     continue;
+                   }
+
+                 hash = ppc_elf_hash_entry (h);
+                 ok_dest = false;
                  fdh = NULL;
                  sym_value = 0;
                  if (hash == NULL)
@@ -13256,14 +13868,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                      sym_value = sym->st_value;
                      if (sym_sec != NULL
                          && sym_sec->output_section != NULL)
-                       ok_dest = TRUE;
+                       ok_dest = true;
                    }
                  else if (hash->elf.root.type == bfd_link_hash_defined
                           || hash->elf.root.type == bfd_link_hash_defweak)
                    {
                      sym_value = hash->elf.root.u.def.value;
                      if (sym_sec->output_section != NULL)
-                       ok_dest = TRUE;
+                       ok_dest = true;
                    }
                  else if (hash->elf.root.type == bfd_link_hash_undefweak
                           || hash->elf.root.type == bfd_link_hash_undefined)
@@ -13281,7 +13893,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                              sym_sec = fdh->elf.root.u.def.section;
                              sym_value = fdh->elf.root.u.def.value;
                              if (sym_sec->output_section != NULL)
-                               ok_dest = TRUE;
+                               ok_dest = true;
                            }
                          else
                            fdh = NULL;
@@ -13322,7 +13934,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                          sym_value += adjust;
                        }
                      dest = opd_entry_value (sym_sec, sym_value,
-                                             &code_sec, &code_value, FALSE);
+                                             &code_sec, &code_value, false);
                      if (dest != (bfd_vma) -1)
                        {
                          destination = dest;
@@ -13339,23 +13951,35 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
                  /* Determine what (if any) linker stub is needed.  */
                  plt_ent = NULL;
-                 stub_type = ppc_type_of_stub (section, irela, &hash,
-                                               &plt_ent, destination,
-                                               local_off);
-
-                 if (r_type == R_PPC64_REL24_NOTOC)
+                 stub_type.main = ppc_type_of_stub (section, irela, &hash,
+                                                    &plt_ent, destination,
+                                                    local_off);
+                 stub_type.sub = ppc_stub_toc;
+                 stub_type.r2save = 0;
+
+                 if (r_type == R_PPC64_REL24_NOTOC
+                     || r_type == R_PPC64_REL24_P9NOTOC)
                    {
-                     if (stub_type == ppc_stub_plt_call)
-                       stub_type = ppc_stub_plt_call_notoc;
-                     else if (stub_type == ppc_stub_long_branch
+                     enum ppc_stub_sub_type notoc = ppc_stub_notoc;
+                     if (htab->params->power10_stubs == 0
+                         || (r_type == R_PPC64_REL24_P9NOTOC
+                             && htab->params->power10_stubs != 1))
+                       notoc = ppc_stub_p9notoc;
+                     if (stub_type.main == ppc_stub_plt_call)
+                       stub_type.sub = notoc;
+                     else if (stub_type.main == ppc_stub_long_branch
                               || (code_sec != NULL
                                   && code_sec->output_section != NULL
                                   && (((hash ? hash->elf.other : sym->st_other)
                                        & STO_PPC64_LOCAL_MASK)
                                       > 1 << STO_PPC64_LOCAL_BIT)))
-                       stub_type = ppc_stub_long_branch_notoc;
+                       {
+                         stub_type.main = ppc_stub_long_branch;
+                         stub_type.sub = notoc;
+                         stub_type.r2save = 0;
+                       }
                    }
-                 else if (stub_type != ppc_stub_plt_call)
+                 else if (stub_type.main != ppc_stub_plt_call)
                    {
                      /* Check whether we need a TOC adjusting stub.
                         Since the linker pastes together pieces from
@@ -13365,22 +13989,25 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         fact a call needing a TOC adjustment.  */
                      if ((code_sec != NULL
                           && code_sec->output_section != NULL
-                          && (htab->sec_info[code_sec->id].toc_off
-                              != htab->sec_info[section->id].toc_off)
                           && (code_sec->has_toc_reloc
-                              || code_sec->makes_toc_func_call))
+                              || code_sec->makes_toc_func_call)
+                          && (htab->sec_info[code_sec->id].toc_off
+                              != htab->sec_info[section->id].toc_off))
                          || (((hash ? hash->elf.other : sym->st_other)
                               & STO_PPC64_LOCAL_MASK)
                              == 1 << STO_PPC64_LOCAL_BIT))
-                       stub_type = ppc_stub_long_branch_r2off;
+                       {
+                         stub_type.main = ppc_stub_long_branch;
+                         stub_type.sub = ppc_stub_toc;
+                         stub_type.r2save = 1;
+                       }
                    }
 
-                 if (stub_type == ppc_stub_none)
+                 if (stub_type.main == ppc_stub_none)
                    continue;
 
                  /* __tls_get_addr calls might be eliminated.  */
-                 if (stub_type != ppc_stub_plt_call
-                     && stub_type != ppc_stub_plt_call_notoc
+                 if (stub_type.main != ppc_stub_plt_call
                      && hash != NULL
                      && is_tls_get_addr (&hash->elf, htab)
                      && section->has_tls_reloc
@@ -13397,7 +14024,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                        continue;
                    }
 
-                 if (stub_type == ppc_stub_plt_call)
+                 if (stub_type.main == ppc_stub_plt_call
+                     && stub_type.sub == ppc_stub_toc)
                    {
                      if (!htab->opd_abi
                          && htab->params->plt_localentry0 != 0
@@ -13413,7 +14041,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                            goto error_ret_free_internal;
                        }
                      else
-                       stub_type = ppc_stub_plt_call_r2save;
+                       stub_type.r2save = 1;
                    }
 
                  /* Support for grouping stub sections.  */
@@ -13425,75 +14053,18 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    goto error_ret_free_internal;
 
                  stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table,
-                                                    stub_name, FALSE, FALSE);
+                                                    stub_name, false, false);
                  if (stub_entry != NULL)
                    {
-                     enum ppc_stub_type old_type;
-                     /* A stub has already been created, but it may
-                        not be the required type.  We shouldn't be
-                        transitioning from plt_call to long_branch
-                        stubs or vice versa, but we might be
-                        upgrading from plt_call to plt_call_r2save or
-                        from long_branch to long_branch_r2off.  */
                      free (stub_name);
-                     old_type = stub_entry->stub_type;
-                     switch (old_type)
+                     if (!ppc_merge_stub (htab, stub_entry, stub_type, r_type))
                        {
-                       default:
-                         abort ();
-
-                       case ppc_stub_save_res:
-                         continue;
-
-                       case ppc_stub_plt_call:
-                       case ppc_stub_plt_call_r2save:
-                       case ppc_stub_plt_call_notoc:
-                       case ppc_stub_plt_call_both:
-                         if (stub_type == ppc_stub_plt_call)
-                           continue;
-                         else if (stub_type == ppc_stub_plt_call_r2save)
-                           {
-                             if (old_type == ppc_stub_plt_call_notoc)
-                               stub_type = ppc_stub_plt_call_both;
-                           }
-                         else if (stub_type == ppc_stub_plt_call_notoc)
-                           {
-                             if (old_type == ppc_stub_plt_call_r2save)
-                               stub_type = ppc_stub_plt_call_both;
-                           }
-                         else
-                           abort ();
-                         break;
-
-                       case ppc_stub_plt_branch:
-                       case ppc_stub_plt_branch_r2off:
-                       case ppc_stub_plt_branch_notoc:
-                       case ppc_stub_plt_branch_both:
-                         old_type += (ppc_stub_long_branch
-                                      - ppc_stub_plt_branch);
-                         /* Fall through.  */
-                       case ppc_stub_long_branch:
-                       case ppc_stub_long_branch_r2off:
-                       case ppc_stub_long_branch_notoc:
-                       case ppc_stub_long_branch_both:
-                         if (stub_type == ppc_stub_long_branch)
-                           continue;
-                         else if (stub_type == ppc_stub_long_branch_r2off)
-                           {
-                             if (old_type == ppc_stub_long_branch_notoc)
-                               stub_type = ppc_stub_long_branch_both;
-                           }
-                         else if (stub_type == ppc_stub_long_branch_notoc)
-                           {
-                             if (old_type == ppc_stub_long_branch_r2off)
-                               stub_type = ppc_stub_long_branch_both;
-                           }
-                         else
-                           abort ();
-                         break;
+                         /* xgettext:c-format */
+                         _bfd_error_handler
+                           (_("%pB: cannot create stub entry %s"),
+                            section->owner, stub_entry->root.string);
+                         goto error_ret_free_internal;
                        }
-                     if (old_type < stub_type)
-                       stub_entry->stub_type = stub_type;
                      continue;
                    }
 
@@ -13505,16 +14076,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                      if (elf_section_data (section)->relocs == NULL)
                        free (internal_relocs);
                    error_ret_free_local:
-                     if (local_syms != NULL
-                         && (symtab_hdr->contents
-                             != (unsigned char *) local_syms))
+                     if (symtab_hdr->contents
+                         != (unsigned char *) local_syms)
                        free (local_syms);
-                     return FALSE;
+                     return false;
                    }
 
-                 stub_entry->stub_type = stub_type;
-                 if (stub_type >= ppc_stub_plt_call
-                     && stub_type <= ppc_stub_plt_call_both)
+                 stub_entry->type = stub_type;
+                 if (stub_type.main == ppc_stub_plt_call)
                    {
                      stub_entry->target_value = sym_value;
                      stub_entry->target_section = sym_sec;
@@ -13561,10 +14130,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
            {
              asection *stub_sec = group->stub_sec;
 
-             if (htab->stub_iteration <= STUB_SHRINK_ITER
-                 || stub_sec->rawsize < stub_sec->size)
-               /* Past STUB_SHRINK_ITER, rawsize is the max size seen.  */
-               stub_sec->rawsize = stub_sec->size;
+             stub_sec->rawsize = stub_sec->size;
              stub_sec->size = 0;
              stub_sec->reloc_count = 0;
              stub_sec->flags &= ~SEC_RELOC;
@@ -13579,15 +14145,20 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          htab->tga_group->stub_sec->size = 24 * 4;
        }
 
-      if (htab->stub_iteration <= STUB_SHRINK_ITER
-         || htab->brlt->rawsize < htab->brlt->size)
-       htab->brlt->rawsize = htab->brlt->size;
+      htab->brlt->rawsize = htab->brlt->size;
       htab->brlt->size = 0;
       htab->brlt->reloc_count = 0;
       htab->brlt->flags &= ~SEC_RELOC;
       if (htab->relbrlt != NULL)
        htab->relbrlt->size = 0;
 
+      if (htab->elf.srelrdyn != NULL)
+       {
+         htab->elf.srelrdyn->rawsize = htab->elf.srelrdyn->size;
+         htab->elf.srelrdyn->size = 0;
+       }
+
+      htab->stub_changed = false;
       bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
       for (group = htab->group; group != NULL; group = group->next)
@@ -13629,6 +14200,53 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                = (group->stub_sec->size + (1 << align) - 1) & -(1 << align);
            }
 
+      if (htab->elf.srelrdyn != NULL)
+       {
+         bfd_vma r_offset;
+
+         for (r_offset = 0; r_offset < htab->brlt->size; r_offset += 8)
+           if (!append_relr_off (htab, (r_offset
+                                        + htab->brlt->output_section->vma
+                                        + htab->brlt->output_offset)))
+             return false;
+
+         if (!got_and_plt_relr_for_local_syms (info))
+           return false;
+         elf_link_hash_traverse (&htab->elf, got_and_plt_relr, info);
+         if (htab->stub_error)
+           return false;
+
+         if (htab->relr_count > 1)
+           qsort (htab->relr_addr, htab->relr_count, sizeof (*htab->relr_addr),
+                  compare_relr_address);
+
+         size_t i = 0;
+         while (i < htab->relr_count)
+           {
+             bfd_vma base = htab->relr_addr[i];
+             htab->elf.srelrdyn->size += 8;
+             i++;
+             /* Handle possible duplicate address.  This can happen
+                as sections increase in size when adding stubs.  */
+             while (i < htab->relr_count
+                    && htab->relr_addr[i] == base)
+               i++;
+             base += 8;
+             while (1)
+               {
+                 size_t start_i = i;
+                 while (i < htab->relr_count
+                        && htab->relr_addr[i] - base < 63 * 8
+                        && (htab->relr_addr[i] - base) % 8 == 0)
+                   i++;
+                 if (i == start_i)
+                   break;
+                 htab->elf.srelrdyn->size += 8;
+                 base += 63 * 8;
+               }
+           }
+       }
+
       for (group = htab->group; group != NULL; group = group->next)
        if (group->stub_sec != NULL
            && group->stub_sec->rawsize != group->stub_sec->size
@@ -13637,15 +14255,36 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          break;
 
       if (group == NULL
+         && (!htab->stub_changed
+             || htab->stub_iteration > STUB_SHRINK_ITER)
          && (htab->brlt->rawsize == htab->brlt->size
              || (htab->stub_iteration > STUB_SHRINK_ITER
                  && htab->brlt->rawsize > htab->brlt->size))
+         && (htab->elf.srelrdyn == NULL
+             || htab->elf.srelrdyn->rawsize == htab->elf.srelrdyn->size
+             || (htab->stub_iteration > STUB_SHRINK_ITER
+                 && htab->elf.srelrdyn->rawsize > htab->elf.srelrdyn->size))
          && (htab->glink_eh_frame == NULL
              || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)
          && (htab->tga_group == NULL
              || htab->stub_iteration > 1))
        break;
 
+      if (htab->stub_iteration > STUB_SHRINK_ITER)
+       {
+         for (group = htab->group; group != NULL; group = group->next)
+           if (group->stub_sec != NULL
+               && group->stub_sec->size < group->stub_sec->rawsize)
+             group->stub_sec->size = group->stub_sec->rawsize;
+
+         if (htab->brlt->size < htab->brlt->rawsize)
+           htab->brlt->size = htab->brlt->rawsize;
+
+         if (htab->elf.srelrdyn != NULL
+             && htab->elf.srelrdyn->size < htab->elf.srelrdyn->rawsize)
+           htab->elf.srelrdyn->size = htab->elf.srelrdyn->rawsize;
+       }
+
       /* Ask the linker to do its stuff.  */
       (*htab->params->layout_sections_again) ();
     }
@@ -13664,7 +14303,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
         indexed in .eh_frame_hdr.  */
       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
       if (p == NULL)
-       return FALSE;
+       return false;
       htab->glink_eh_frame->contents = p;
       last_fde = p;
       align = 4;
@@ -13719,11 +14358,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          /* Augmentation.  */
          p += 1;
 
-         *p++ = DW_CFA_advance_loc + 1;
+         *p++ = DW_CFA_advance_loc + (htab->has_plt_localentry0 ? 3 : 2);
          *p++ = DW_CFA_register;
          *p++ = 65;
          *p++ = htab->opd_abi ? 12 : 0;
-         *p++ = DW_CFA_advance_loc + (htab->opd_abi ? 5 : 7);
+         *p++ = DW_CFA_advance_loc + (htab->opd_abi ? 4 : 2);
          *p++ = DW_CFA_restore_extended;
          *p++ = 65;
          p += ((24 + align - 1) & -align) - 24;
@@ -13739,10 +14378,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
     }
 
   maybe_strip_output (info, htab->brlt);
+  if (htab->relbrlt != NULL)
+    maybe_strip_output (info, htab->relbrlt);
   if (htab->glink_eh_frame != NULL)
     maybe_strip_output (info, htab->glink_eh_frame);
+  if (htab->elf.srelrdyn != NULL)
+    maybe_strip_output (info, htab->elf.srelrdyn);
 
-  return TRUE;
+  return true;
 }
 
 /* Called after we have determined section placement.  If sections
@@ -13759,19 +14402,20 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
       struct elf_link_hash_entry *h;
       struct elf_link_hash_table *htab = elf_hash_table (info);
 
-      if (is_elf_hash_table (htab)
+      if (is_elf_hash_table (&htab->root)
          && htab->hgot != NULL)
        h = htab->hgot;
       else
        {
-         h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE);
-         if (is_elf_hash_table (htab))
+         h = (struct elf_link_hash_entry *)
+           bfd_link_hash_lookup (&htab->root, ".TOC.", false, false, true);
+         if (is_elf_hash_table (&htab->root))
            htab->hgot = h;
        }
       if (h != NULL
          && h->root.type == bfd_link_hash_defined
          && !h->root.linker_def
-         && (!is_elf_hash_table (htab)
+         && (!is_elf_hash_table (&htab->root)
              || h->def_regular))
        {
          TOCstart = defined_sym_val (h) - TOC_BASE_OFF;
@@ -13848,7 +14492,7 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
          struct bfd_link_hash_entry *bh = NULL;
          _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
                                            s, TOC_BASE_OFF - adjust,
-                                           NULL, FALSE, FALSE, &bh);
+                                           NULL, false, false, &bh);
        }
     }
   return TOCstart;
@@ -13857,7 +14501,7 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 /* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
    write out any global entry stubs, and PLT relocations.  */
 
-static bfd_boolean
+static bool
 build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
@@ -13866,12 +14510,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
   asection *s;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   info = inf;
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
@@ -13882,8 +14526,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
        asection *plt, *relplt;
        bfd_byte *loc;
 
-       if (!htab->elf.dynamic_sections_created
-           || h->dynindx == -1)
+       if (use_local_plt (info, h))
          {
            if (!(h->def_regular
                  && (h->root.type == bfd_link_hash_defined
@@ -13893,7 +14536,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
              {
                plt = htab->elf.iplt;
                relplt = htab->elf.irelplt;
-               htab->local_ifunc_resolver = 1;
+               htab->elf.ifunc_resolvers = true;
                if (htab->opd_abi)
                  rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
                else
@@ -13902,7 +14545,9 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
            else
              {
                plt = htab->pltlocal;
-               if (bfd_link_pic (info))
+               relplt = NULL;
+               if (bfd_link_pic (info)
+                   && !(info->enable_dt_relr && !htab->opd_abi))
                  {
                    relplt = htab->relpltlocal;
                    if (htab->opd_abi)
@@ -13910,8 +14555,6 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
                    else
                      rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
                  }
-               else
-                 relplt = NULL;
              }
            rela.r_addend = defined_sym_val (h) + ent->addend;
 
@@ -13947,20 +14590,20 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
                   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
                      / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
            if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-             htab->maybe_local_ifunc_resolver = 1;
+             htab->elf.ifunc_resolvers = true;
            bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
          }
       }
 
   if (!h->pointer_equality_needed)
-    return TRUE;
+    return true;
 
   if (h->def_regular)
-    return TRUE;
+    return true;
 
   s = htab->global_entry;
   if (s == NULL || s->size == 0)
-    return TRUE;
+    return true;
 
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1
@@ -13972,8 +14615,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
 
        p = s->contents + h->root.u.def.value;
        plt = htab->elf.splt;
-       if (!htab->elf.dynamic_sections_created
-           || h->dynindx == -1)
+       if (use_local_plt (info, h))
          {
            if (h->type == STT_GNU_IFUNC)
              plt = htab->elf.iplt;
@@ -13989,7 +14631,7 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
              (_("%P: linkage table error against `%pT'\n"),
               h->root.root.string);
            bfd_set_error (bfd_error_bad_value);
-           htab->stub_error = TRUE;
+           htab->stub_error = true;
          }
 
        htab->stub_count[ppc_stub_global_entry - 1] += 1;
@@ -13999,12 +14641,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
            char *name = bfd_malloc (sizeof "12345678.global_entry." + len);
 
            if (name == NULL)
-             return FALSE;
+             return false;
 
            sprintf (name, "%08x.global_entry.%s", s->id, h->root.root.string);
-           h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
+           h = elf_link_hash_lookup (&htab->elf, name, true, false, false);
            if (h == NULL)
-             return FALSE;
+             return false;
            if (h->root.type == bfd_link_hash_new)
              {
                h->root.type = bfd_link_hash_defined;
@@ -14031,12 +14673,12 @@ build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
        bfd_put_32 (s->owner, BCTR, p);
        break;
       }
-  return TRUE;
+  return true;
 }
 
 /* Write PLT relocs for locals.  */
 
-static bfd_boolean
+static bool
 write_plt_relocs_for_local_syms (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
@@ -14076,28 +14718,28 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
              if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
                              lplt - local_plt, ibfd))
                {
-                 if (local_syms != NULL
-                     && symtab_hdr->contents != (unsigned char *) local_syms)
+                 if (symtab_hdr->contents != (unsigned char *) local_syms)
                    free (local_syms);
-                 return FALSE;
+                 return false;
                }
 
              val = sym->st_value + ent->addend;
-             if (ELF_ST_TYPE (sym->st_info) != STT_GNU_IFUNC)
-               val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
              if (sym_sec != NULL && sym_sec->output_section != NULL)
                val += sym_sec->output_offset + sym_sec->output_section->vma;
 
              if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                {
-                 htab->local_ifunc_resolver = 1;
+                 htab->elf.ifunc_resolvers = true;
                  plt = htab->elf.iplt;
                  relplt = htab->elf.irelplt;
                }
              else
                {
                  plt = htab->pltlocal;
-                 relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                 relplt = NULL;
+                 if (bfd_link_pic (info)
+                     && !(info->enable_dt_relr && !htab->opd_abi))
+                   relplt = htab->relpltlocal;
                }
 
              if (relplt == NULL)
@@ -14146,13 +14788,13 @@ write_plt_relocs_for_local_syms (struct bfd_link_info *info)
            symtab_hdr->contents = (unsigned char *) local_syms;
        }
     }
-  return TRUE;
+  return true;
 }
 
 /* Emit the static wrapper function preserving registers around a
    __tls_get_addr_opt call.  */
 
-static bfd_boolean
+static bool
 emit_tga_desc (struct ppc_link_hash_table *htab)
 {
   asection *stub_sec = htab->tga_group->stub_sec;
@@ -14169,8 +14811,8 @@ emit_tga_desc (struct ppc_link_hash_table *htab)
   if (delta + (1 << 25) >= 1 << 26)
     {
       _bfd_error_handler (_("__tls_get_addr call offset overflow"));
-      htab->stub_error = TRUE;
-      return FALSE;
+      htab->stub_error = true;
+      return false;
     }
 
   p = stub_sec->contents;
@@ -14221,7 +14863,7 @@ emit_tga_desc_eh_frame (struct ppc_link_hash_table *htab, bfd_byte *p)
    The stubs are kept in a hash table attached to the main linker
    hash table.  This function is called via gldelf64ppc_finish.  */
 
-bfd_boolean
+bool
 ppc64_elf_build_stubs (struct bfd_link_info *info,
                       char **stats)
 {
@@ -14232,7 +14874,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   int stub_sec_count = 0;
 
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* Allocate memory to hold the linker stubs.  */
   for (group = htab->group; group != NULL; group = group->next)
@@ -14245,7 +14887,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
          stub_sec->contents = bfd_zalloc (htab->params->stub_bfd,
                                           stub_sec->size);
          if (stub_sec->contents == NULL)
-           return FALSE;
+           return false;
          stub_sec->size = 0;
        }
     }
@@ -14260,9 +14902,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        {
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
-                                   TRUE, FALSE, FALSE);
+                                   true, false, false);
          if (h == NULL)
-           return FALSE;
+           return false;
          if (h->root.type == bfd_link_hash_new)
            {
              h->root.type = bfd_link_hash_defined;
@@ -14283,7 +14925,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        {
          Elf_Internal_Rela *r = get_relocs (htab->glink, 1);
          if (r == NULL)
-           return FALSE;
+           return false;
          r->r_offset = (htab->glink->output_offset
                         + htab->glink->output_section->vma);
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL64);
@@ -14318,23 +14960,60 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        }
       else
        {
+         unsigned int insn;
+
+         /* 0:
+            .  .quad plt0-1f           # plt0 entry relative to 1:
+            #
+            # We get here with r12 initially @ a glink branch
+            # Load the address of _dl_runtime_resolve from plt0 and
+            # jump to it, with r0 set to the index of the PLT entry
+            # to be resolved and r11 the link map.
+            __glink_PLTresolve:
+            .  std %r2,24(%r1)         # optional
+            .  mflr %r0
+            .  bcl 20,31,1f
+            1:
+            .  mflr %r11
+            .  mtlr %r0
+            .  ld %r0,(0b-1b)(%r11)
+            .  sub %r12,%r12,%r11
+            .  add %r11,%r0,%r11
+            .  addi %r0,%r12,1b-2f
+            .  ld %r12,0(%r11)
+            .  srdi %r0,%r0,2
+            .  mtctr %r12
+            .  ld %r11,8(%r11)
+            .  bctr
+            2:
+            .  b __glink_PLTresolve
+            .  ...
+            .  b __glink_PLTresolve  */
+
+         if (htab->has_plt_localentry0)
+           {
+             bfd_put_32 (htab->glink->owner, STD_R2_0R1 + 24, p);
+             p += 4;
+           }
          bfd_put_32 (htab->glink->owner, MFLR_R0, p);
          p += 4;
          bfd_put_32 (htab->glink->owner, BCL_20_31, p);
          p += 4;
          bfd_put_32 (htab->glink->owner, MFLR_R11, p);
          p += 4;
-         bfd_put_32 (htab->glink->owner, STD_R2_0R1 + 24, p);
-         p += 4;
-         bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p);
-         p += 4;
          bfd_put_32 (htab->glink->owner, MTLR_R0, p);
          p += 4;
+         if (htab->has_plt_localentry0)
+           insn = LD_R0_0R11 | (-20 & 0xfffc);
+         else
+           insn = LD_R0_0R11 | (-16 & 0xfffc);
+         bfd_put_32 (htab->glink->owner, insn, p);
+         p += 4;
          bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p);
          p += 4;
-         bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p);
+         bfd_put_32 (htab->glink->owner, ADD_R11_R0_R11, p);
          p += 4;
-         bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p);
+         bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-44 & 0xffff), p);
          p += 4;
          bfd_put_32 (htab->glink->owner, LD_R12_0R11, p);
          p += 4;
@@ -14381,7 +15060,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
       htab->tga_group->lr_restore = 23 * 4;
       htab->tga_group->stub_sec->size = 24 * 4;
       if (!emit_tga_desc (htab))
-       return FALSE;
+       return false;
       if (htab->glink_eh_frame != NULL
          && htab->glink_eh_frame->size != 0)
        {
@@ -14398,21 +15077,21 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
 
   if (!write_plt_relocs_for_local_syms (info))
-    return FALSE;
+    return false;
 
   if (htab->brlt != NULL && htab->brlt->size != 0)
     {
       htab->brlt->contents = bfd_zalloc (htab->brlt->owner,
                                         htab->brlt->size);
       if (htab->brlt->contents == NULL)
-       return FALSE;
+       return false;
     }
   if (htab->relbrlt != NULL && htab->relbrlt->size != 0)
     {
       htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner,
                                            htab->relbrlt->size);
       if (htab->relbrlt->contents == NULL)
-       return FALSE;
+       return false;
     }
 
   /* Build the stubs as directed by the stub hash table.  */
@@ -14445,7 +15124,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
 
            for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++)
              if (!sfpr_define (info, &save_res_funcs[i], stub_sec))
-               return FALSE;
+               return false;
          }
       }
 
@@ -14472,7 +15151,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
                _bfd_error_handler
                  (_("%s offset too large for .eh_frame sdata4 encoding"),
                   group->stub_sec->name);
-               return FALSE;
+               return false;
              }
            bfd_put_32 (htab->elf.dynobj, val, p + 8);
            p += (group->eh_size + 17 + 3) & -4;
@@ -14491,13 +15170,62 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
              _bfd_error_handler
                (_("%s offset too large for .eh_frame sdata4 encoding"),
                 htab->glink->name);
-             return FALSE;
+             return false;
            }
          bfd_put_32 (htab->elf.dynobj, val, p + 8);
          p += (24 + align - 1) & -align;
        }
     }
 
+  if (htab->elf.srelrdyn != NULL && htab->elf.srelrdyn->size != 0)
+    {
+      htab->elf.srelrdyn->contents
+       = bfd_alloc (htab->elf.dynobj, htab->elf.srelrdyn->size);
+      if (htab->elf.srelrdyn->contents == NULL)
+       return false;
+
+      size_t i = 0;
+      bfd_byte *loc = htab->elf.srelrdyn->contents;
+      while (i < htab->relr_count)
+       {
+         bfd_vma base = htab->relr_addr[i];
+         BFD_ASSERT (base % 2 == 0);
+         bfd_put_64 (htab->elf.dynobj, base, loc);
+         loc += 8;
+         i++;
+         while (i < htab->relr_count
+                && htab->relr_addr[i] == base)
+           {
+             htab->stub_error = true;
+             i++;
+           }
+         base += 8;
+         while (1)
+           {
+             bfd_vma bits = 0;
+             while (i < htab->relr_count
+                    && htab->relr_addr[i] - base < 63 * 8
+                    && (htab->relr_addr[i] - base) % 8 == 0)
+               {
+                 bits |= (bfd_vma) 1 << ((htab->relr_addr[i] - base) / 8);
+                 i++;
+               }
+             if (bits == 0)
+               break;
+             bfd_put_64 (htab->elf.dynobj, (bits << 1) | 1, loc);
+             loc += 8;
+             base += 63 * 8;
+           }
+       }
+      /* Pad any excess with 1's, a do-nothing encoding.  */
+      while ((size_t) (loc - htab->elf.srelrdyn->contents)
+            < htab->elf.srelrdyn->size)
+       {
+         bfd_put_64 (htab->elf.dynobj, 1, loc);
+         loc += 8;
+       }
+    }
+
   for (group = htab->group; group != NULL; group = group->next)
     if ((stub_sec = group->stub_sec) != NULL)
       {
@@ -14509,54 +15237,40 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
       }
 
   if (group != NULL)
+    htab->stub_error = true;
+
+  if (htab->stub_error)
     {
-      htab->stub_error = TRUE;
       _bfd_error_handler (_("stubs don't match calculated size"));
+      return false;
     }
 
-  if (htab->stub_error)
-    return FALSE;
-
   if (stats != NULL)
     {
-      size_t len;
-      *stats = bfd_malloc (500);
-      if (*stats == NULL)
-       return FALSE;
-
-      len = sprintf (*stats,
-                    ngettext ("linker stubs in %u group\n",
-                              "linker stubs in %u groups\n",
-                              stub_sec_count),
-                    stub_sec_count);
-      sprintf (*stats + len, _("  branch         %lu\n"
-                              "  branch toc adj %lu\n"
-                              "  branch notoc   %lu\n"
-                              "  branch both    %lu\n"
-                              "  long branch    %lu\n"
-                              "  long toc adj   %lu\n"
-                              "  long notoc     %lu\n"
-                              "  long both      %lu\n"
-                              "  plt call       %lu\n"
-                              "  plt call save  %lu\n"
-                              "  plt call notoc %lu\n"
-                              "  plt call both  %lu\n"
-                              "  global entry   %lu"),
-              htab->stub_count[ppc_stub_long_branch - 1],
-              htab->stub_count[ppc_stub_long_branch_r2off - 1],
-              htab->stub_count[ppc_stub_long_branch_notoc - 1],
-              htab->stub_count[ppc_stub_long_branch_both - 1],
-              htab->stub_count[ppc_stub_plt_branch - 1],
-              htab->stub_count[ppc_stub_plt_branch_r2off - 1],
-              htab->stub_count[ppc_stub_plt_branch_notoc - 1],
-              htab->stub_count[ppc_stub_plt_branch_both - 1],
-              htab->stub_count[ppc_stub_plt_call - 1],
-              htab->stub_count[ppc_stub_plt_call_r2save - 1],
-              htab->stub_count[ppc_stub_plt_call_notoc - 1],
-              htab->stub_count[ppc_stub_plt_call_both - 1],
-              htab->stub_count[ppc_stub_global_entry - 1]);
+      char *groupmsg;
+      if (asprintf (&groupmsg,
+                   ngettext ("linker stubs in %u group\n",
+                             "linker stubs in %u groups\n",
+                             stub_sec_count),
+                   stub_sec_count) < 0)
+       *stats = NULL;
+      else
+       {
+         if (asprintf (stats, _("%s"
+                                "  branch         %lu\n"
+                                "  long branch    %lu\n"
+                                "  plt call       %lu\n"
+                                "  global entry   %lu"),
+                       groupmsg,
+                       htab->stub_count[ppc_stub_long_branch - 1],
+                       htab->stub_count[ppc_stub_plt_branch - 1],
+                       htab->stub_count[ppc_stub_plt_call - 1],
+                       htab->stub_count[ppc_stub_global_entry - 1]) < 0)
+           *stats = NULL;
+         free (groupmsg);
+       }
     }
-  return TRUE;
+  return true;
 }
 
 /* What to do when ld finds relocations against symbols defined in
@@ -14579,7 +15293,7 @@ ppc64_elf_action_discarded (asection *sec)
 
 /* These are the dynamic relocations supported by glibc.  */
 
-static bfd_boolean
+static bool
 ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
 {
   switch (r_type)
@@ -14630,10 +15344,10 @@ ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
     case R_PPC64_ADDR14_BRNTAKEN:
     case R_PPC64_REL32:
     case R_PPC64_REL64:
-      return TRUE;
+      return true;
 
     default:
-      return FALSE;
+      return false;
     }
 }
 
@@ -14666,7 +15380,7 @@ ppc64_glibc_dynamic_reloc (enum elf_ppc64_reloc_type r_type)
    section, which means that the addend must be adjusted
    accordingly.  */
 
-static bfd_boolean
+static int
 ppc64_elf_relocate_section (bfd *output_bfd,
                            struct bfd_link_info *info,
                            bfd *input_bfd,
@@ -14686,11 +15400,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   bfd_byte *loc;
   struct got_entry **local_got_ents;
   bfd_vma TOCstart;
-  bfd_boolean ret = TRUE;
-  bfd_boolean is_opd;
+  bool ret = true;
+  bool is_opd;
   /* Assume 'at' branch hints.  */
-  bfd_boolean is_isa_v2 = TRUE;
-  bfd_boolean warned_dynamic = FALSE;
+  bool is_isa_v2 = true;
+  bool warned_dynamic = false;
   bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
 
   /* Initialize howto table if needed.  */
@@ -14699,16 +15413,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* Don't relocate stub sections.  */
   if (input_section->owner == htab->params->stub_bfd)
-    return TRUE;
+    return true;
 
   if (!is_ppc64_elf (input_bfd))
     {
       bfd_set_error (bfd_error_wrong_format);
-      return FALSE;
+      return false;
     }
 
   local_got_ents = elf_local_got_ents (input_bfd);
@@ -14735,8 +15449,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       unsigned char tls_mask, tls_gd, tls_type;
       unsigned char sym_type;
       bfd_vma relocation;
-      bfd_boolean unresolved_reloc, save_unresolved_reloc;
-      bfd_boolean warned;
+      bool unresolved_reloc, save_unresolved_reloc;
+      bool warned;
       enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
       unsigned int insn;
       unsigned int mask;
@@ -14768,8 +15482,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       sec = NULL;
       h_elf = NULL;
       sym_name = NULL;
-      unresolved_reloc = FALSE;
-      warned = FALSE;
+      unresolved_reloc = false;
+      warned = false;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -14804,7 +15518,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
       else
        {
-         bfd_boolean ignored;
+         bool ignored;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
@@ -14869,7 +15583,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        {
          relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
          sec = bfd_abs_section_ptr;
-         unresolved_reloc = FALSE;
+         unresolved_reloc = false;
        }
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -14899,7 +15613,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
                             &local_syms, rel, input_bfd))
-           return FALSE;
+           return false;
 
          if (toc_tls)
            tls_mask = *toc_tls;
@@ -14951,13 +15665,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_LO_DS_OPT:
-         insn = bfd_get_32 (input_bfd, contents + rel->r_offset - d_offset);
-         if ((insn & (0x3fu << 26)) != 58u << 26)
-           abort ();
-         insn += (14u << 26) - (58u << 26);
-         bfd_put_32 (input_bfd, insn, contents + rel->r_offset - d_offset);
-         r_type = R_PPC64_TOC16_LO;
-         rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+         if (offset_in_range (input_section, rel->r_offset - d_offset, 4))
+           {
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
+             if ((insn & (0x3fu << 26)) != 58u << 26)
+               abort ();
+             insn += (14u << 26) - (58u << 26);
+             bfd_put_32 (input_bfd, insn,
+                         contents + rel->r_offset - d_offset);
+             r_type = R_PPC64_TOC16_LO;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+           }
          break;
 
        case R_PPC64_TOC16:
@@ -14972,7 +15691,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
                                   &local_syms, rel, input_bfd);
            if (retval == 0)
-             return FALSE;
+             return false;
 
            if (toc_tls)
              {
@@ -15009,7 +15728,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
          if ((tls_mask & TLS_TLS) != 0
-             && (tls_mask & TLS_TPREL) == 0)
+             && (tls_mask & TLS_TPREL) == 0
+             && offset_in_range (input_section, rel->r_offset - d_offset, 4))
            {
              rel->r_offset -= d_offset;
              bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
@@ -15021,7 +15741,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TPREL16_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
          if ((tls_mask & TLS_TLS) != 0
-             && (tls_mask & TLS_TPREL) == 0)
+             && (tls_mask & TLS_TPREL) == 0
+             && offset_in_range (input_section, rel->r_offset - d_offset, 4))
            {
            toctprel:
              insn = bfd_get_32 (input_bfd,
@@ -15044,9 +15765,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
-       case R_PPC64_GOT_TPREL34:
+       case R_PPC64_GOT_TPREL_PCREL34:
          if ((tls_mask & TLS_TLS) != 0
-             && (tls_mask & TLS_TPREL) == 0)
+             && (tls_mask & TLS_TPREL) == 0
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              /* pld ra,sym@got@tprel@pcrel -> paddi ra,r13,sym@tprel  */
              pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
@@ -15065,7 +15787,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_TLS:
          if ((tls_mask & TLS_TLS) != 0
-             && (tls_mask & TLS_TPREL) == 0)
+             && (tls_mask & TLS_TPREL) == 0
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
              insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
@@ -15116,13 +15839,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSGD16_HI:
        case R_PPC64_GOT_TLSGD16_HA:
          tls_gd = TLS_GDIE;
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            goto tls_gdld_hi;
          break;
 
        case R_PPC64_GOT_TLSLD16_HI:
        case R_PPC64_GOT_TLSLD16_HA:
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
            tls_gdld_hi:
              if ((tls_mask & tls_gd) != 0)
@@ -15141,13 +15866,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSGD16:
        case R_PPC64_GOT_TLSGD16_LO:
          tls_gd = TLS_GDIE;
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            goto tls_ldgd_opt;
          break;
 
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              unsigned int insn1, insn2;
 
@@ -15217,10 +15944,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
              bfd_put_32 (input_bfd, insn1,
                          contents + rel->r_offset - d_offset);
-             if (offset != (bfd_vma) -1)
+             if (offset != (bfd_vma) -1
+                 && offset_in_range (input_section, offset, 4))
                {
                  bfd_put_32 (input_bfd, insn2, contents + offset);
-                 if (offset + 8 <= input_section->size)
+                 if (offset_in_range (input_section, offset + 4, 4))
                    {
                      insn2 = bfd_get_32 (input_bfd, contents + offset + 4);
                      if (insn2 == LD_R2_0R1 + STK_TOC (htab))
@@ -15237,8 +15965,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
-       case R_PPC64_GOT_TLSGD34:
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+       case R_PPC64_GOT_TLSGD_PCREL34:
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              pinsn <<= 32;
@@ -15247,7 +15976,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                {
                  /* IE, pla -> pld  */
                  pinsn += (-2ULL << 56) + (57ULL << 26) - (14ULL << 26);
-                 r_type = R_PPC64_GOT_TPREL34;
+                 r_type = R_PPC64_GOT_TPREL_PCREL34;
                }
              else
                {
@@ -15263,8 +15992,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          break;
 
-       case R_PPC64_GOT_TLSLD34:
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
+       case R_PPC64_GOT_TLSLD_PCREL34:
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              pinsn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              pinsn <<= 32;
@@ -15284,7 +16014,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_TLSGD:
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
-             && rel + 1 < relend)
+             && rel + 1 < relend
+             && offset_in_range (input_section, rel->r_offset,
+                                 is_8byte_reloc (ELF64_R_TYPE (rel[1].r_info))
+                                 ? 8 : 4))
            {
              unsigned int insn2;
              enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
@@ -15300,7 +16033,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  break;
                }
 
-             if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+             if (r_type1 == R_PPC64_PLTCALL)
                bfd_put_32 (output_bfd, NOP, contents + offset + 4);
 
              if ((tls_mask & TLS_GDIE) != 0)
@@ -15318,6 +16051,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      rel->r_addend = toc_addend;
                    }
                  if (r_type1 == R_PPC64_REL24_NOTOC
+                     || r_type1 == R_PPC64_REL24_P9NOTOC
                      || r_type1 == R_PPC64_PLTCALL_NOTOC)
                    {
                      r_type = R_PPC64_NONE;
@@ -15344,7 +16078,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_TLSLD:
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
-             && rel + 1 < relend)
+             && rel + 1 < relend
+             && offset_in_range (input_section, rel->r_offset,
+                                 is_8byte_reloc (ELF64_R_TYPE (rel[1].r_info))
+                                 ? 8 : 4))
            {
              unsigned int insn2;
              enum elf_ppc64_reloc_type r_type1 = ELF64_R_TYPE (rel[1].r_info);
@@ -15360,10 +16097,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  break;
                }
 
-             if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+             if (r_type1 == R_PPC64_PLTCALL)
                bfd_put_32 (output_bfd, NOP, contents + offset + 4);
 
              if (r_type1 == R_PPC64_REL24_NOTOC
+                 || r_type1 == R_PPC64_REL24_P9NOTOC
                  || r_type1 == R_PPC64_PLTCALL_NOTOC)
                {
                  r_type = R_PPC64_NONE;
@@ -15392,7 +16130,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
              && rel[1].r_offset == rel->r_offset + 8)
            {
-             if ((tls_mask & TLS_GD) == 0)
+             if ((tls_mask & TLS_GD) == 0
+                 && offset_in_range (input_section, rel->r_offset, 8))
                {
                  rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE);
                  if ((tls_mask & TLS_GDIE) != 0)
@@ -15407,7 +16146,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          else
            {
-             if ((tls_mask & TLS_LD) == 0)
+             if ((tls_mask & TLS_LD) == 0
+                 && offset_in_range (input_section, rel->r_offset, 8))
                {
                  bfd_put_64 (output_bfd, 1, contents + rel->r_offset);
                  r_type = R_PPC64_NONE;
@@ -15428,7 +16168,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
          if (!bfd_link_pic (info)
              && !info->traditional_format
-             && relocation + 0x80008000 <= 0xffffffff)
+             && relocation + 0x80008000 <= 0xffffffff
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              unsigned int insn1, insn2;
 
@@ -15450,7 +16191,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              relocation -= (rel->r_offset
                             + input_section->output_offset
                             + input_section->output_section->vma);
-             if (relocation + 0x80008000 <= 0xffffffff)
+             if (relocation + 0x80008000 <= 0xffffffff
+                 && offset_in_range (input_section, rel->r_offset, 8))
                {
                  unsigned int insn1, insn2;
 
@@ -15487,7 +16229,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO)
              && rel[1].r_offset == rel->r_offset + 4
              && rel[1].r_addend == rel->r_addend + 4
-             && relocation + 0x80008000 <= 0xffffffff)
+             && relocation + 0x80008000 <= 0xffffffff
+             && offset_in_range (input_section, rel->r_offset - d_offset, 8))
            {
              unsigned int insn1, insn2;
              offset = rel->r_offset - d_offset;
@@ -15522,7 +16265,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                      + input_section->output_offset
                                      + input_section->output_section->vma)
              && tocsave_find (htab, NO_INSERT,
-                              &local_syms, rel, input_bfd))
+                              &local_syms, rel, input_bfd)
+             && offset_in_range (input_section, rel->r_offset, 4))
            {
              insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              if (insn == NOP
@@ -15542,6 +16286,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
+         if (!offset_in_range (input_section, rel->r_offset, 4))
+           break;
          insn |= bfd_get_32 (input_bfd,
                              contents + rel->r_offset) & ~(0x01 << 21);
          /* Fall through.  */
@@ -15552,6 +16298,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_REL24:
        case R_PPC64_REL24_NOTOC:
+       case R_PPC64_REL24_P9NOTOC:
        case R_PPC64_PLTCALL:
        case R_PPC64_PLTCALL_NOTOC:
          /* Calls to functions with a different TOC, such as calls to
@@ -15570,38 +16317,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          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)
+             && stub_entry->type.main == ppc_stub_plt_call)
            stub_entry = NULL;
 
          if (stub_entry != NULL
-             && ((stub_entry->stub_type >= ppc_stub_plt_call
-                  && stub_entry->stub_type <= ppc_stub_plt_call_both)
-                 || stub_entry->stub_type == ppc_stub_plt_branch_r2off
-                 || stub_entry->stub_type == ppc_stub_plt_branch_both
-                 || stub_entry->stub_type == ppc_stub_long_branch_r2off
-                 || stub_entry->stub_type == ppc_stub_long_branch_both))
+             && (stub_entry->type.main == ppc_stub_plt_call
+                 || stub_entry->type.r2save))
            {
-             bfd_boolean can_plt_call = FALSE;
+             bool can_plt_call = false;
 
-             if (stub_entry->stub_type == ppc_stub_plt_call
-                 && !htab->opd_abi
-                 && htab->params->plt_localentry0 != 0
-                 && is_elfv2_localentry0 (&h->elf))
+             if (r_type == R_PPC64_REL24_NOTOC
+                 || r_type == R_PPC64_REL24_P9NOTOC)
                {
-                 /* The function doesn't use or change r2.  */
-                 can_plt_call = TRUE;
+                 /* NOTOC calls don't need to restore r2.  */
+                 can_plt_call = true;
                }
-             else if (r_type == R_PPC64_REL24_NOTOC)
+             else if (stub_entry->type.main == ppc_stub_plt_call
+                      && !htab->opd_abi
+                      && htab->params->plt_localentry0 != 0
+                      && h != NULL
+                      && is_elfv2_localentry0 (&h->elf))
                {
-                 /* NOTOC calls don't need to restore r2.  */
-                 can_plt_call = TRUE;
+                 /* The function doesn't use or change r2.  */
+                 can_plt_call = true;
                }
 
              /* All of these stubs may modify r2, so there must be a
                 branch and link followed by a nop.  The nop is
                 replaced by an insn to restore r2.  */
-             else if (rel->r_offset + 8 <= input_section->size)
+             else if (offset_in_range (input_section, rel->r_offset, 8))
                {
                  unsigned long br;
 
@@ -15614,7 +16358,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      nop = bfd_get_32 (input_bfd,
                                        contents + rel->r_offset + 4);
                      if (nop == LD_R2_0R1 + STK_TOC (htab))
-                       can_plt_call = TRUE;
+                       can_plt_call = true;
                      else if (nop == NOP
                               || nop == CROR_151515
                               || nop == CROR_313131)
@@ -15629,7 +16373,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                            bfd_put_32 (input_bfd,
                                        LD_R2_0R1 + STK_TOC (htab),
                                        contents + rel->r_offset + 4);
-                         can_plt_call = TRUE;
+                         can_plt_call = true;
                        }
                    }
                }
@@ -15641,13 +16385,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  if (*name == '.')
                    ++name;
 
-                 if (strncmp (name, "__libc_start_main", 17) == 0
+                 if (startswith (name, "__libc_start_main")
                      && (name[17] == 0 || name[17] == '@'))
                    {
                      /* Allow crt1 branch to go via a toc adjusting
                         stub.  Other calls that never return could do
                         the same, if we could detect such.  */
-                     can_plt_call = TRUE;
+                     can_plt_call = true;
                    }
                }
 
@@ -15669,16 +16413,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                     - sec->output_section->vma
                                     - sec->output_offset);
 
-                     opd_entry_value (sec, off, &code_sec, NULL, FALSE);
+                     opd_entry_value (sec, off, &code_sec, NULL, false);
                    }
                  if (code_sec == input_section)
-                   can_plt_call = TRUE;
+                   can_plt_call = true;
                }
 
              if (!can_plt_call)
                {
-                 if (stub_entry->stub_type >= ppc_stub_plt_call
-                     && stub_entry->stub_type <= ppc_stub_plt_call_both)
+                 if (stub_entry->type.main == ppc_stub_plt_call)
                    info->callbacks->einfo
                      /* xgettext:c-format */
                      (_("%H: call to `%pT' lacks nop, can't restore toc; "
@@ -15692,25 +16435,24 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                       input_bfd, input_section, rel->r_offset, sym_name);
 
                  bfd_set_error (bfd_error_bad_value);
-                 ret = FALSE;
+                 ret = false;
                }
 
              if (can_plt_call
-                 && stub_entry->stub_type >= ppc_stub_plt_call
-                 && stub_entry->stub_type <= ppc_stub_plt_call_both)
-               unresolved_reloc = FALSE;
+                 && stub_entry->type.main == ppc_stub_plt_call)
+               unresolved_reloc = false;
            }
 
          if ((stub_entry == NULL
-              || stub_entry->stub_type == ppc_stub_long_branch
-              || stub_entry->stub_type == ppc_stub_plt_branch)
+              || stub_entry->type.main == ppc_stub_long_branch
+              || stub_entry->type.main == ppc_stub_plt_branch)
              && get_opd_info (sec) != NULL)
            {
              /* The branch destination is the value of the opd entry. */
              bfd_vma off = (relocation + addend
                             - sec->output_section->vma
                             - sec->output_offset);
-             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE);
+             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, false);
              if (dest != (bfd_vma) -1)
                {
                  relocation = dest;
@@ -15730,36 +16472,36 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                                  : sym->st_other);
 
          if (stub_entry != NULL
-             && (stub_entry->stub_type == ppc_stub_long_branch
-                 || stub_entry->stub_type == ppc_stub_plt_branch)
-             && (r_type == R_PPC64_ADDR14_BRTAKEN
-                 || r_type == R_PPC64_ADDR14_BRNTAKEN
-                 || (relocation + addend - from + max_br_offset
-                     < 2 * max_br_offset)))
-           /* Don't use the stub if this branch is in range.  */
-           stub_entry = NULL;
-
-         if (stub_entry != NULL
-             && (stub_entry->stub_type == ppc_stub_long_branch_notoc
-                 || stub_entry->stub_type == ppc_stub_long_branch_both
-                 || stub_entry->stub_type == ppc_stub_plt_branch_notoc
-                 || 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)
-             && (relocation + addend - from + max_br_offset
-                 < 2 * max_br_offset))
-           stub_entry = NULL;
-
-         if (stub_entry != NULL
-             && (stub_entry->stub_type == ppc_stub_long_branch_r2off
-                 || stub_entry->stub_type == ppc_stub_long_branch_both
-                 || stub_entry->stub_type == ppc_stub_plt_branch_r2off
-                 || stub_entry->stub_type == ppc_stub_plt_branch_both)
-             && r_type == R_PPC64_REL24_NOTOC
-             && (relocation + addend - from + max_br_offset
-                 < 2 * max_br_offset))
-           stub_entry = NULL;
+             && (stub_entry->type.main == ppc_stub_long_branch
+                 || stub_entry->type.main == ppc_stub_plt_branch))
+           {
+             if (stub_entry->type.sub == ppc_stub_toc
+                 && !stub_entry->type.r2save
+                 && (r_type == R_PPC64_ADDR14_BRTAKEN
+                     || r_type == R_PPC64_ADDR14_BRNTAKEN
+                     || (relocation + addend - from + max_br_offset
+                         < 2 * max_br_offset)))
+               /* Don't use the stub if this branch is in range.  */
+               stub_entry = NULL;
+
+             if (stub_entry != NULL
+                 && stub_entry->type.sub >= ppc_stub_notoc
+                 && ((r_type != R_PPC64_REL24_NOTOC
+                      && r_type != R_PPC64_REL24_P9NOTOC)
+                     || ((fdh ? fdh->elf.other : sym->st_other)
+                         & STO_PPC64_LOCAL_MASK) <= 1 << STO_PPC64_LOCAL_BIT)
+                 && (relocation + addend - from + max_br_offset
+                     < 2 * max_br_offset))
+               stub_entry = NULL;
+
+             if (stub_entry != NULL
+                 && stub_entry->type.r2save
+                 && (r_type == R_PPC64_REL24_NOTOC
+                     || r_type == R_PPC64_REL24_P9NOTOC)
+                 && (relocation + addend - from + max_br_offset
+                     < 2 * max_br_offset))
+               stub_entry = NULL;
+           }
 
          if (stub_entry != NULL)
            {
@@ -15767,7 +16509,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 rather than the procedure directly.  */
              asection *stub_sec = stub_entry->group->stub_sec;
 
-             if (stub_entry->stub_type == ppc_stub_save_res)
+             if (stub_entry->type.main == ppc_stub_save_res)
                relocation += (stub_sec->output_offset
                               + stub_sec->output_section->vma
                               + stub_sec->size - htab->sfpr->size
@@ -15780,26 +16522,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              addend = 0;
              reloc_dest = DEST_STUB;
 
-             if (((stub_entry->stub_type == ppc_stub_plt_call
-                   && ALWAYS_EMIT_R2SAVE)
-                  || stub_entry->stub_type == ppc_stub_plt_call_r2save
-                  || stub_entry->stub_type == ppc_stub_plt_call_both)
-                 && !(h != NULL
-                      && is_tls_get_addr (&h->elf, htab)
-                      && htab->params->tls_get_addr_opt)
-                 && rel + 1 < relend
-                 && rel[1].r_offset == rel->r_offset + 4
-                 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
-               relocation += 4;
-             else if ((stub_entry->stub_type == ppc_stub_long_branch_both
-                       || stub_entry->stub_type == ppc_stub_plt_branch_both
-                       || stub_entry->stub_type == ppc_stub_plt_call_both)
-                      && r_type == R_PPC64_REL24_NOTOC)
-               relocation += 4;
+             if (((stub_entry->type.r2save
+                   && (r_type == R_PPC64_REL24_NOTOC
+                       || r_type == R_PPC64_REL24_P9NOTOC))
+                  || ((stub_entry->type.main == ppc_stub_plt_call
+                       && (ALWAYS_EMIT_R2SAVE || stub_entry->type.r2save))
+                      && rel + 1 < relend
+                      && rel[1].r_offset == rel->r_offset + 4
+                      && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE))
+                 && !(stub_entry->type.main == ppc_stub_plt_call
+                      && htab->params->tls_get_addr_opt
+                      && h != NULL
+                      && is_tls_get_addr (&h->elf, htab)))
+               {
+                 /* Skip over the r2 store at the start of the stub.  */
+                 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))
+             if ((r_type == R_PPC64_REL24_NOTOC
+                  || r_type == R_PPC64_REL24_P9NOTOC)
+                 && stub_entry->type.main == ppc_stub_plt_call
+                 && stub_entry->type.sub >= ppc_stub_notoc)
                htab->notoc_plt = 1;
            }
 
@@ -15834,9 +16577,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   && h->elf.root.type == bfd_link_hash_undefweak
                   && h->elf.dynindx == -1
                   && (r_type == R_PPC64_REL24
-                      || r_type == R_PPC64_REL24_NOTOC)
+                      || r_type == R_PPC64_REL24_NOTOC
+                      || r_type == R_PPC64_REL24_P9NOTOC)
                   && relocation == 0
-                  && addend == 0)
+                  && addend == 0
+                  && offset_in_range (input_section, rel->r_offset, 4))
            {
              bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
              goto copy_reloc;
@@ -15844,9 +16589,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_GOT16_DS:
+         if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+             || (bfd_link_pic (info)
+                 && sec == bfd_abs_section_ptr)
+             || !htab->do_toc_opt)
+           break;
          from = TOCstart + htab->sec_info[input_section->id].toc_off;
          if (relocation + addend - from + 0x8000 < 0x10000
-             && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+             && sec != NULL
+             && sec->output_section != NULL
+             && !discarded_section (sec)
+             && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
              if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
@@ -15861,19 +16615,30 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_GOT16_LO_DS:
        case R_PPC64_GOT16_HA:
+         if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+             || (bfd_link_pic (info)
+                 && sec == bfd_abs_section_ptr)
+             || !htab->do_toc_opt)
+           break;
          from = TOCstart + htab->sec_info[input_section->id].toc_off;
          if (relocation + addend - from + 0x80008000ULL < 0x100000000ULL
-             && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+             && sec != NULL
+             && sec->output_section != NULL
+             && !discarded_section (sec)
+             && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
-             if ((insn & (0x3fu << 26 | 0x3)) == 58u << 26 /* ld */)
+             if (r_type == R_PPC64_GOT16_LO_DS
+                 && (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 */)
+             else if (r_type == R_PPC64_GOT16_HA
+                      && (insn & (0x3fu << 26)) == 15u << 26 /* addis */)
                {
                  r_type = R_PPC64_TOC16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -15882,32 +16647,45 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_GOT_PCREL34:
+         if ((h ? h->elf.type : ELF_ST_TYPE (sym->st_info)) == STT_GNU_IFUNC
+             || (bfd_link_pic (info)
+                 && sec == bfd_abs_section_ptr)
+             || !htab->do_toc_opt)
+           break;
          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;
+         if (!(relocation - from + (1ULL << 33) < 1ULL << 34
+               && sec != NULL
+               && sec->output_section != NULL
+               && !discarded_section (sec)
+               && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+               && offset_in_range (input_section, rel->r_offset, 8)))
+           break;
+
+         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 */))
+           break;
+
+         /* 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);
+         /* Fall through.  */
 
        case R_PPC64_PCREL34:
-         if (SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+         if (!htab->params->no_pcrel_opt
+             && rel + 1 < relend
+             && rel[1].r_offset == rel->r_offset
+             && rel[1].r_info == ELF64_R_INFO (0, R_PPC64_PCREL_OPT)
+             && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              offset = rel->r_offset;
              pinsn = bfd_get_32 (input_bfd, contents + offset);
@@ -15917,43 +16695,37 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   == ((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 (offset_in_range (input_section, off2, 4))
                    {
-                     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 (!offset_in_range (input_section, off2, 8))
+                           break;
+                         pinsn2 |= bfd_get_32 (input_bfd,
+                                               contents + off2 + 4);
+                       }
+                     if (xlate_pcrel_opt (&pinsn, &pinsn2, &addend_off))
                        {
-                         uint64_t pinsn2;
-                         bfd_signed_vma addend_off;
-                         pinsn2 = bfd_get_32 (input_bfd, contents + off2);
-                         pinsn2 <<= 32;
+                         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)
-                           {
-                             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);
-                           }
+                           bfd_put_32 (input_bfd, pinsn2,
+                                       contents + off2 + 4);
                        }
                    }
                }
@@ -15971,7 +16743,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                              input_bfd, ppc64_elf_howto_table[r_type]->name);
 
          bfd_set_error (bfd_error_bad_value);
-         ret = FALSE;
+         ret = false;
          goto copy_reloc;
 
        case R_PPC64_NONE:
@@ -15993,7 +16765,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:
+       case R_PPC64_GOT_TLSGD_PCREL34:
          tls_type = TLS_TLS | TLS_GD;
          goto dogot;
 
@@ -16001,7 +16773,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:
+       case R_PPC64_GOT_TLSLD_PCREL34:
          tls_type = TLS_TLS | TLS_LD;
          goto dogot;
 
@@ -16009,7 +16781,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:
+       case R_PPC64_GOT_TPREL_PCREL34:
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogot;
 
@@ -16017,7 +16789,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:
+       case R_PPC64_GOT_DTPREL_PCREL34:
          tls_type = TLS_TLS | TLS_DTPREL;
          goto dogot;
 
@@ -16039,7 +16811,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            struct got_entry *ent;
 
            if (tls_type == (TLS_TLS | TLS_LD)
-               && SYMBOL_REFERENCES_LOCAL (info, &h->elf))
+               && (h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
              ent = ppc64_tlsld_got (input_bfd);
            else
              {
@@ -16057,7 +16829,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    else
                      {
                        indx = h->elf.dynindx;
-                       unresolved_reloc = FALSE;
+                       unresolved_reloc = false;
                      }
                    ent = h->elf.got.glist;
                  }
@@ -16096,7 +16868,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                   the case of TLSLD where we'll use one entry per
                   module.  */
                asection *relgot;
-               bfd_boolean ifunc;
+               bool ifunc;
 
                *offp = off | 1;
                relgot = NULL;
@@ -16106,10 +16878,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (ifunc)
                  {
                    relgot = htab->elf.irelplt;
-                   if (indx == 0)
-                     htab->local_ifunc_resolver = 1;
-                   else if (is_static_defined (&h->elf))
-                     htab->maybe_local_ifunc_resolver = 1;
+                   if (indx == 0 || is_static_defined (&h->elf))
+                     htab->elf.ifunc_resolvers = true;
                  }
                else if (indx != 0
                         || (bfd_link_pic (info)
@@ -16117,7 +16887,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                 || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf))
                             && !(tls_type != 0
                                  && bfd_link_executable (info)
-                                 && SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
+                                 && (h == NULL
+                                     || SYMBOL_REFERENCES_LOCAL (info,
+                                                                 &h->elf)))
+                            && (h != NULL
+                                ? !bfd_is_abs_symbol (&h->elf.root)
+                                : sym->st_shndx != SHN_ABS)))
+
                  relgot = ppc64_elf_tdata (ent->owner)->relgot;
                if (relgot != NULL)
                  {
@@ -16173,10 +16949,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                              outrel.r_addend -= htab->elf.tls_sec->vma;
                          }
                      }
-                   loc = relgot->contents;
-                   loc += (relgot->reloc_count++
-                           * sizeof (Elf64_External_Rela));
-                   bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+                   if (!(info->enable_dt_relr
+                         && ELF64_R_TYPE (outrel.r_info) == R_PPC64_RELATIVE))
+                     {
+                       loc = relgot->contents;
+                       loc += (relgot->reloc_count++
+                               * sizeof (Elf64_External_Rela));
+                       bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+                     }
                  }
 
                /* Init the .got section contents here if we're not
@@ -16216,10 +16996,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            relocation = got->output_section->vma + got->output_offset + 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))
+                 || r_type == R_PPC64_GOT_TLSGD_PCREL34
+                 || r_type == R_PPC64_GOT_TLSLD_PCREL34
+                 || r_type == R_PPC64_GOT_TPREL_PCREL34
+                 || r_type == R_PPC64_GOT_DTPREL_PCREL34))
              addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
          }
          break;
@@ -16238,7 +17018,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLTCALL_NOTOC:
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
-         unresolved_reloc = TRUE;
+         unresolved_reloc = true;
          {
            struct plt_entry **plt_list = NULL;
            if (h != NULL)
@@ -16261,9 +17041,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      bfd_vma got;
 
                      plt = htab->elf.splt;
-                     if (!htab->elf.dynamic_sections_created
-                         || h == NULL
-                         || h->elf.dynindx == -1)
+                     if (use_local_plt (info, elf_hash_entry (h)))
                        {
                          if (h != NULL
                              ? h->elf.type == STT_GNU_IFUNC
@@ -16285,7 +17063,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          relocation -= got;
                        }
                      addend = 0;
-                     unresolved_reloc = FALSE;
+                     unresolved_reloc = false;
                      break;
                    }
              }
@@ -16302,7 +17080,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          else if (sec != NULL && sec->id < htab->sec_info_arr_size)
            relocation += htab->sec_info[sec->id].toc_off;
          else
-           unresolved_reloc = TRUE;
+           unresolved_reloc = true;
+         if (unresolved_reloc
+             || (!is_opd
+                 && h != NULL
+                 && !SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
+           info->callbacks->einfo
+             /* xgettext:c-format */
+             (_("%H: %s against %pT is not supported\n"),
+              input_bfd, input_section, rel->r_offset,
+              ppc64_elf_howto_table[r_type]->name, sym_name);
          goto dodyn;
 
          /* TOC16 relocs.  We want the offset relative to the TOC base,
@@ -16351,6 +17138,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
        case R_PPC64_REL24_NOTOC:
+       case R_PPC64_REL24_P9NOTOC:
        case R_PPC64_PCREL34:
        case R_PPC64_PCREL28:
          break;
@@ -16367,10 +17155,10 @@ 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)
+             && h->elf.dynindx == -1
+             && offset_in_range (input_section, rel->r_offset - d_offset, 4))
            {
              /* Make this relocation against an undefined weak symbol
                 resolve to zero.  This is really just a tweak, since
@@ -16384,6 +17172,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                bfd_put_32 (input_bfd, insn, p);
              break;
            }
+         /* Fall through.  */
+
+       case R_PPC64_TPREL34:
          if (htab->elf.tls_sec != NULL)
            addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          /* The TPREL16 relocs shouldn't really be used in shared
@@ -16473,14 +17264,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          if (bfd_link_pic (info)
              ? ((h == NULL
-                 || h->dyn_relocs != NULL)
+                 || h->elf.dyn_relocs != NULL)
                 && ((h != NULL && pc_dynrelocs (h))
                     || must_be_dyn_reloc (info, r_type)))
              : (h != NULL
-                ? h->dyn_relocs != NULL
+                ? h->elf.dyn_relocs != NULL
                 : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
            {
-             bfd_boolean skip, relocate;
+             bool skip, relocate;
              asection *sreloc;
              bfd_vma out_off;
              long indx = 0;
@@ -16489,15 +17280,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 are copied into the output file to be resolved at run
                 time.  */
 
-             skip = FALSE;
-             relocate = FALSE;
+             skip = false;
+             relocate = false;
 
              out_off = _bfd_elf_section_offset (output_bfd, info,
                                                 input_section, rel->r_offset);
              if (out_off == (bfd_vma) -1)
-               skip = TRUE;
+               skip = true;
              else if (out_off == (bfd_vma) -2)
-               skip = TRUE, relocate = TRUE;
+               skip = true, relocate = true;
              out_off += (input_section->output_section->vma
                          + input_section->output_offset);
              outrel.r_offset = out_off;
@@ -16516,7 +17307,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
+             else if (h != NULL
+                      && !SYMBOL_REFERENCES_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                {
@@ -16544,7 +17336,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             bug in binutils handling of weak syms.)
                             In these cases we won't use the opd
                             entry in this lib.  */
-                         unresolved_reloc = FALSE;
+                         unresolved_reloc = false;
                        }
                      if (!is_opd
                          && r_type == R_PPC64_ADDR64
@@ -16560,7 +17352,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             Prelink also wants simple and consistent rules
                             for relocs.  This make all RELATIVE relocs have
                             *r_offset equal to r_addend.  */
-                         relocate = TRUE;
+                         relocate = true;
                        }
                    }
                  else
@@ -16576,14 +17368,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
                             sym_name);
-                         ret = FALSE;
+                         ret = false;
                        }
                      else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
                          bfd_set_error (bfd_error_bad_value);
-                         return FALSE;
+                         return false;
                        }
                      else
                        {
@@ -16632,26 +17424,31 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    }
                }
 
-             sreloc = elf_section_data (input_section)->sreloc;
-             if (h != NULL
-                 ? h->elf.type == STT_GNU_IFUNC
-                 : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+             if (!(info->enable_dt_relr
+                   && ELF64_R_TYPE (outrel.r_info) == R_PPC64_RELATIVE
+                   && rel->r_offset % 2 == 0
+                   && input_section->alignment_power != 0
+                   && ELF64_R_TYPE (orig_rel.r_info) != R_PPC64_UADDR64))
                {
-                 sreloc = htab->elf.irelplt;
-                 if (indx == 0)
-                   htab->local_ifunc_resolver = 1;
-                 else if (is_static_defined (&h->elf))
-                   htab->maybe_local_ifunc_resolver = 1;
+                 sreloc = elf_section_data (input_section)->sreloc;
+                 if (h != NULL
+                     ? h->elf.type == STT_GNU_IFUNC
+                     : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   {
+                     sreloc = htab->elf.irelplt;
+                     if (indx == 0 || is_static_defined (&h->elf))
+                       htab->elf.ifunc_resolvers = true;
+                   }
+                 if (sreloc == NULL)
+                   abort ();
+
+                 if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
+                     >= sreloc->size)
+                   abort ();
+                 loc = sreloc->contents;
+                 loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
+                 bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
                }
-             if (sreloc == NULL)
-               abort ();
-
-             if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
-                 >= sreloc->size)
-               abort ();
-             loc = sreloc->contents;
-             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)))
@@ -16663,7 +17460,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                     input_bfd,
                     ppc64_elf_howto_table[ELF64_R_TYPE (outrel.r_info)]->name,
                     sym_name);
-                 warned_dynamic = TRUE;
+                 warned_dynamic = true;
                }
 
              /* If this reloc is against an external symbol, it will
@@ -16672,7 +17469,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 that the section contents are a known value.  */
              if (!relocate)
                {
-                 unresolved_reloc = FALSE;
+                 unresolved_reloc = false;
                  /* The value chosen here is quite arbitrary as ld.so
                     ignores section contents except for the special
                     case of .opd where the contents might be accessed
@@ -16718,7 +17515,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
          bfd_set_error (bfd_error_invalid_operation);
-         ret = FALSE;
+         ret = false;
          goto copy_reloc;
        }
 
@@ -16750,7 +17547,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            htab->notoc_plt = 1;
          /* Fall through.  */
        case R_PPC64_PLTCALL:
-         if (unresolved_reloc)
+         if (unresolved_reloc
+             && offset_in_range (input_section, rel->r_offset,
+                                 r_type == R_PPC64_PLTCALL ? 8 : 4))
            {
              /* No plt entry.  Make this into a direct call.  */
              bfd_byte *p = contents + rel->r_offset;
@@ -16768,7 +17567,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLTSEQ:
          if (unresolved_reloc)
            {
-             unresolved_reloc = FALSE;
+             unresolved_reloc = false;
              goto nop_it;
            }
          break;
@@ -16778,12 +17577,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            htab->notoc_plt = 1;
          /* Fall through.  */
        case R_PPC64_PLT_PCREL34:
-         if (unresolved_reloc)
+         if (unresolved_reloc
+             && offset_in_range (input_section, rel->r_offset, 8))
            {
              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;
+             unresolved_reloc = false;
              goto copy_reloc;
            }
          break;
@@ -16791,7 +17591,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLT16_HA:
          if (unresolved_reloc)
            {
-             unresolved_reloc = FALSE;
+             unresolved_reloc = false;
              goto nop_it;
            }
          /* Fall through.  */
@@ -16802,13 +17602,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT16_HA:
        case R_PPC64_TOC16_HA:
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
-             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn
+             && !(bfd_link_pic (info)
+                  && (h != NULL
+                      ? bfd_is_abs_symbol (&h->elf.root)
+                      : sec == bfd_abs_section_ptr)))
            {
              bfd_byte *p;
            nop_it:
-             p = contents + (rel->r_offset & ~3);
-             bfd_put_32 (input_bfd, NOP, p);
-             goto copy_reloc;
+             if (offset_in_range (input_section, rel->r_offset & ~3, 4))
+               {
+                 p = contents + (rel->r_offset & ~3);
+                 bfd_put_32 (input_bfd, NOP, p);
+                 goto copy_reloc;
+               }
            }
          break;
 
@@ -16816,7 +17623,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLT16_LO_DS:
          if (unresolved_reloc)
            {
-             unresolved_reloc = FALSE;
+             unresolved_reloc = false;
              goto nop_it;
            }
          /* Fall through.  */
@@ -16829,7 +17636,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_LO_DS:
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
-             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn
+             && !(bfd_link_pic (info)
+                  && (h != NULL
+                      ? bfd_is_abs_symbol (&h->elf.root)
+                      : sec == bfd_abs_section_ptr))
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
@@ -16849,28 +17661,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_TPREL16_HA:
-         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+         if (htab->do_tls_opt
+             && relocation + addend + 0x8000 < 0x10000
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
-             insn = bfd_get_32 (input_bfd, p);
-             if ((insn & ((0x3fu << 26) | 0x1f << 16))
-                 != ((15u << 26) | (13 << 16)) /* addis rt,13,imm */)
-               /* xgettext:c-format */
-               info->callbacks->minfo
-                 (_("%H: warning: %s unexpected insn %#x.\n"),
-                  input_bfd, input_section, rel->r_offset,
-                  ppc64_elf_howto_table[r_type]->name, insn);
-             else
-               {
-                 bfd_put_32 (input_bfd, NOP, p);
-                 goto copy_reloc;
-               }
+             bfd_put_32 (input_bfd, NOP, p);
+             goto copy_reloc;
            }
          break;
 
        case R_PPC64_TPREL16_LO:
        case R_PPC64_TPREL16_LO_DS:
-         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+         if (htab->do_tls_opt
+             && relocation + addend + 0x8000 < 0x10000
+             && offset_in_range (input_section, rel->r_offset & ~3, 4))
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
@@ -16954,6 +17759,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TPREL16_LO_DS:
        case R_PPC64_DTPREL16_DS:
        case R_PPC64_DTPREL16_LO_DS:
+         if (!offset_in_range (input_section, rel->r_offset & ~3, 4))
+           break;
          insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
          mask = 3;
          /* If this reloc is against an lq, lxv, or stxv insn, then
@@ -16977,7 +17784,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                 ppc64_elf_howto_table[r_type]->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
-             ret = FALSE;
+             ret = false;
              goto copy_reloc;
            }
          break;
@@ -16999,7 +17806,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             input_bfd, input_section, rel->r_offset,
             howto->name,
             h->elf.root.root.string);
-         ret = FALSE;
+         ret = false;
        }
 
       /* 16-bit fields in insns mostly have signed values, but a
@@ -17007,7 +17814,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
         have different reloc types.  */
       if (howto->complain_on_overflow != complain_overflow_dont
          && howto->dst_mask == 0xffff
-         && (input_section->flags & SEC_CODE) != 0)
+         && (input_section->flags & SEC_CODE) != 0
+         && offset_in_range (input_section, rel->r_offset & ~3, 4))
        {
          enum complain_overflow complain = complain_overflow_signed;
 
@@ -17041,15 +17849,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        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_GOT_TLSGD_PCREL34:
+       case R_PPC64_GOT_TLSLD_PCREL34:
+       case R_PPC64_GOT_TPREL_PCREL34:
+       case R_PPC64_GOT_DTPREL_PCREL34:
        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)
+         if (!offset_in_range (input_section, rel->r_offset, 8))
            r = bfd_reloc_outofrange;
          else
            {
@@ -17078,7 +17886,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_REL16DX_HA:
-         if (rel->r_offset + 4 > input_section->size)
+         if (!offset_in_range (input_section, rel->r_offset, 4))
            r = bfd_reloc_outofrange;
          else
            {
@@ -17130,11 +17938,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                           && (h->elf.root.type == bfd_link_hash_undefweak
                               || h->elf.root.type == bfd_link_hash_undefined)
                           && is_branch_reloc (r_type))))
-               info->callbacks->reloc_overflow (info, &h->elf.root,
-                                                sym_name, reloc_name,
-                                                orig_rel.r_addend,
-                                                input_bfd, input_section,
-                                                rel->r_offset);
+               info->callbacks->reloc_overflow
+                 (info, (struct bfd_link_hash_entry *) h, sym_name,
+                  reloc_name, orig_rel.r_addend, input_bfd, input_section,
+                  rel->r_offset);
            }
          else
            {
@@ -17143,10 +17950,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                (_("%H: %s against `%pT': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
                 reloc_name, sym_name, (int) r);
-             ret = FALSE;
+             ret = false;
            }
-         if (more_info != NULL)
-           free (more_info);
+         free (more_info);
        }
     copy_reloc:
       if (wrel != rel)
@@ -17186,7 +17992,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL);
       ppc64_elf_tdata (input_bfd)->opd.relocs = rel;
       if (rel == NULL)
-       return FALSE;
+       return false;
       memcpy (rel, relocs, amt);
     }
   return ret;
@@ -17227,7 +18033,7 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h,
@@ -17238,7 +18044,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   if (!htab->opd_abi && !h->def_regular)
     for (ent = h->plt.plist; ent != NULL; ent = ent->next)
@@ -17290,7 +18096,7 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Used to decide how to sort relocs in an optimal manner for the
@@ -17323,7 +18129,7 @@ ppc64_elf_reloc_type_class (const struct bfd_link_info *info,
 
 /* Finish up the dynamic sections.  */
 
-static bfd_boolean
+static bool
 ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                   struct bfd_link_info *info)
 {
@@ -17333,7 +18139,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   dynobj = htab->elf.dynobj;
   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
@@ -17406,11 +18212,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
              break;
 
            case DT_TEXTREL:
-             if (htab->local_ifunc_resolver)
-               info->callbacks->einfo
-                 (_("%X%P: text relocations and GNU indirect "
-                    "functions will result in a segfault at runtime\n"));
-             else if (htab->maybe_local_ifunc_resolver)
+             if (htab->elf.ifunc_resolvers)
                info->callbacks->einfo
                  (_("%P: warning: text relocations and GNU indirect "
                     "functions may result in a segfault at runtime\n"));
@@ -17452,7 +18254,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                       elf_section_data (htab->brlt)->rela.hdr,
                                       elf_section_data (htab->brlt)->relocs,
                                       NULL))
-    return FALSE;
+    return false;
 
   if (htab->glink != NULL
       && htab->glink->reloc_count != 0
@@ -17461,7 +18263,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                       elf_section_data (htab->glink)->rela.hdr,
                                       elf_section_data (htab->glink)->relocs,
                                       NULL))
-    return FALSE;
+    return false;
 
 
   if (htab->glink_eh_frame != NULL
@@ -17470,7 +18272,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
       && !_bfd_elf_write_section_eh_frame (output_bfd, info,
                                           htab->glink_eh_frame,
                                           htab->glink_eh_frame->contents))
-    return FALSE;
+    return false;
 
   /* We need to handle writing out multiple GOT sections ourselves,
      since we didn't add them to DYNOBJ.  We know dynobj is the first
@@ -17489,7 +18291,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
          && !bfd_set_section_contents (output_bfd, s->output_section,
                                        s->contents, s->output_offset,
                                        s->size))
-       return FALSE;
+       return false;
       s = ppc64_elf_tdata (dynobj)->relgot;
       if (s != NULL
          && s->size != 0
@@ -17497,10 +18299,10 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
          && !bfd_set_section_contents (output_bfd, s->output_section,
                                        s->contents, s->output_offset,
                                        s->size))
-       return FALSE;
+       return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 #include "elf64-target.h"
@@ -17508,7 +18310,9 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 /* FreeBSD support */
 
 #undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM powerpc_elf64_fbsd_le_vec
 #undef  TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elf64-powerpcle-freebsd"
 
 #undef  TARGET_BIG_SYM
 #define TARGET_BIG_SYM powerpc_elf64_fbsd_vec