ubsan: som.c undefined shift in som_set_reloc_info
[binutils-gdb.git] / bfd / elf32-ppc.c
index e0456b886fc8979b1d958c90dfd1961fc1606b84..1f77e18133addee44bc5df8022a552501183f024 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright (C) 1994-2018 Free Software Foundation, Inc.
+   Copyright (C) 1994-2022 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
    Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
    Boston, MA 02110-1301, USA.  */
 
-
-/* This file is based on a preliminary PowerPC ELF ABI.  The
-   information may not match the final PowerPC ELF ABI.  It includes
-   suggestions from the in-progress Embedded PowerPC ABI, and that
-   information may also not match.  */
+/* 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>
@@ -37,6 +36,9 @@
 #include "dwarf2.h"
 #include "opcode/ppc.h"
 
+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
 typedef enum split16_format_type
 {
   split16a_type = 0,
@@ -186,1199 +188,384 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
    + (SYM)->root.u.def.section->output_offset          \
    + (SYM)->root.u.def.value)
 \f
+/* Relocation HOWTO's.  */
+/* Like other ELF RELA targets that don't apply multiple
+   field-altering relocations to the same localation, src_mask is
+   always zero and pcrel_offset is the same as pc_relative.
+   PowerPC can always use a zero bitpos, even when the field is not at
+   the LSB.  For example, a REL24 could use rightshift=2, bisize=24
+   and bitpos=2 which matches the ABI description, or as we do here,
+   rightshift=0, bitsize=26 and bitpos=0.  */
+#define HOW(type, size, bitsize, mask, rightshift, pc_relative, \
+           complain, special_func)                             \
+  HOWTO (type, rightshift, size, bitsize, pc_relative, 0,      \
+        complain_overflow_ ## complain, special_func,          \
+        #type, false, 0, mask, pc_relative)
+
 static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
 
 static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
-  HOWTO (R_PPC_NONE,           /* type */
-        0,                     /* rightshift */
-        3,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_NONE",          /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_NONE, 0, 0, 0, 0, false, dont,
+       bfd_elf_generic_reloc),
 
   /* A standard 32 bit relocation.  */
-  HOWTO (R_PPC_ADDR32,         /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR32",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR32, 4, 32, 0xffffffff, 0, false, dont,
+       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.  */
-  HOWTO (R_PPC_ADDR24,         /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        26,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR24",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR24, 4, 26, 0x3fffffc, 0, false, signed,
+       bfd_elf_generic_reloc),
 
   /* A standard 16 bit relocation.  */
-  HOWTO (R_PPC_ADDR16,         /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR16",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR16, 2, 16, 0xffff, 0, false, bitfield,
+       bfd_elf_generic_reloc),
 
   /* A 16 bit relocation without overflow.  */
-  HOWTO (R_PPC_ADDR16_LO,      /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR16_LO",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR16_LO, 2, 16, 0xffff, 0, false, dont,
+       bfd_elf_generic_reloc),
 
   /* The high order 16 bits of an address.  */
-  HOWTO (R_PPC_ADDR16_HI,      /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR16_HI",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR16_HI, 2, 16, 0xffff, 16, false, dont,
+       bfd_elf_generic_reloc),
 
   /* The high order 16 bits of an address, plus 1 if the contents of
      the low 16 bits, treated as a signed number, is negative.  */
-  HOWTO (R_PPC_ADDR16_HA,      /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
-        "R_PPC_ADDR16_HA",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_addr16_ha_reloc),
 
   /* An absolute 16 bit branch; the lower two bits must be zero.
      FIXME: we don't check that, we just clear them.  */
-  HOWTO (R_PPC_ADDR14,         /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR14",        /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR14, 4, 16, 0xfffc, 0, false, signed,
+       bfd_elf_generic_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.  */
-  HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR14_BRTAKEN",/* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR14_BRTAKEN, 4, 16, 0xfffc, 0, false, signed,
+       bfd_elf_generic_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.  */
-  HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_ADDR14_BRNTAKEN",/* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_ADDR14_BRNTAKEN, 4, 16, 0xfffc, 0, false, signed,
+       bfd_elf_generic_reloc),
 
   /* A relative 26 bit branch; the lower two bits must be zero.  */
-  HOWTO (R_PPC_REL24,          /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        26,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL24",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL24, 4, 26, 0x3fffffc, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* A relative 16 bit branch; the lower two bits must be zero.  */
-  HOWTO (R_PPC_REL14,          /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL14",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL14, 4, 16, 0xfffc, 0, true, signed,
+       bfd_elf_generic_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.  */
-  HOWTO (R_PPC_REL14_BRTAKEN,  /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL14_BRTAKEN", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL14_BRTAKEN, 4, 16, 0xfffc, 0, true, signed,
+       bfd_elf_generic_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.  */
-  HOWTO (R_PPC_REL14_BRNTAKEN, /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL14_BRNTAKEN",/* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL14_BRNTAKEN, 4, 16, 0xfffc, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* Like R_PPC_ADDR16, but referring to the GOT table entry for the
      symbol.  */
-  HOWTO (R_PPC_GOT16,          /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT16",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_PPC_GOT16_LO,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT16_LO",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_PPC_GOT16_HI,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT16_HI",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                 /* pcrel_offset */
+  HOW (R_PPC_GOT16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for
      the symbol.  */
-  HOWTO (R_PPC_GOT16_HA,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT16_HA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_REL24, but referring to the procedure linkage table
      entry for the symbol.  */
-  HOWTO (R_PPC_PLTREL24,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        26,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLTREL24",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_PLTREL24, 4, 26, 0x3fffffc, 0, true, signed,
+       ppc_elf_unhandled_reloc),
 
   /* This is used only by the dynamic linker.  The symbol should exist
      both in the object being run and in some shared library.  The
      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.  */
-  HOWTO (R_PPC_COPY,           /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_COPY",          /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_COPY, 4, 32, 0, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR32, but used when setting global offset table
      entries.  */
-  HOWTO (R_PPC_GLOB_DAT,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GLOB_DAT",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GLOB_DAT, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Marks a procedure linkage table entry for a symbol.  */
-  HOWTO (R_PPC_JMP_SLOT,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_JMP_SLOT",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_JMP_SLOT, 4, 32, 0, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Used only by the dynamic linker.  When the object is run, this
      longword is set to the load address of the object, plus the
      addend.  */
-  HOWTO (R_PPC_RELATIVE,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_RELATIVE",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_RELATIVE, 4, 32, 0xffffffff, 0, false, dont,
+       bfd_elf_generic_reloc),
 
   /* Like R_PPC_REL24, but uses the value of the symbol within the
      object rather than the final value.  Normally used for
      _GLOBAL_OFFSET_TABLE_.  */
-  HOWTO (R_PPC_LOCAL24PC,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        26,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_LOCAL24PC",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_LOCAL24PC, 4, 26, 0x3fffffc, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* Like R_PPC_ADDR32, but may be unaligned.  */
-  HOWTO (R_PPC_UADDR32,                /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_UADDR32",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_UADDR32, 4, 32, 0xffffffff, 0, false, dont,
+       bfd_elf_generic_reloc),
 
   /* Like R_PPC_ADDR16, but may be unaligned.  */
-  HOWTO (R_PPC_UADDR16,                /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_UADDR16",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_UADDR16, 2, 16, 0xffff, 0, false, bitfield,
+       bfd_elf_generic_reloc),
 
   /* 32-bit PC relative */
-  HOWTO (R_PPC_REL32,          /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL32",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL32, 4, 32, 0xffffffff, 0, true, dont,
+       bfd_elf_generic_reloc),
 
   /* 32-bit relocation to the symbol's procedure linkage table.
      FIXME: not supported.  */
-  HOWTO (R_PPC_PLT32,          /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLT32",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_PLT32, 4, 32, 0, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* 32-bit PC relative relocation to the symbol's procedure linkage table.
      FIXME: not supported.  */
-  HOWTO (R_PPC_PLTREL32,       /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLTREL32",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_PLTREL32, 4, 32, 0, 0, true, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for
      the symbol.  */
-  HOWTO (R_PPC_PLT16_LO,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLT16_LO",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_PLT16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for
      the symbol.  */
-  HOWTO (R_PPC_PLT16_HI,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLT16_HI",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                 /* pcrel_offset */
+  HOW (R_PPC_PLT16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
      the symbol.  */
-  HOWTO (R_PPC_PLT16_HA,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_PLT16_HA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_PLT16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with
      small data items.  */
-  HOWTO (R_PPC_SDAREL16,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_SDAREL16",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_SDAREL16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* 16-bit section relative relocation.  */
-  HOWTO (R_PPC_SECTOFF,                /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_SECTOFF",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_SECTOFF, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* 16-bit lower half section relative relocation.  */
-  HOWTO (R_PPC_SECTOFF_LO,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_SECTOFF_LO",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_SECTOFF_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* 16-bit upper half section relative relocation.  */
-  HOWTO (R_PPC_SECTOFF_HI,     /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_SECTOFF_HI",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                 /* pcrel_offset */
+  HOW (R_PPC_SECTOFF_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* 16-bit upper half adjusted section relative relocation.  */
-  HOWTO (R_PPC_SECTOFF_HA,     /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_SECTOFF_HA",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_SECTOFF_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Marker relocs for TLS.  */
-  HOWTO (R_PPC_TLS,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_TLS",           /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_PPC_TLSGD,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_TLSGD",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_PPC_TLSLD,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_TLSLD",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TLS, 4, 32, 0, 0, false, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC_TLSGD, 4, 32, 0, 0, false, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC_TLSLD, 4, 32, 0, 0, false, dont,
+       bfd_elf_generic_reloc),
+
+  /* Marker relocs on inline plt call instructions.  */
+  HOW (R_PPC_PLTSEQ, 4, 32, 0, 0, false, dont,
+       bfd_elf_generic_reloc),
+
+  HOW (R_PPC_PLTCALL, 4, 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.  */
-  HOWTO (R_PPC_DTPMOD32,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPMOD32",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPMOD32, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_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.  */
-  HOWTO (R_PPC_DTPREL32,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPREL32",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPREL32, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* A 16 bit dtprel reloc.  */
-  HOWTO (R_PPC_DTPREL16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPREL16",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPREL16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like DTPREL16, but no overflow.  */
-  HOWTO (R_PPC_DTPREL16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPREL16_LO",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPREL16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like DTPREL16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_DTPREL16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPREL16_HI",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPREL16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like DTPREL16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_DTPREL16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_DTPREL16_HA",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_DTPREL16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Computes a tp-relative displacement, the difference between the value of
      sym+add and the value of the thread pointer (r13).  */
-  HOWTO (R_PPC_TPREL32,
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TPREL32",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TPREL32, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* A 16 bit tprel reloc.  */
-  HOWTO (R_PPC_TPREL16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TPREL16",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TPREL16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like TPREL16, but no overflow.  */
-  HOWTO (R_PPC_TPREL16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TPREL16_LO",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TPREL16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like TPREL16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_TPREL16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TPREL16_HI",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TPREL16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like TPREL16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_TPREL16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TPREL16_HA",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TPREL16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_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.  */
-  HOWTO (R_PPC_GOT_TLSGD16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSGD16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSGD16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16, but no overflow.  */
-  HOWTO (R_PPC_GOT_TLSGD16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSGD16_LO", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSGD16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_GOT_TLSGD16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSGD16_HI", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSGD16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSGD16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_GOT_TLSGD16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSGD16_HA", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSGD16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_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.  */
-  HOWTO (R_PPC_GOT_TLSLD16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSLD16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSLD16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16, but no overflow.  */
-  HOWTO (R_PPC_GOT_TLSLD16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSLD16_LO", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSLD16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_GOT_TLSLD16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSLD16_HI", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSLD16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TLSLD16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_GOT_TLSLD16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TLSLD16_HA", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TLSLD16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
      the offset to the entry.  */
-  HOWTO (R_PPC_GOT_DTPREL16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_DTPREL16",  /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_DTPREL16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16, but no overflow.  */
-  HOWTO (R_PPC_GOT_DTPREL16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_DTPREL16_LO", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_DTPREL16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_GOT_DTPREL16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_DTPREL16_HI", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_DTPREL16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_DTPREL16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_GOT_DTPREL16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_DTPREL16_HA", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_DTPREL16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
      offset to the entry.  */
-  HOWTO (R_PPC_GOT_TPREL16,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TPREL16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TPREL16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16, but no overflow.  */
-  HOWTO (R_PPC_GOT_TPREL16_LO,
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TPREL16_LO", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TPREL16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16_LO, but next higher group of 16 bits.  */
-  HOWTO (R_PPC_GOT_TPREL16_HI,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TPREL16_HI", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TPREL16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Like GOT_TPREL16_HI, but adjust for low 16 bits.  */
-  HOWTO (R_PPC_GOT_TPREL16_HA,
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_GOT_TPREL16_HA", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GOT_TPREL16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The remaining relocs are from the Embedded ELF ABI, and are not
      in the SVR4 ELF ABI.  */
 
   /* 32 bit value resulting from the addend minus the symbol.  */
-  HOWTO (R_PPC_EMB_NADDR32,    /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_NADDR32",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_NADDR32, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* 16 bit value resulting from the addend minus the symbol.  */
-  HOWTO (R_PPC_EMB_NADDR16,    /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_NADDR16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_NADDR16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* 16 bit value resulting from the addend minus the symbol.  */
-  HOWTO (R_PPC_EMB_NADDR16_LO, /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_ADDR16_LO", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_NADDR16_LO, 2, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The high order 16 bits of the addend minus the symbol.  */
-  HOWTO (R_PPC_EMB_NADDR16_HI, /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_NADDR16_HI", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_NADDR16_HI, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The high order 16 bits of the result of the addend minus the address,
      plus 1 if the contents of the low 16 bits, treated as a signed number,
      is negative.  */
-  HOWTO (R_PPC_EMB_NADDR16_HA, /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_NADDR16_HA", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_NADDR16_HA, 2, 16, 0xffff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* 16 bit value resulting from allocating a 4 byte word to hold an
      address in the .sdata section, and returning the offset from
      _SDA_BASE_ for that relocation.  */
-  HOWTO (R_PPC_EMB_SDAI16,     /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_SDAI16",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_SDAI16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* 16 bit value resulting from allocating a 4 byte word to hold an
      address in the .sdata2 section, and returning the offset from
      _SDA2_BASE_ for that relocation.  */
-  HOWTO (R_PPC_EMB_SDA2I16,    /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_SDA2I16",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_SDA2I16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with
      small data items.  */
-  HOWTO (R_PPC_EMB_SDA2REL,    /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_SDA2REL",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_SDA2REL, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit
      signed offset from the appropriate base, and filling in the register
      field with the appropriate register (0, 2, or 13).  */
-  HOWTO (R_PPC_EMB_SDA21,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_SDA21",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_SDA21, 4, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Relocation not handled: R_PPC_EMB_MRKREF */
   /* Relocation not handled: R_PPC_EMB_RELSEC16 */
@@ -1390,441 +577,122 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling
      in the 16 bit signed offset from the appropriate base, and filling in the
      register field with the appropriate register (0, 2, or 13).  */
-  HOWTO (R_PPC_EMB_RELSDA,     /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_EMB_RELSDA",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_EMB_RELSDA, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* A relative 8 bit branch.  */
-  HOWTO (R_PPC_VLE_REL8,       /* type */
-        1,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_REL8",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_VLE_REL8, 2, 8, 0xff, 1, true, signed,
+       bfd_elf_generic_reloc),
 
   /* A relative 15 bit branch.  */
-  HOWTO (R_PPC_VLE_REL15,      /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        15,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        1,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_REL15",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xfffe,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_VLE_REL15, 4, 16, 0xfffe, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* A relative 24 bit branch.  */
-  HOWTO (R_PPC_VLE_REL24,      /* type */
-        1,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        24,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        1,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_REL24",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1fffffe,             /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_VLE_REL24, 4, 25, 0x1fffffe, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* The 16 LSBS in split16a format.  */
-  HOWTO (R_PPC_VLE_LO16A,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_LO16A",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_LO16A, 4, 16, 0x1f07ff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The 16 LSBS in split16d format.  */
-  HOWTO (R_PPC_VLE_LO16D,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_LO16D",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_LO16D, 4, 16, 0x3e007ff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 split16a format.  */
-  HOWTO (R_PPC_VLE_HI16A,      /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_HI16A",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_HI16A, 4, 16, 0x1f07ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 split16d format.  */
-  HOWTO (R_PPC_VLE_HI16D,      /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_HI16D",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_HI16D, 4, 16, 0x3e007ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 (High Adjusted) in split16a format.  */
-  HOWTO (R_PPC_VLE_HA16A,      /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_HA16A",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_HA16A, 4, 16, 0x1f07ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 (High Adjusted) in split16d format.  */
-  HOWTO (R_PPC_VLE_HA16D,      /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_HA16D",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_HA16D, 4, 16, 0x3e007ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
      instructions.  If the register base is 0 then the linker changes
      the e_add16i to an e_li instruction.  */
-  HOWTO (R_PPC_VLE_SDA21,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDA21",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDA21, 4, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 
   /* Like R_PPC_VLE_SDA21 but ignore overflow.  */
-  HOWTO (R_PPC_VLE_SDA21_LO,   /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDA21_LO",  /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDA21_LO, 4, 16, 0xffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_LO16A", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_LO16A, 4, 16, 0x1f07ff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_LO16D", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_LO16D, 4, 16, 0x3e007ff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_HI16A", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_HI16A, 4, 16, 0x1f07ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_HI16D", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_HI16D, 4, 16, 0x3e007ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_HA16A", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_HA16A, 4, 16, 0x1f07ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_VLE_SDAREL_HA16D", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x3e007ff,             /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_SDAREL_HA16D, 4, 16, 0x3e007ff, 16, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* e_li split20 format.  */
-  HOWTO (R_PPC_VLE_ADDR20,     /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        20,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_ADDR20",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
-
-  HOWTO (R_PPC_IRELATIVE,      /* type */
-        0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_IRELATIVE",     /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_VLE_ADDR20, 4, 20, 0x1f7fff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
+
+  HOW (R_PPC_IRELATIVE, 4, 32, 0xffffffff, 0, false, dont,
+       ppc_elf_unhandled_reloc),
 
   /* A 16 bit relative relocation.  */
-  HOWTO (R_PPC_REL16,          /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL16",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL16, 2, 16, 0xffff, 0, true, signed,
+       bfd_elf_generic_reloc),
 
   /* A 16 bit relative relocation without overflow.  */
-  HOWTO (R_PPC_REL16_LO,       /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL16_LO",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL16_LO, 2, 16, 0xffff, 0, true, dont,
+       bfd_elf_generic_reloc),
 
   /* The high order 16 bits of a relative address.  */
-  HOWTO (R_PPC_REL16_HI,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_REL16_HI",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL16_HI, 2, 16, 0xffff, 16, true, dont,
+       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.  */
-  HOWTO (R_PPC_REL16_HA,       /* type */
-        16,                    /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
-        "R_PPC_REL16_HA",      /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL16_HA, 2, 16, 0xffff, 16, true, dont,
+       ppc_elf_addr16_ha_reloc),
 
   /* Like R_PPC_REL16_HA but for split field in addpcis.  */
-  HOWTO (R_PPC_REL16DX_HA,     /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
-        "R_PPC_REL16DX_HA",    /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1fffc1,              /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+  HOW (R_PPC_REL16DX_HA, 4, 16, 0x1fffc1, 16, true, signed,
+       ppc_elf_addr16_ha_reloc),
 
   /* A split-field reloc for addpcis, non-relative (gas internal use only).  */
-  HOWTO (R_PPC_16DX_HA,                /* type */
-        16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
-        "R_PPC_16DX_HA",       /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0x1fffc1,              /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_16DX_HA, 4, 16, 0x1fffc1, 16, false, signed,
+       ppc_elf_addr16_ha_reloc),
 
   /* GNU extension to record C++ vtable hierarchy.  */
-  HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_PPC_GNU_VTINHERIT", /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GNU_VTINHERIT, 0, 0, 0, 0, false, dont,
+       NULL),
 
   /* GNU extension to record C++ vtable member usage.  */
-  HOWTO (R_PPC_GNU_VTENTRY,    /* type */
-        0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_dont, /* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_PPC_GNU_VTENTRY",   /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_GNU_VTENTRY, 0, 0, 0, 0, false, dont,
+       NULL),
 
   /* Phony reloc to handle AIX style TOC entries.  */
-  HOWTO (R_PPC_TOC16,          /* type */
-        0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
-        16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
-        0,                     /* bitpos */
-        complain_overflow_signed, /* complain_on_overflow */
-        ppc_elf_unhandled_reloc, /* special_function */
-        "R_PPC_TOC16",         /* name */
-        FALSE,                 /* partial_inplace */
-        0,                     /* src_mask */
-        0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+  HOW (R_PPC_TOC16, 2, 16, 0xffff, 0, false, signed,
+       ppc_elf_unhandled_reloc),
 };
 \f
 /* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */
@@ -2014,7 +882,7 @@ ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
-static bfd_boolean
+static bool
 ppc_elf_info_to_howto (bfd *abfd,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
@@ -2032,7 +900,7 @@ ppc_elf_info_to_howto (bfd *abfd,
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                          abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
   cache_ptr->howto = ppc_elf_howto_table[r_type];
@@ -2046,10 +914,10 @@ ppc_elf_info_to_howto (bfd *abfd,
                          abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
 
-      return FALSE;
+      return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs.  */
@@ -2090,7 +958,11 @@ ppc_elf_addr16_ha_reloc (bfd *abfd,
            + input_section->output_section->vma);
   value >>= 16;
 
-  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  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);
@@ -2116,10 +988,12 @@ ppc_elf_unhandled_reloc (bfd *abfd,
 
   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;
 }
@@ -2181,7 +1055,7 @@ struct ppc_elf_obj_tdata
 
 /* Override the generic function because we store some extras.  */
 
-static bfd_boolean
+static bool
 ppc_elf_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata),
@@ -2190,7 +1064,7 @@ ppc_elf_mkobject (bfd *abfd)
 
 /* When defaulting arch/mach, decode apuinfo to find a better match.  */
 
-bfd_boolean
+bool
 _bfd_elf_ppc_set_arch (bfd *abfd)
 {
   unsigned long mach = 0;
@@ -2211,7 +1085,9 @@ _bfd_elf_ppc_set_arch (bfd *abfd)
   if (mach == 0)
     {
       s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
-      if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+      if (s != NULL
+         && s->size >= 24
+         && bfd_malloc_and_get_section (abfd, s, &contents))
        {
          unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
          unsigned int i;
@@ -2263,17 +1139,17 @@ _bfd_elf_ppc_set_arch (bfd *abfd)
            break;
          }
     }
-  return TRUE;
+  return true;
 }
 
 /* Fix bad default arch selected for a 32 bit input bfd when the
    default is 64 bit.  Also select arch based on apuinfo.  */
 
-static bfd_boolean
+static bool
 ppc_elf_object_p (bfd *abfd)
 {
   if (!abfd->arch_info->the_default)
-    return TRUE;
+    return true;
 
   if (abfd->arch_info->bits_per_word == 64)
     {
@@ -2291,20 +1167,20 @@ ppc_elf_object_p (bfd *abfd)
 
 /* Function to set whether a module needs the -mrelocatable bit set.  */
 
-static bfd_boolean
+static bool
 ppc_elf_set_private_flags (bfd *abfd, flagword flags)
 {
   BFD_ASSERT (!elf_flags_init (abfd)
              || elf_elfheader (abfd)->e_flags == flags);
 
   elf_elfheader (abfd)->e_flags = flags;
-  elf_flags_init (abfd) = TRUE;
-  return TRUE;
+  elf_flags_init (abfd) = true;
+  return true;
 }
 
 /* Support for core dump NOTE sections.  */
 
-static bfd_boolean
+static bool
 ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   int offset;
@@ -2313,7 +1189,7 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   switch (note->descsz)
     {
     default:
-      return FALSE;
+      return false;
 
     case 268:          /* Linux/PPC.  */
       /* pr_cursig */
@@ -2334,13 +1210,13 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
                                          size, note->descpos + offset);
 }
 
-static bfd_boolean
+static bool
 ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
   switch (note->descsz)
     {
     default:
-      return FALSE;
+      return false;
 
     case 128:          /* Linux/PPC elf_prpsinfo.  */
       elf_tdata (abfd)->core->pid
@@ -2363,7 +1239,7 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
       command[n - 1] = '\0';
   }
 
-  return TRUE;
+  return true;
 }
 
 static char *
@@ -2376,13 +1252,24 @@ ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
 
     case NT_PRPSINFO:
       {
-       char data[128];
+       char data[128] ATTRIBUTE_NONSTRING;
        va_list ap;
 
        va_start (ap, note_type);
        memset (data, 0, sizeof (data));
        strncpy (data + 32, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_PUSH;
+       /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+          -Wstringop-truncation:
+          https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+        */
+       DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
        strncpy (data + 48, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_POP;
+#endif
        va_end (ap);
        return elfcore_write_note (abfd, buf, bufsiz,
                                   "CORE", note_type, data, sizeof (data));
@@ -2437,7 +1324,7 @@ ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED,
    is called when bfd_section_from_shdr finds a section with an unknown
    type.  */
 
-static bfd_boolean
+static bool
 ppc_elf_section_from_shdr (bfd *abfd,
                           Elf_Internal_Shdr *hdr,
                           const char *name,
@@ -2447,23 +1334,29 @@ ppc_elf_section_from_shdr (bfd *abfd,
   flagword flags;
 
   if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
-    return FALSE;
+    return false;
 
   newsect = hdr->bfd_section;
-  flags = bfd_get_section_flags (abfd, newsect);
+  flags = 0;
   if (hdr->sh_flags & SHF_EXCLUDE)
     flags |= SEC_EXCLUDE;
 
   if (hdr->sh_type == SHT_ORDERED)
     flags |= SEC_SORT_ENTRIES;
 
-  bfd_set_section_flags (abfd, newsect, flags);
-  return TRUE;
+  if (startswith (name, ".PPC.EMB"))
+    name += 8;
+  if (startswith (name, ".sbss")
+      || startswith (name, ".sdata"))
+    flags |= SEC_SMALL_DATA;
+
+  return (flags == 0
+         || bfd_set_section_flags (newsect, newsect->flags | flags));
 }
 
 /* Set up any other section flags and such that may be necessary.  */
 
-static bfd_boolean
+static bool
 ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
                       Elf_Internal_Shdr *shdr,
                       asection *asect)
@@ -2471,7 +1364,7 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
   if ((asect->flags & SEC_SORT_ENTRIES) != 0)
     shdr->sh_type = SHT_ORDERED;
 
-  return TRUE;
+  return true;
 }
 
 /* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we
@@ -2497,7 +1390,7 @@ ppc_elf_additional_program_headers (bfd *abfd,
 
 /* Modify the segment map for VLE executables.  */
 
-bfd_boolean
+bool
 ppc_elf_modify_segment_map (bfd *abfd,
                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
@@ -2512,7 +1405,7 @@ ppc_elf_modify_segment_map (bfd *abfd,
   for (m = elf_seg_map (abfd); m != NULL; m = m->next)
     {
       struct elf_segment_map *n;
-      bfd_size_type amt;
+      size_t amt;
       unsigned int j, k;
       unsigned int p_flags;
 
@@ -2568,7 +1461,7 @@ ppc_elf_modify_segment_map (bfd *abfd,
       amt += (m->count - j - 1) * sizeof (asection *);
       n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
       if (n == NULL)
-       return FALSE;
+       return false;
 
       n->p_type = PT_LOAD;
       n->count = m->count - j;
@@ -2580,7 +1473,7 @@ ppc_elf_modify_segment_map (bfd *abfd,
       m->next = n;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Add extra PPC sections -- Note, for now, make .sbss2 and
@@ -2603,7 +1496,7 @@ static const struct bfd_elf_special_section ppc_elf_special_sections[] =
 };
 
 /* This is what we want for new plt/got.  */
-static struct bfd_elf_special_section ppc_alt_plt =
+static const struct bfd_elf_special_section ppc_alt_plt =
   { STRING_COMMA_LEN (".plt"),            0, SHT_PROGBITS, SHF_ALLOC };
 
 static const struct bfd_elf_special_section *
@@ -2636,13 +1529,13 @@ typedef struct apuinfo_list
 apuinfo_list;
 
 static apuinfo_list *head;
-static bfd_boolean apuinfo_set;
+static bool apuinfo_set;
 
 static void
 apuinfo_list_init (void)
 {
   head = NULL;
-  apuinfo_set = FALSE;
+  apuinfo_set = false;
 }
 
 static void
@@ -2742,11 +1635,10 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
       if (length < 20)
        goto fail;
 
-      apuinfo_set = TRUE;
+      apuinfo_set = true;
       if (largest_input_size < asec->size)
        {
-         if (buffer)
-           free (buffer);
+         free (buffer);
          largest_input_size = asec->size;
          buffer = bfd_malloc (largest_input_size);
          if (!buffer)
@@ -2795,7 +1687,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
       /* Set the output section size, if it exists.  */
       asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
 
-      if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
+      if (asec && !bfd_set_section_size (asec, 20 + num_entries * 4))
        {
          ibfd = abfd;
          /* xgettext:c-format */
@@ -2804,8 +1696,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
     }
 
  fail:
-  if (buffer)
-    free (buffer);
+  free (buffer);
 
   if (error_message)
     _bfd_error_handler (error_message, APUINFO_SECTION_NAME, ibfd);
@@ -2814,7 +1705,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
 /* Prevent the output section from accumulating the input sections'
    contents.  We have already stored this in our linked list structure.  */
 
-static bfd_boolean
+static bool
 ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
                       struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
                       asection *asec,
@@ -2826,7 +1717,7 @@ ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
 /* Finally we can generate the output section.  */
 
 static void
-ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
+ppc_final_write_processing (bfd *abfd)
 {
   bfd_byte *buffer;
   asection *asec;
@@ -2877,14 +1768,21 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
 
   apuinfo_list_finish ();
 }
+
+static bool
+ppc_elf_final_write_processing (bfd *abfd)
+{
+  ppc_final_write_processing (abfd);
+  return _bfd_elf_final_write_processing (abfd);
+}
 \f
-static bfd_boolean
+static bool
 is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
 {
   bfd_byte buf[4 * 4];
 
   if (!bfd_get_section_contents (abfd, glink, buf, off, sizeof buf))
-    return FALSE;
+    return false;
 
   return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11
          && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11
@@ -2892,7 +1790,7 @@ is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
          && bfd_get_32 (abfd, buf + 12) == BCTR);
 }
 
-static bfd_boolean
+static bool
 section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
 {
   bfd_vma vma = *(bfd_vma *) ptr;
@@ -2906,14 +1804,14 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
                              long dynsymcount, asymbol **dynsyms,
                              asymbol **ret)
 {
-  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+  bool (*slurp_relocs) (bfd *, asection *, asymbol **, bool);
   asection *plt, *relplt, *dynamic, *glink;
   bfd_vma glink_vma = 0;
   bfd_vma resolv_vma = 0;
   bfd_vma stub_off;
   asymbol *s;
   arelent *p;
-  long count, i, stub_delta;
+  size_t count, i, stub_delta;
   size_t size;
   char *names;
   bfd_byte buf[4];
@@ -2954,9 +1852,9 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
       extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
       swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
-      extdyn = dynbuf;
-      extdynend = extdyn + dynamic->size;
-      for (; extdyn < extdynend; extdyn += extdynsize)
+      for (extdyn = dynbuf, extdynend = dynbuf + dynamic->size;
+          (size_t) (extdynend - extdyn) >= extdynsize;
+          extdyn += extdynsize)
        {
          Elf_Internal_Dyn dyn;
          (*swap_dyn_in) (abfd, extdyn, &dyn);
@@ -3035,7 +1933,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
     return 0;
 
   slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
-  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+  if (! (*slurp_relocs) (abfd, relplt, dynsyms, true))
     return -1;
 
   size = count * sizeof (asymbol);
@@ -3223,23 +2121,29 @@ struct ppc_elf_link_hash_entry
      from the beginning of the section.  */
   elf_linker_section_pointers_t *linker_section_pointer;
 
-  /* Track dynamic relocs copied for this symbol.  */
-  struct elf_dyn_relocs *dyn_relocs;
-
-  /* Contexts in which symbol is used in the GOT (or TOC).
-     TLS_GD .. TLS_TLS bits are or'd into the mask as the
-     corresponding relocs are encountered during check_relocs.
-     tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
-     indicate the corresponding GOT entry type is not needed.  */
-#define TLS_GD          1      /* GD reloc. */
-#define TLS_LD          2      /* LD reloc. */
-#define TLS_TPREL       4      /* TPREL reloc, => IE. */
-#define TLS_DTPREL      8      /* DTPREL reloc, => LD. */
-#define TLS_TLS                16      /* Any TLS reloc.  */
-#define TLS_TPRELGD    32      /* TPREL reloc resulting from GD->IE. */
-#define PLT_IFUNC      64      /* STT_GNU_IFUNC.  */
+  /* Contexts in which symbol is used in the GOT.
+     Bits are or'd into the mask as the corresponding relocs are
+     encountered during check_relocs, with TLS_TLS being set when any
+     of the other TLS bits are set.  tls_optimize clears bits when
+     optimizing to indicate the corresponding GOT entry type is not
+     needed.  If set, TLS_TLS is never cleared.  tls_optimize may also
+     set TLS_GDIE when a GD reloc turns into an IE one.
+     These flags are also kept for local symbols.  */
+#define TLS_TLS                 1      /* Any TLS reloc.  */
+#define TLS_GD          2      /* GD reloc. */
+#define TLS_LD          4      /* LD reloc. */
+#define TLS_TPREL       8      /* TPREL reloc, => IE. */
+#define TLS_DTPREL     16      /* DTPREL reloc, => LD. */
+#define TLS_MARK       32      /* __tls_get_addr call marked. */
+#define TLS_GDIE       64      /* GOT TPREL reloc resulting from GD->IE. */
   unsigned char tls_mask;
 
+  /* The above field is also used to mark function symbols.  In which
+     case TLS_TLS will be 0.  */
+#define PLT_IFUNC       2      /* STT_GNU_IFUNC.  */
+#define PLT_KEEP        4      /* inline plt call requires plt entry.  */
+#define NON_GOT        256     /* local symbol plt, not stored.  */
+
   /* Nonzero if we have seen a small data relocation referring to this
      symbol.  */
   unsigned char has_sda_refs : 1;
@@ -3267,6 +2171,8 @@ struct ppc_elf_link_hash_table
   elf_linker_section_t sdata[2];
   asection *sbss;
   asection *glink_eh_frame;
+  asection *pltlocal;
+  asection *relpltlocal;
 
   /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
   asection *srelplt2;
@@ -3294,9 +2200,6 @@ struct ppc_elf_link_hash_table
   /* The type of PLT we have chosen to use.  */
   enum ppc_elf_plt_type plt_type;
 
-  /* True if the target system is VxWorks.  */
-  unsigned int is_vxworks:1;
-
   /* Whether there exist local gnu indirect function resolvers,
      referenced by dynamic relocations.  */
   unsigned int local_ifunc_resolver:1;
@@ -3305,15 +2208,15 @@ struct ppc_elf_link_hash_table
   /* Set if tls optimization is enabled.  */
   unsigned int do_tls_opt:1;
 
+  /* Set if inline plt calls should be converted to direct calls.  */
+  unsigned int can_convert_all_inline_plt:1;
+
   /* The size of PLT entries.  */
   int plt_entry_size;
   /* The distance between adjacent PLT slots.  */
   int plt_slot_size;
   /* The size of the first PLT entry.  */
   int plt_initial_entry_size;
-
-  /* Small local sym cache.  */
-  struct sym_cache sym_cache;
 };
 
 /* Rename some of the generic section flags to better document how they
@@ -3322,14 +2225,19 @@ struct ppc_elf_link_hash_table
 /* Nonzero if this section has TLS related relocations.  */
 #define has_tls_reloc sec_flg0
 
-/* Nonzero if this section has a call to __tls_get_addr.  */
-#define has_tls_get_addr_call sec_flg1
+/* Nonzero if this section has a call to __tls_get_addr lacking marker
+   relocs.  */
+#define nomark_tls_get_addr sec_flg1
+
+  /* Flag set when PLTCALL relocs are detected.  */
+#define has_pltcall sec_flg2
 
 /* Get the PPC ELF linker hash table from a link_info structure.  */
 
 #define ppc_elf_hash_table(p) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-  == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
+  ((is_elf_hash_table ((p)->hash)                                      \
+    && elf_hash_table_id (elf_hash_table (p)) == PPC32_ELF_DATA)       \
+   ? (struct ppc_elf_link_hash_table *) (p)->hash : NULL)
 
 /* Create an entry in a PPC ELF linker hash table.  */
 
@@ -3353,7 +2261,6 @@ ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
   if (entry != NULL)
     {
       ppc_elf_hash_entry (entry)->linker_section_pointer = NULL;
-      ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
       ppc_elf_hash_entry (entry)->tls_mask = 0;
       ppc_elf_hash_entry (entry)->has_sda_refs = 0;
     }
@@ -3419,33 +2326,33 @@ ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params)
 
 /* Create .got and the related sections.  */
 
-static bfd_boolean
+static bool
 ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
 
   if (!_bfd_elf_create_got_section (abfd, info))
-    return FALSE;
+    return false;
 
   htab = ppc_elf_hash_table (info);
-  if (!htab->is_vxworks)
+  if (htab->elf.target_os != is_vxworks)
     {
       /* The powerpc .got has a blrl instruction in it.  Mark it
         executable.  */
       flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
                        | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      if (!bfd_set_section_flags (abfd, htab->elf.sgot, flags))
-       return FALSE;
+      if (!bfd_set_section_flags (htab->elf.sgot, flags))
+       return false;
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Create a special linker section, used for R_PPC_EMB_SDAI16 and
    R_PPC_EMB_SDA2I16 pointers.  These sections become part of .sdata
    and .sdata2.  Create _SDA_BASE_ and _SDA2_BASE too.  */
 
-static bfd_boolean
+static bool
 ppc_elf_create_linker_section (bfd *abfd,
                               struct bfd_link_info *info,
                               flagword flags,
@@ -3458,7 +2365,7 @@ ppc_elf_create_linker_section (bfd *abfd,
 
   s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags);
   if (s == NULL)
-    return FALSE;
+    return false;
   lsect->section = s;
 
   /* Define the sym on the first section of this name.  */
@@ -3466,12 +2373,12 @@ ppc_elf_create_linker_section (bfd *abfd,
 
   lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name);
   if (lsect->sym == NULL)
-    return FALSE;
+    return false;
   lsect->sym->root.u.def.value = 0x8000;
-  return TRUE;
+  return true;
 }
 
-static bfd_boolean
+static bool
 ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
@@ -3487,8 +2394,8 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
   if (p2align < htab->params->plt_stub_align)
     p2align = htab->params->plt_stub_align;
   if (s == NULL
-      || !bfd_set_section_alignment (abfd, s, p2align))
-    return FALSE;
+      || !bfd_set_section_alignment (s, p2align))
+    return false;
 
   if (!info->no_ld_generated_unwind_info)
     {
@@ -3497,41 +2404,61 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
       s = bfd_make_section_anyway_with_flags (abfd, ".eh_frame", flags);
       htab->glink_eh_frame = s;
       if (s == NULL
-         || !bfd_set_section_alignment (abfd, s, 2))
-       return FALSE;
+         || !bfd_set_section_alignment (s, 2))
+       return false;
     }
 
   flags = SEC_ALLOC | SEC_LINKER_CREATED;
   s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
   htab->elf.iplt = s;
   if (s == NULL
-      || !bfd_set_section_alignment (abfd, s, 4))
-    return FALSE;
+      || !bfd_set_section_alignment (s, 4))
+    return false;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
   s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags);
   htab->elf.irelplt = s;
   if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, 2))
-    return FALSE;
+      || ! bfd_set_section_alignment (s, 2))
+    return false;
+
+  /* Local plt entries.  */
+  flags = (SEC_ALLOC | SEC_LOAD
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->pltlocal = bfd_make_section_anyway_with_flags (abfd, ".branch_lt",
+                                                      flags);
+  if (htab->pltlocal == NULL
+      || !bfd_set_section_alignment (htab->pltlocal, 2))
+    return false;
+
+  if (bfd_link_pic (info))
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->relpltlocal
+       = bfd_make_section_anyway_with_flags (abfd, ".rela.branch_lt", flags);
+      if (htab->relpltlocal == NULL
+         || !bfd_set_section_alignment (htab->relpltlocal, 2))
+       return false;
+    }
 
   if (!ppc_elf_create_linker_section (abfd, info, 0,
                                      &htab->sdata[0]))
-    return FALSE;
+    return false;
 
   if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
                                      &htab->sdata[1]))
-    return FALSE;
+    return false;
 
-  return TRUE;
+  return true;
 }
 
 /* We have to create .dynsbss and .rela.sbss here so that they get mapped
    to output sections (just like _bfd_elf_create_dynamic_sections has
    to create .dynbss and .rela.bss).  */
 
-static bfd_boolean
+static bool
 ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
@@ -3542,20 +2469,20 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   if (htab->elf.sgot == NULL
       && !ppc_elf_create_got (abfd, info))
-    return FALSE;
+    return false;
 
   if (!_bfd_elf_create_dynamic_sections (abfd, info))
-    return FALSE;
+    return false;
 
   if (htab->glink == NULL
       && !ppc_elf_create_glink (abfd, info))
-    return FALSE;
+    return false;
 
   s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss",
                                          SEC_ALLOC | SEC_LINKER_CREATED);
   htab->dynsbss = s;
   if (s == NULL)
-    return FALSE;
+    return false;
 
   if (! bfd_link_pic (info))
     {
@@ -3564,20 +2491,20 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags);
       htab->relsbss = s;
       if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s, 2))
-       return FALSE;
+         || !bfd_set_section_alignment (s, 2))
+       return false;
     }
 
-  if (htab->is_vxworks
+  if (htab->elf.target_os == is_vxworks
       && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
-    return FALSE;
+    return false;
 
   s = htab->elf.splt;
   flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED;
   if (htab->plt_type == PLT_VXWORKS)
     /* The VxWorks PLT is a loaded section with contents.  */
     flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY;
-  return bfd_set_section_flags (abfd, s, flags);
+  return bfd_set_section_flags (s, flags);
 }
 
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
@@ -3607,20 +2534,20 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
   if (eind->elf.root.type != bfd_link_hash_indirect)
     return;
 
-  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;
 
          /* 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 = &ind->dyn_relocs; (p = *pp) != NULL; )
            {
              struct elf_dyn_relocs *q;
 
-             for (q = edir->dyn_relocs; q != NULL; q = q->next)
+             for (q = dir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
                  {
                    q->pc_count += p->pc_count;
@@ -3631,11 +2558,11 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
              if (q == NULL)
                pp = &p->next;
            }
-         *pp = edir->dyn_relocs;
+         *pp = 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 the GOT refcount entries that we may have already seen to
@@ -3687,7 +2614,7 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info,
 /* Hook called by the linker routine which adds symbols from an object
    file.  We use it to put .comm items in .sbss, and not .bss.  */
 
-static bfd_boolean
+static bool
 ppc_elf_add_symbol_hook (bfd *abfd,
                         struct bfd_link_info *info,
                         Elf_Internal_Sym *sym,
@@ -3708,7 +2635,7 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       htab = ppc_elf_hash_table (info);
       if (htab->sbss == NULL)
        {
-         flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
+         flagword flags = SEC_IS_COMMON | SEC_SMALL_DATA | SEC_LINKER_CREATED;
 
          if (!htab->elf.dynobj)
            htab->elf.dynobj = abfd;
@@ -3717,19 +2644,14 @@ ppc_elf_add_symbol_hook (bfd *abfd,
                                                           ".sbss",
                                                           flags);
          if (htab->sbss == NULL)
-           return FALSE;
+           return false;
        }
 
       *secp = htab->sbss;
       *valp = sym->st_size;
     }
 
-  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-      && (abfd->flags & DYNAMIC) == 0
-      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
-  return TRUE;
+  return true;
 }
 \f
 /* Find a linker generated pointer with a given addend and type.  */
@@ -3749,7 +2671,7 @@ elf_find_pointer_linker_section
 
 /* Allocate a pointer to live in a linker created section.  */
 
-static bfd_boolean
+static bool
 elf_allocate_pointer_linker_section (bfd *abfd,
                                     elf_linker_section_t *lsect,
                                     struct elf_link_hash_entry *h,
@@ -3772,7 +2694,7 @@ elf_allocate_pointer_linker_section (bfd *abfd,
       if (elf_find_pointer_linker_section (eh->linker_section_pointer,
                                           rel->r_addend,
                                           lsect))
-       return TRUE;
+       return true;
 
       ptr_linker_section_ptr = &eh->linker_section_pointer;
     }
@@ -3793,7 +2715,7 @@ elf_allocate_pointer_linker_section (bfd *abfd,
          ptr = bfd_zalloc (abfd, amt);
 
          if (!ptr)
-           return FALSE;
+           return false;
 
          elf_local_ptr_offsets (abfd) = ptr;
        }
@@ -3802,7 +2724,7 @@ elf_allocate_pointer_linker_section (bfd *abfd,
       if (elf_find_pointer_linker_section (ptr[r_symndx],
                                           rel->r_addend,
                                           lsect))
-       return TRUE;
+       return true;
 
       ptr_linker_section_ptr = &ptr[r_symndx];
     }
@@ -3814,15 +2736,15 @@ elf_allocate_pointer_linker_section (bfd *abfd,
   linker_section_ptr = bfd_alloc (abfd, amt);
 
   if (!linker_section_ptr)
-    return FALSE;
+    return false;
 
   linker_section_ptr->next = *ptr_linker_section_ptr;
   linker_section_ptr->addend = rel->r_addend;
   linker_section_ptr->lsect = lsect;
   *ptr_linker_section_ptr = linker_section_ptr;
 
-  if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2))
-    return FALSE;
+  if (!bfd_set_section_alignment (lsect->section, 2))
+    return false;
   linker_section_ptr->offset = lsect->section->size;
   lsect->section->size += 4;
 
@@ -3833,7 +2755,7 @@ elf_allocate_pointer_linker_section (bfd *abfd,
           (long) lsect->section->size);
 #endif
 
-  return TRUE;
+  return true;
 }
 
 static struct plt_entry **
@@ -3861,13 +2783,13 @@ update_local_sym_info (bfd *abfd,
 
   local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
   local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
-  local_got_tls_masks[r_symndx] |= tls_type;
-  if (tls_type != PLT_IFUNC)
+  local_got_tls_masks[r_symndx] |= tls_type & 0xff;
+  if ((tls_type & NON_GOT) == 0)
     local_got_refcounts[r_symndx] += 1;
   return local_plt + r_symndx;
 }
 
-static bfd_boolean
+static bool
 update_plt_info (bfd *abfd, struct plt_entry **plist,
                 asection *sec, bfd_vma addend)
 {
@@ -3880,10 +2802,10 @@ update_plt_info (bfd *abfd, struct plt_entry **plist,
       break;
   if (ent == NULL)
     {
-      bfd_size_type amt = sizeof (*ent);
+      size_t amt = sizeof (*ent);
       ent = bfd_alloc (abfd, amt);
       if (ent == NULL)
-       return FALSE;
+       return false;
       ent->next = *plist;
       ent->sec = sec;
       ent->addend = addend;
@@ -3891,7 +2813,7 @@ update_plt_info (bfd *abfd, struct plt_entry **plist,
       *plist = ent;
     }
   ent->plt.refcount += 1;
-  return TRUE;
+  return true;
 }
 
 static struct plt_entry *
@@ -3907,7 +2829,7 @@ find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend)
   return ent;
 }
 
-static bfd_boolean
+static bool
 is_branch_reloc (enum elf_ppc_reloc_type r_type)
 {
   return (r_type == R_PPC_PLTREL24
@@ -3923,6 +2845,26 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type)
          || r_type == R_PPC_VLE_REL24);
 }
 
+/* Relocs on inline plt call sequence insns prior to the call.  */
+
+static bool
+is_plt_seq_reloc (enum elf_ppc_reloc_type r_type)
+{
+  return (r_type == R_PPC_PLT16_HA
+         || r_type == R_PPC_PLT16_HI
+         || r_type == R_PPC_PLT16_LO
+         || r_type == R_PPC_PLTSEQ);
+}
+
+/* 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;
+}
+
 static void
 bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
 {
@@ -3938,7 +2880,7 @@ bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
    allocate space in the global offset table or procedure linkage
    table.  */
 
-static bfd_boolean
+static bool
 ppc_elf_check_relocs (bfd *abfd,
                      struct bfd_link_info *info,
                      asection *sec,
@@ -3953,16 +2895,7 @@ ppc_elf_check_relocs (bfd *abfd,
   struct elf_link_hash_entry *tga;
 
   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;
 
 #ifdef DEBUG
   _bfd_error_handler ("ppc_elf_check_relocs called for section %pA in %pB",
@@ -3981,10 +2914,10 @@ ppc_elf_check_relocs (bfd *abfd,
       if (htab->elf.dynobj == NULL)
        htab->elf.dynobj = abfd;
       if (!ppc_elf_create_glink (htab->elf.dynobj, info))
-       return FALSE;
+       return false;
     }
   tga = 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);
   got2 = bfd_get_section_by_name (abfd, ".got2");
@@ -3996,18 +2929,27 @@ ppc_elf_check_relocs (bfd *abfd,
       unsigned long r_symndx;
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *isym;
       int tls_type;
       struct plt_entry **ifunc;
+      struct plt_entry **pltent;
+      bfd_vma addend;
 
       r_symndx = ELF32_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
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         isym = NULL;
        }
 
       /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
@@ -4020,48 +2962,56 @@ ppc_elf_check_relocs (bfd *abfd,
          if (htab->elf.dynobj == NULL)
            htab->elf.dynobj = abfd;
          if (!ppc_elf_create_got (htab->elf.dynobj, info))
-           return FALSE;
+           return false;
          BFD_ASSERT (h == htab->elf.hgot);
        }
 
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
       ifunc = NULL;
-      if (h == NULL && !htab->is_vxworks)
+      if (h != NULL)
+       {
+         if (h->type == STT_GNU_IFUNC)
+           {
+             h->needs_plt = 1;
+             ifunc = &h->plt.plist;
+           }
+       }
+      else if (htab->elf.target_os != is_vxworks)
        {
-         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)
            {
              /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-                                            PLT_IFUNC);
+                                            NON_GOT | PLT_IFUNC);
              if (ifunc == NULL)
-               return FALSE;
+               return false;
 
              /* STT_GNU_IFUNC symbols must have a PLT entry;
                 In a non-pie executable even when there are
                 no plt calls.  */
              if (!bfd_link_pic (info)
-                 || is_branch_reloc (r_type))
+                 || is_branch_reloc (r_type)
+                 || r_type == R_PPC_PLT16_LO
+                 || r_type == R_PPC_PLT16_HI
+                 || r_type == R_PPC_PLT16_HA)
                {
-                 bfd_vma addend = 0;
+                 addend = 0;
                  if (r_type == R_PPC_PLTREL24)
-                   {
-                     ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                     if (bfd_link_pic (info))
-                       addend = rel->r_addend;
-                   }
+                   ppc_elf_tdata (abfd)->makes_plt_call = 1;
+                 if (bfd_link_pic (info)
+                     && (r_type == R_PPC_PLTREL24
+                         || r_type == R_PPC_PLT16_LO
+                         || r_type == R_PPC_PLT16_HI
+                         || r_type == R_PPC_PLT16_HA))
+                   addend = rel->r_addend;
                  if (!update_plt_info (abfd, ifunc, got2, addend))
-                   return FALSE;
+                   return false;
                }
            }
        }
 
-      if (!htab->is_vxworks
+      if (htab->elf.target_os != is_vxworks
          && is_branch_reloc (r_type)
          && h != NULL
          && h == tga)
@@ -4074,7 +3024,7 @@ ppc_elf_check_relocs (bfd *abfd,
            ;
          else
            /* Mark this section as having an old-style call.  */
-           sec->has_tls_get_addr_call = 1;
+           sec->nomark_tls_get_addr = 1;
        }
 
       switch (r_type)
@@ -4083,6 +3033,15 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TLSLD:
          /* These special tls relocs tie a call to __tls_get_addr with
             its parameter symbol.  */
+         if (h != NULL)
+           ppc_elf_hash_entry (h)->tls_mask |= TLS_TLS | TLS_MARK;
+         else
+           if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                       NON_GOT | TLS_TLS | TLS_MARK))
+             return false;
+         break;
+
+       case R_PPC_PLTSEQ:
          break;
 
        case R_PPC_GOT_TLSLD16:
@@ -4128,7 +3087,7 @@ ppc_elf_check_relocs (bfd *abfd,
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
              if (!ppc_elf_create_got (htab->elf.dynobj, info))
-               return FALSE;
+               return false;
            }
          if (h != NULL)
            {
@@ -4138,50 +3097,45 @@ ppc_elf_check_relocs (bfd *abfd,
          else
            /* This is a global offset table entry for a local symbol.  */
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type))
-             return FALSE;
+             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))
            {
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
-               return FALSE;
+               return false;
            }
          break;
 
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
-         if (bfd_link_pic (info))
-           {
-             bad_shared_reloc (abfd, r_type);
-             return FALSE;
-           }
          htab->sdata[0].sym->ref_regular = 1;
          if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0],
                                                    h, rel))
-           return FALSE;
+           return false;
          if (h != NULL)
            {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             h->non_got_ref = TRUE;
+             ppc_elf_hash_entry (h)->has_sda_refs = true;
+             h->non_got_ref = true;
            }
          break;
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
-         if (bfd_link_pic (info))
+         if (!bfd_link_executable (info))
            {
              bad_shared_reloc (abfd, r_type);
-             return FALSE;
+             return false;
            }
          htab->sdata[1].sym->ref_regular = 1;
          if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1],
                                                    h, rel))
-           return FALSE;
+           return false;
          if (h != NULL)
            {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             h->non_got_ref = TRUE;
+             ppc_elf_hash_entry (h)->has_sda_refs = true;
+             h->non_got_ref = true;
            }
          break;
 
@@ -4197,8 +3151,8 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_VLE_SDAREL_HA16D:
          if (h != NULL)
            {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             h->non_got_ref = TRUE;
+             ppc_elf_hash_entry (h)->has_sda_refs = true;
+             h->non_got_ref = true;
            }
          break;
 
@@ -4215,16 +3169,16 @@ ppc_elf_check_relocs (bfd *abfd,
          break;
 
        case R_PPC_EMB_SDA2REL:
-         if (bfd_link_pic (info))
+         if (!bfd_link_executable (info))
            {
              bad_shared_reloc (abfd, r_type);
-             return FALSE;
+             return false;
            }
          htab->sdata[1].sym->ref_regular = 1;
          if (h != NULL)
            {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             h->non_got_ref = TRUE;
+             ppc_elf_hash_entry (h)->has_sda_refs = true;
+             h->non_got_ref = true;
            }
          break;
 
@@ -4232,15 +3186,10 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_VLE_SDA21:
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
-         if (bfd_link_pic (info))
-           {
-             bad_shared_reloc (abfd, r_type);
-             return FALSE;
-           }
          if (h != NULL)
            {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             h->non_got_ref = TRUE;
+             ppc_elf_hash_entry (h)->has_sda_refs = true;
+             h->non_got_ref = true;
            }
          break;
 
@@ -4249,57 +3198,53 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_EMB_NADDR16_LO:
        case R_PPC_EMB_NADDR16_HI:
        case R_PPC_EMB_NADDR16_HA:
-         if (bfd_link_pic (info))
-           {
-             bad_shared_reloc (abfd, r_type);
-             return FALSE;
-           }
          if (h != NULL)
-           h->non_got_ref = TRUE;
+           h->non_got_ref = true;
          break;
 
        case R_PPC_PLTREL24:
          if (h == NULL)
            break;
-         /* Fall through */
+         ppc_elf_tdata (abfd)->makes_plt_call = 1;
+         goto pltentry;
+
+       case R_PPC_PLTCALL:
+         sec->has_pltcall = 1;
+         /* Fall through.  */
+
        case R_PPC_PLT32:
        case R_PPC_PLTREL32:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
+       pltentry:
 #ifdef DEBUG
          fprintf (stderr, "Reloc requires a PLT entry\n");
 #endif
          /* This symbol requires a procedure linkage table entry.  */
          if (h == NULL)
            {
-             if (ifunc == NULL)
-               {
-                 /* It does not make sense to have a procedure linkage
-                    table entry for a non-ifunc local symbol.  */
-                 info->callbacks->einfo
-                   /* xgettext:c-format */
-                   (_("%H: %s reloc against local symbol\n"),
-                    abfd, sec, rel->r_offset,
-                    ppc_elf_howto_table[r_type]->name);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-               }
+             pltent = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                             NON_GOT | PLT_KEEP);
+             if (pltent == NULL)
+               return false;
            }
          else
            {
-             bfd_vma addend = 0;
-
-             if (r_type == R_PPC_PLTREL24)
-               {
-                 ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                 if (bfd_link_pic (info))
-                   addend = rel->r_addend;
-               }
+             if (r_type != R_PPC_PLTREL24)
+               ppc_elf_hash_entry (h)->tls_mask |= PLT_KEEP;
              h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
-               return FALSE;
+             pltent = &h->plt.plist;
            }
+         addend = 0;
+         if (bfd_link_pic (info)
+             && (r_type == R_PPC_PLTREL24
+                 || r_type == R_PPC_PLT16_LO
+                 || r_type == R_PPC_PLT16_HI
+                 || r_type == R_PPC_PLT16_HA))
+           addend = rel->r_addend;
+         if (!update_plt_info (abfd, pltent, got2, addend))
+           return false;
          break;
 
          /* The following relocations don't need to propagate the
@@ -4359,36 +3304,34 @@ ppc_elf_check_relocs (bfd *abfd,
              htab->plt_type = PLT_OLD;
              htab->old_bfd = abfd;
            }
-         if (h != NULL && h->type == STT_GNU_IFUNC)
-           {
-             h->needs_plt = 1;
-             if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
-               return FALSE;
-           }
+         if (h != NULL
+             && ifunc != NULL
+             && !update_plt_info (abfd, ifunc, NULL, 0))
+           return false;
          break;
 
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
        case R_PPC_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_PPC_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
          break;
 
+       case R_PPC_TPREL16_HI:
+       case R_PPC_TPREL16_HA:
+         sec->has_tls_reloc = 1;
+         /* Fall through.  */
          /* We shouldn't really be seeing TPREL32.  */
        case R_PPC_TPREL32:
        case R_PPC_TPREL16:
        case R_PPC_TPREL16_LO:
-       case R_PPC_TPREL16_HI:
-       case R_PPC_TPREL16_HA:
          if (bfd_link_dll (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
@@ -4412,12 +3355,6 @@ ppc_elf_check_relocs (bfd *abfd,
                 reliably deduce the GOT pointer value needed for
                 PLT call stubs.  */
              asection *s;
-             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 == got2)
@@ -4442,7 +3379,7 @@ ppc_elf_check_relocs (bfd *abfd,
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
-               return FALSE;
+               return false;
 
              /* We may need a copy reloc too.  */
              h->non_got_ref = 1;
@@ -4481,43 +3418,26 @@ ppc_elf_check_relocs (bfd *abfd,
                 a function defined in a dynamic object.  */
              h->needs_plt = 1;
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
-               return FALSE;
+               return false;
              break;
            }
 
        dodyn:
-         /* If we are creating a shared library, and this is a reloc
-            against a global symbol, or a non PC relative reloc
-            against a local symbol, then we need to copy the reloc
-            into the shared library.  However, if we are linking with
-            -Bsymbolic, we do not need to copy a reloc against a
-            global symbol which is defined in an object we are
-            including in the link (i.e., DEF_REGULAR is set).  At
-            this point we have not seen all the input files, so it is
-            possible that DEF_REGULAR is not set now but will be set
-            later (it is never cleared).  In case of a weak definition,
-            DEF_REGULAR may be cleared later by a strong definition in
-            a shared library.  We account for that possibility below by
-            storing information in the dyn_relocs field of the hash
-            table entry.  A similar situation occurs when creating
-            shared libraries and symbol visibility changes render the
-            symbol local.
-
-            If on the other hand, we are creating an executable, we
-            may need to keep relocations for symbols satisfied by a
-            dynamic library if we manage to avoid copy relocs for the
-            symbol.  */
-         if ((bfd_link_pic (info)
-              && (must_be_dyn_reloc (info, r_type)
-                  || (h != NULL
-                      && (!SYMBOLIC_BIND (info, h)
-                          || h->root.type == bfd_link_hash_defweak
-                          || !h->def_regular))))
-             || (ELIMINATE_COPY_RELOCS
-                 && !bfd_link_pic (info)
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+         /* Set up information for symbols that might need dynamic
+            relocations.  At this point in linking we have read all
+            the input files and resolved most symbols, but have not
+            yet decided whether symbols are dynamic or finalized
+            symbol flags.  In some cases we might be setting dynamic
+            reloc info for symbols that do not end up needing such.
+            That's OK, adjust_dynamic_symbol and allocate_dynrelocs
+            work together with this code.  */
+         if ((h != NULL
+              && !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)))
            {
 #ifdef DEBUG
              fprintf (stderr,
@@ -4532,10 +3452,10 @@ ppc_elf_check_relocs (bfd *abfd,
                    htab->elf.dynobj = abfd;
 
                  sreloc = _bfd_elf_make_dynamic_reloc_section
-                   (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
+                   (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ true);
 
                  if (sreloc == NULL)
-                   return FALSE;
+                   return false;
                }
 
              /* If this is a global symbol, we count the number of
@@ -4545,13 +3465,13 @@ ppc_elf_check_relocs (bfd *abfd,
                  struct elf_dyn_relocs *p;
                  struct elf_dyn_relocs **rel_head;
 
-                 rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
+                 rel_head = &h->dyn_relocs;
                  p = *rel_head;
                  if (p == NULL || p->sec != sec)
                    {
                      p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                      if (p == NULL)
-                       return FALSE;
+                       return false;
                      p->next = *rel_head;
                      *rel_head = p;
                      p->sec = sec;
@@ -4569,15 +3489,9 @@ ppc_elf_check_relocs (bfd *abfd,
                     easily.  Oh well.  */
                  struct ppc_dyn_relocs *p;
                  struct ppc_dyn_relocs **rel_head;
-                 bfd_boolean is_ifunc;
+                 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)
@@ -4585,7 +3499,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
                  vpp = &elf_section_data (s)->local_dynrel;
                  rel_head = (struct ppc_dyn_relocs **) vpp;
-                 is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+                 is_ifunc = ifunc != NULL;
                  p = *rel_head;
                  if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
                    p = p->next;
@@ -4593,7 +3507,7 @@ ppc_elf_check_relocs (bfd *abfd,
                    {
                      p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                      if (p == NULL)
-                       return FALSE;
+                       return false;
                      p->next = *rel_head;
                      *rel_head = p;
                      p->sec = sec;
@@ -4608,17 +3522,29 @@ ppc_elf_check_relocs (bfd *abfd,
        }
     }
 
-  return TRUE;
+  return true;
 }
 \f
 /* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
    and OBFD, and merge non-conflicting ones.  */
-void
+bool
 _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
+  bool ret = true;
+  bool warn_only;
+
+  /* We only warn about shared library mismatches, because common
+     libraries advertise support for a particular long double variant
+     but actually support more than one variant.  For example, glibc
+     typically supports 128-bit IBM long double in the shared library
+     but has a compatibility static archive for 64-bit long double.
+     The linker doesn't have the smarts to see that an app using
+     object files marked as 64-bit long double call the compatibility
+     layer objects and only from there call into the shared library.  */
+  warn_only = (ibfd->flags & DYNAMIC) != 0;
 
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
@@ -4630,32 +3556,51 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
     {
       int in_fp = in_attr->i & 3;
       int out_fp = out_attr->i & 3;
+      static bfd *last_fp, *last_ld;
 
       if (in_fp == 0)
        ;
       else if (out_fp == 0)
        {
-         out_attr->type = 1;
-         out_attr->i ^= in_fp;
+         if (!warn_only)
+           {
+             out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+             out_attr->i ^= in_fp;
+             last_fp = ibfd;
+           }
        }
       else if (out_fp != 2 && in_fp == 2)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses hard float, %pB uses soft float"), obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses hard float, %pB uses soft float"),
+            last_fp, ibfd);
+         ret = warn_only;
+       }
       else if (out_fp == 2 && in_fp != 2)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses hard float, %pB uses soft float"), ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses hard float, %pB uses soft float"),
+            ibfd, last_fp);
+         ret = warn_only;
+       }
       else if (out_fp == 1 && in_fp == 3)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses double-precision hard float, "
-            "%pB uses single-precision hard float"), obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses double-precision hard float, "
+              "%pB uses single-precision hard float"), last_fp, ibfd);
+         ret = warn_only;
+       }
       else if (out_fp == 3 && in_fp == 1)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses double-precision hard float, "
-            "%pB uses single-precision hard float"), ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses double-precision hard float, "
+              "%pB uses single-precision hard float"), ibfd, last_fp);
+         ret = warn_only;
+       }
 
       in_fp = in_attr->i & 0xc;
       out_fp = out_attr->i & 0xc;
@@ -4663,42 +3608,67 @@ _bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
        ;
       else if (out_fp == 0)
        {
-         out_attr->type = 1;
-         out_attr->i ^= in_fp;
+         if (!warn_only)
+           {
+             out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+             out_attr->i ^= in_fp;
+             last_ld = ibfd;
+           }
        }
       else if (out_fp != 2 * 4 && in_fp == 2 * 4)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses 64-bit long double, "
-            "%pB uses 128-bit long double"), ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses 64-bit long double, "
+              "%pB uses 128-bit long double"), ibfd, last_ld);
+         ret = warn_only;
+       }
       else if (in_fp != 2 * 4 && out_fp == 2 * 4)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses 64-bit long double, "
-            "%pB uses 128-bit long double"), obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses 64-bit long double, "
+              "%pB uses 128-bit long double"), last_ld, ibfd);
+         ret = warn_only;
+       }
       else if (out_fp == 1 * 4 && in_fp == 3 * 4)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses IBM long double, "
-            "%pB uses IEEE long double"), ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses IBM long double, "
+              "%pB uses IEEE long double"), last_ld, ibfd);
+         ret = warn_only;
+       }
       else if (out_fp == 3 * 4 && in_fp == 1 * 4)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses IBM long double, "
-            "%pB uses IEEE long double"), obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses IBM long double, "
+              "%pB uses IEEE long double"), ibfd, last_ld);
+         ret = warn_only;
+       }
+    }
+
+  if (!ret)
+    {
+      out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+      bfd_set_error (bfd_error_bad_value);
     }
+  return ret;
 }
 
 /* Merge object attributes from IBFD into OBFD.  Warn if
    there are conflicting attributes.  */
-static bfd_boolean
+static bool
 ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd;
   obj_attribute *in_attr, *in_attrs;
   obj_attribute *out_attr, *out_attrs;
+  bool ret;
 
-  _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+  if (!_bfd_elf_ppc_merge_fp_attributes (ibfd, info))
+    return false;
 
   obfd = info->output_bfd;
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
@@ -4708,17 +3678,20 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
      merge non-conflicting ones.  */
   in_attr = &in_attrs[Tag_GNU_Power_ABI_Vector];
   out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
+  ret = true;
   if (in_attr->i != out_attr->i)
     {
       int in_vec = in_attr->i & 3;
       int out_vec = out_attr->i & 3;
+      static bfd *last_vec;
 
       if (in_vec == 0)
        ;
       else if (out_vec == 0)
        {
-         out_attr->type = 1;
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
          out_attr->i = in_vec;
+         last_vec = ibfd;
        }
       /* For now, allow generic to transition to AltiVec or SPE
         without a warning.  If GCC marked files with their stack
@@ -4729,19 +3702,28 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
        ;
       else if (out_vec == 1)
        {
-         out_attr->type = 1;
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
          out_attr->i = in_vec;
+         last_vec = ibfd;
        }
       else if (out_vec < in_vec)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
-          obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
+            last_vec, ibfd);
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+         ret = false;
+       }
       else if (out_vec > in_vec)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
-          ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses AltiVec vector ABI, %pB uses SPE vector ABI"),
+            ibfd, last_vec);
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+         ret = false;
+       }
     }
 
   /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
@@ -4752,59 +3734,75 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
     {
       int in_struct = in_attr->i & 3;
       int out_struct = out_attr->i & 3;
+      static bfd *last_struct;
 
       if (in_struct == 0 || in_struct == 3)
        ;
       else if (out_struct == 0)
        {
-         out_attr->type = 1;
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
          out_attr->i = in_struct;
+         last_struct = ibfd;
        }
       else if (out_struct < in_struct)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses r3/r4 for small structure returns, "
-            "%pB uses memory"), obfd, ibfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses r3/r4 for small structure returns, "
+              "%pB uses memory"), last_struct, ibfd);
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+         ret = false;
+       }
       else if (out_struct > in_struct)
-       _bfd_error_handler
-         /* xgettext:c-format */
-         (_("warning: %pB uses r3/r4 for small structure returns, "
-            "%pB uses memory"), ibfd, obfd);
+       {
+         _bfd_error_handler
+           /* xgettext:c-format */
+           (_("%pB uses r3/r4 for small structure returns, "
+              "%pB uses memory"), ibfd, last_struct);
+         out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+         ret = false;
+       }
+    }
+  if (!ret)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return false;
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, info);
-
-  return TRUE;
+  return _bfd_elf_merge_object_attributes (ibfd, info);
 }
 
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 
-static bfd_boolean
+static bool
 ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
   flagword old_flags;
   flagword new_flags;
-  bfd_boolean error;
+  bool error;
 
   if (!is_ppc_elf (ibfd) || !is_ppc_elf (obfd))
-    return TRUE;
+    return true;
 
   /* Check if we have the same endianness.  */
   if (! _bfd_generic_verify_endian_match (ibfd, info))
-    return FALSE;
+    return false;
 
   if (!ppc_elf_merge_obj_attributes (ibfd, info))
-    return FALSE;
+    return false;
+
+  if ((ibfd->flags & DYNAMIC) != 0)
+    return true;
 
   new_flags = elf_elfheader (ibfd)->e_flags;
   old_flags = elf_elfheader (obfd)->e_flags;
   if (!elf_flags_init (obfd))
     {
       /* First call, no flags set.  */
-      elf_flags_init (obfd) = TRUE;
+      elf_flags_init (obfd) = true;
       elf_elfheader (obfd)->e_flags = new_flags;
     }
 
@@ -4817,11 +3815,11 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
     {
       /* Warn about -mrelocatable mismatch.  Allow -mrelocatable-lib
         to be linked with either.  */
-      error = FALSE;
+      error = false;
       if ((new_flags & EF_PPC_RELOCATABLE) != 0
          && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
        {
-         error = TRUE;
+         error = true;
          _bfd_error_handler
            (_("%pB: compiled with -mrelocatable and linked with "
               "modules compiled normally"), ibfd);
@@ -4829,7 +3827,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
               && (old_flags & EF_PPC_RELOCATABLE) != 0)
        {
-         error = TRUE;
+         error = true;
          _bfd_error_handler
            (_("%pB: compiled normally and linked with "
               "modules compiled with -mrelocatable"), ibfd);
@@ -4856,7 +3854,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       /* Warn about any other mismatches.  */
       if (new_flags != old_flags)
        {
-         error = TRUE;
+         error = true;
          _bfd_error_handler
            /* xgettext:c-format */
            (_("%pB: uses different e_flags (%#x) fields "
@@ -4867,26 +3865,28 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       if (error)
        {
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
        }
     }
 
-  return TRUE;
+  return true;
 }
 
-static void
+static bfd_reloc_status_type
 ppc_elf_vle_split16 (bfd *input_bfd,
                     asection *input_section,
                     unsigned long offset,
                     bfd_byte *loc,
                     bfd_vma value,
                     split16_format_type split16_format,
-                    bfd_boolean fixup)
+                    bool fixup)
 {
-  unsigned int insn, opcode, top5;
+  unsigned int insn, opcode;
 
+  if (!offset_in_range (input_section, offset, 4))
+    return bfd_reloc_outofrange;
   insn = bfd_get_32 (input_bfd, loc);
-  opcode = insn & 0xfc00f800;
+  opcode = insn & E_OPCODE_MASK;
   if (opcode == E_OR2I_INSN
       || opcode == E_AND2I_DOT_INSN
       || opcode == E_OR2IS_INSN
@@ -4923,12 +3923,25 @@ ppc_elf_vle_split16 (bfd *input_bfd,
               input_bfd, input_section, offset, opcode);
        }
     }
-  top5 = value & 0xf800;
-  top5 = top5 << (split16_format == split16a_type ? 5 : 10);
-  insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x3e007ff);
-  insn |= top5;
+  if (split16_format == split16a_type)
+    {
+      insn &= ~((0xf800 << 5) | 0x7ff);
+      insn |= (value & 0xf800) << 5;
+      if ((insn & E_LI_MASK) == E_LI_INSN)
+       {
+         /* Hack for e_li.  Extend sign.  */
+         insn &= ~(0xf0000 >> 5);
+         insn |= (-(value & 0x8000) & 0xf0000) >> 5;
+       }
+    }
+  else
+    {
+      insn &= ~((0xf800 << 10) | 0x7ff);
+      insn |= (value & 0xf800) << 10;
+    }
   insn |= value & 0x7ff;
   bfd_put_32 (input_bfd, insn, loc);
+  return bfd_reloc_ok;
 }
 
 static void
@@ -4968,7 +3981,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
       else if (bfd_link_pic (info)
               && htab->elf.dynamic_sections_created
               && (h = elf_link_hash_lookup (&htab->elf, "_mcount",
-                                            FALSE, FALSE, TRUE)) != NULL
+                                            false, false, true)) != NULL
               && (h->type == STT_FUNC
                   || h->needs_plt)
               && h->ref_regular
@@ -5024,19 +4037,19 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       /* The new PLT is a loaded section.  */
       if (htab->elf.splt != NULL
-         && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.splt, flags))
+         && !bfd_set_section_flags (htab->elf.splt, flags))
        return -1;
 
       /* The new GOT is not executable.  */
       if (htab->elf.sgot != NULL
-         && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.sgot, flags))
+         && !bfd_set_section_flags (htab->elf.sgot, flags))
        return -1;
     }
   else
     {
       /* Stop an unused .glink section from affecting .text alignment.  */
       if (htab->glink != NULL
-         && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0))
+         && !bfd_set_section_alignment (htab->glink, 0))
        return -1;
     }
   return htab->plt_type == PLT_NEW;
@@ -5062,83 +4075,304 @@ ppc_elf_gc_mark_hook (asection *sec,
 
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
 }
-\f
-/* Set plt output section type, htab->tls_get_addr, and call the
-   generic ELF tls_setup function.  */
 
-asection *
-ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+static bool
+get_sym_h (struct elf_link_hash_entry **hp,
+          Elf_Internal_Sym **symp,
+          asection **symsecp,
+          unsigned char **tls_maskp,
+          Elf_Internal_Sym **locsymsp,
+          unsigned long r_symndx,
+          bfd *ibfd)
 {
-  struct ppc_elf_link_hash_table *htab;
-
-  htab = ppc_elf_hash_table (info);
-  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
-                                            FALSE, FALSE, TRUE);
-  if (htab->plt_type != PLT_NEW)
-    htab->params->no_tls_get_addr_opt = TRUE;
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
 
-  if (!htab->params->no_tls_get_addr_opt)
+  if (r_symndx >= symtab_hdr->sh_info)
     {
-      struct elf_link_hash_entry *opt, *tga;
-      opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
-                                 FALSE, FALSE, TRUE);
-      if (opt != NULL
-         && (opt->root.type == bfd_link_hash_defined
-             || opt->root.type == bfd_link_hash_defweak))
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+      if (hp != NULL)
+       *hp = h;
+
+      if (symp != NULL)
+       *symp = NULL;
+
+      if (symsecp != NULL)
        {
-         /* If glibc supports an optimized __tls_get_addr call stub,
-            signalled by the presence of __tls_get_addr_opt, and we'll
-            be calling __tls_get_addr via a plt call stub, then
-            make __tls_get_addr point to __tls_get_addr_opt.  */
-         tga = htab->tls_get_addr;
-         if (htab->elf.dynamic_sections_created
-             && tga != NULL
-             && (tga->type == STT_FUNC
-                 || tga->needs_plt)
-             && !(SYMBOL_CALLS_LOCAL (info, tga)
-                  || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga)))
-           {
-             struct plt_entry *ent;
-             for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
-               if (ent->plt.refcount > 0)
-                 break;
-             if (ent != NULL)
-               {
-                 tga->root.type = bfd_link_hash_indirect;
-                 tga->root.u.i.link = &opt->root;
-                 ppc_elf_copy_indirect_symbol (info, opt, tga);
-                 opt->mark = 1;
-                 if (opt->dynindx != -1)
-                   {
-                     /* Use __tls_get_addr_opt in dynamic relocations.  */
-                     opt->dynindx = -1;
-                     _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
-                                             opt->dynstr_index);
-                     if (!bfd_elf_link_record_dynamic_symbol (info, opt))
-                       return FALSE;
-                   }
-                 htab->tls_get_addr = opt;
-               }
-           }
+         asection *symsec = NULL;
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+           symsec = h->root.u.def.section;
+         *symsecp = symsec;
        }
-      else
-       htab->params->no_tls_get_addr_opt = TRUE;
+
+      if (tls_maskp != NULL)
+       *tls_maskp = &ppc_elf_hash_entry (h)->tls_mask;
     }
-  if (htab->plt_type == PLT_NEW
-      && htab->elf.splt != NULL
-      && htab->elf.splt->output_section != NULL)
+  else
     {
-      elf_section_type (htab->elf.splt->output_section) = SHT_PROGBITS;
-      elf_section_flags (htab->elf.splt->output_section) = SHF_ALLOC + SHF_WRITE;
-    }
+      Elf_Internal_Sym *sym;
+      Elf_Internal_Sym *locsyms = *locsymsp;
 
-  return _bfd_elf_tls_setup (obfd, info);
-}
+      if (locsyms == NULL)
+       {
+         locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+         if (locsyms == NULL)
+           locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+                                           symtab_hdr->sh_info,
+                                           0, NULL, NULL, NULL);
+         if (locsyms == NULL)
+           return false;
+         *locsymsp = locsyms;
+       }
+      sym = locsyms + r_symndx;
 
-/* Return TRUE iff REL is a branch reloc with a global symbol matching
+      if (hp != NULL)
+       *hp = NULL;
+
+      if (symp != NULL)
+       *symp = sym;
+
+      if (symsecp != NULL)
+       *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+
+      if (tls_maskp != NULL)
+       {
+         bfd_signed_vma *local_got;
+         unsigned char *tls_mask;
+
+         tls_mask = NULL;
+         local_got = elf_local_got_refcounts (ibfd);
+         if (local_got != NULL)
+           {
+             struct plt_entry **local_plt = (struct plt_entry **)
+               (local_got + symtab_hdr->sh_info);
+             unsigned char *lgot_masks = (unsigned char *)
+               (local_plt + symtab_hdr->sh_info);
+             tls_mask = &lgot_masks[r_symndx];
+           }
+         *tls_maskp = tls_mask;
+       }
+    }
+  return true;
+}
+\f
+/* Analyze inline PLT call relocations to see whether calls to locally
+   defined functions can be converted to direct calls.  */
+
+bool
+ppc_elf_inline_plt (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab;
+  bfd *ibfd;
+  asection *sec;
+  bfd_vma low_vma, high_vma, limit;
+
+  htab = ppc_elf_hash_table (info);
+  if (htab == NULL)
+    return false;
+
+  /* A bl insn can reach -0x2000000 to 0x1fffffc.  The limit is
+     reduced somewhat to cater for possible stubs that might be added
+     between the call and its destination.  */
+  limit = 0x1e00000;
+  low_vma = -1;
+  high_vma = 0;
+  for (sec = info->output_bfd->sections; sec != NULL; sec = sec->next)
+    if ((sec->flags & (SEC_ALLOC | SEC_CODE)) == (SEC_ALLOC | SEC_CODE))
+      {
+       if (low_vma > sec->vma)
+         low_vma = sec->vma;
+       if (high_vma < sec->vma + sec->size)
+         high_vma = sec->vma + sec->size;
+      }
+
+  /* If a "bl" can reach anywhere in local code sections, then we can
+     convert all inline PLT sequences to direct calls when the symbol
+     is local.  */
+  if (high_vma - low_vma < limit)
+    {
+      htab->can_convert_all_inline_plt = 1;
+      return true;
+    }
+
+  /* Otherwise, go looking through relocs for cases where a direct
+     call won't reach.  Mark the symbol on any such reloc to disable
+     the optimization and keep the PLT entry as it seems likely that
+     this will be better than creating trampolines.  Note that this
+     will disable the optimization for all inline PLT calls to a
+     particular symbol, not just those that won't reach.  The
+     difficulty in doing a more precise optimization is that the
+     linker needs to make a decision depending on whether a
+     particular R_PPC_PLTCALL insn can be turned into a direct
+     call, for each of the R_PPC_PLTSEQ and R_PPC_PLT16* insns in
+     the sequence, and there is nothing that ties those relocs
+     together except their symbol.  */
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+
+      if (!is_ppc_elf (ibfd))
+       continue;
+
+      local_syms = NULL;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if (sec->has_pltcall
+           && !bfd_is_abs_section (sec->output_section))
+         {
+           Elf_Internal_Rela *relstart, *rel, *relend;
+
+           /* Read the relocations.  */
+           relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                                 info->keep_memory);
+           if (relstart == NULL)
+             return false;
+
+           relend = relstart + sec->reloc_count;
+           for (rel = relstart; rel < relend; rel++)
+             {
+               enum elf_ppc_reloc_type r_type;
+               unsigned long r_symndx;
+               asection *sym_sec;
+               struct elf_link_hash_entry *h;
+               Elf_Internal_Sym *sym;
+               unsigned char *tls_maskp;
+
+               r_type = ELF32_R_TYPE (rel->r_info);
+               if (r_type != R_PPC_PLTCALL)
+                 continue;
+
+               r_symndx = ELF32_R_SYM (rel->r_info);
+               if (!get_sym_h (&h, &sym, &sym_sec, &tls_maskp, &local_syms,
+                               r_symndx, ibfd))
+                 {
+                   if (elf_section_data (sec)->relocs != relstart)
+                     free (relstart);
+                   if (symtab_hdr->contents != (unsigned char *) local_syms)
+                     free (local_syms);
+                   return false;
+                 }
+
+               if (sym_sec != NULL && sym_sec->output_section != NULL)
+                 {
+                   bfd_vma from, to;
+                   if (h != NULL)
+                     to = h->root.u.def.value;
+                   else
+                     to = sym->st_value;
+                   to += (rel->r_addend
+                          + sym_sec->output_offset
+                          + sym_sec->output_section->vma);
+                   from = (rel->r_offset
+                           + sec->output_offset
+                           + sec->output_section->vma);
+                   if (to - from + limit < 2 * limit)
+                     *tls_maskp &= ~PLT_KEEP;
+                 }
+             }
+           if (elf_section_data (sec)->relocs != relstart)
+             free (relstart);
+         }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
+
+  return true;
+}
+
+/* Set plt output section type, htab->tls_get_addr, and call the
+   generic ELF tls_setup function.  */
+
+asection *
+ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab;
+
+  htab = ppc_elf_hash_table (info);
+  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                                            false, false, true);
+  if (htab->plt_type != PLT_NEW)
+    htab->params->no_tls_get_addr_opt = true;
+
+  if (!htab->params->no_tls_get_addr_opt)
+    {
+      struct elf_link_hash_entry *opt, *tga;
+      opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
+                                 false, false, true);
+      if (opt != NULL
+         && (opt->root.type == bfd_link_hash_defined
+             || opt->root.type == bfd_link_hash_defweak))
+       {
+         /* If glibc supports an optimized __tls_get_addr call stub,
+            signalled by the presence of __tls_get_addr_opt, and we'll
+            be calling __tls_get_addr via a plt call stub, then
+            make __tls_get_addr point to __tls_get_addr_opt.  */
+         tga = htab->tls_get_addr;
+         if (htab->elf.dynamic_sections_created
+             && tga != NULL
+             && (tga->type == STT_FUNC
+                 || tga->needs_plt)
+             && !(SYMBOL_CALLS_LOCAL (info, tga)
+                  || UNDEFWEAK_NO_DYNAMIC_RELOC (info, tga)))
+           {
+             struct plt_entry *ent;
+             for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->plt.refcount > 0)
+                 break;
+             if (ent != NULL)
+               {
+                 tga->root.type = bfd_link_hash_indirect;
+                 tga->root.u.i.link = &opt->root;
+                 ppc_elf_copy_indirect_symbol (info, opt, tga);
+                 opt->mark = 1;
+                 if (opt->dynindx != -1)
+                   {
+                     /* Use __tls_get_addr_opt in dynamic relocations.  */
+                     opt->dynindx = -1;
+                     _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                             opt->dynstr_index);
+                     if (!bfd_elf_link_record_dynamic_symbol (info, opt))
+                       return false;
+                   }
+                 htab->tls_get_addr = opt;
+               }
+           }
+       }
+      else
+       htab->params->no_tls_get_addr_opt = true;
+    }
+  if (htab->plt_type == PLT_NEW
+      && htab->elf.splt != NULL
+      && htab->elf.splt->output_section != NULL)
+    {
+      elf_section_type (htab->elf.splt->output_section) = SHT_PROGBITS;
+      elf_section_flags (htab->elf.splt->output_section) = SHF_ALLOC + SHF_WRITE;
+    }
+
+  return _bfd_elf_tls_setup (obfd, info);
+}
+
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
    HASH.  */
 
-static bfd_boolean
+static bool
 branch_reloc_hash_match (const bfd *ibfd,
                         const Elf_Internal_Rela *rel,
                         const struct elf_link_hash_entry *hash)
@@ -5157,15 +4391,15 @@ branch_reloc_hash_match (const bfd *ibfd,
             || h->root.type == bfd_link_hash_warning)
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
       if (h == hash)
-       return TRUE;
+       return true;
     }
-  return FALSE;
+  return false;
 }
 
 /* Run through all the TLS relocs looking for optimization
    opportunities.  */
 
-bfd_boolean
+bool
 ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      struct bfd_link_info *info)
 {
@@ -5175,11 +4409,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   int pass;
 
   if (!bfd_link_executable (info))
-    return TRUE;
+    return true;
 
   htab = ppc_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
+
+  htab->do_tls_opt = 1;
 
   /* Make two passes through the relocs.  First time check that tls
      relocs involved in setting up a tls_get_addr call are indeed
@@ -5190,7 +4426,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   for (pass = 0; pass < 2; ++pass)
     for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
       {
-       Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
        asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
 
@@ -5204,7 +4439,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
              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; rel++)
@@ -5213,8 +4448,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  unsigned long r_symndx;
                  struct elf_link_hash_entry *h = NULL;
                  unsigned char *tls_mask;
-                 char tls_set, tls_clear;
-                 bfd_boolean is_local;
+                 unsigned char tls_set, tls_clear;
+                 bool is_local;
                  bfd_signed_vma *got_count;
 
                  r_symndx = ELF32_R_SYM (rel->r_info);
@@ -5229,11 +4464,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                        h = (struct elf_link_hash_entry *) h->root.u.i.link;
                    }
 
-                 is_local = FALSE;
-                 if (h == NULL
-                     || !h->def_dynamic)
-                   is_local = TRUE;
-
+                 is_local = SYMBOL_REFERENCES_LOCAL (info, h);
                  r_type = ELF32_R_TYPE (rel->r_info);
                  /* If this section has old-style __tls_get_addr calls
                     without marker relocs, then check that each
@@ -5242,7 +4473,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                     setup insn.  If we don't find matching arg setup
                     relocs, don't do any tls optimization.  */
                  if (pass == 0
-                     && sec->has_tls_get_addr_call
+                     && sec->nomark_tls_get_addr
                      && h != NULL
                      && h == htab->tls_get_addr
                      && !expecting_tls_get_addr
@@ -5253,7 +4484,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                                              ibfd, sec, rel->r_offset);
                      if (elf_section_data (sec)->relocs != relstart)
                        free (relstart);
-                     return TRUE;
+                     return true;
                    }
 
                  expecting_tls_get_addr = 0;
@@ -5289,7 +4520,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                        tls_set = 0;
                      else
                        /* GD -> IE */
-                       tls_set = TLS_TLS | TLS_TPRELGD;
+                       tls_set = TLS_TLS | TLS_GDIE;
                      tls_clear = TLS_GD;
                      break;
 
@@ -5307,13 +4538,81 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      else
                        continue;
 
-                   case R_PPC_TLSGD:
                    case R_PPC_TLSLD:
+                     if (!is_local)
+                       continue;
+                     /* Fall through.  */
+                   case R_PPC_TLSGD:
+                     if (rel + 1 < relend
+                         && is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+                       {
+                         if (pass != 0
+                             && ELF32_R_TYPE (rel[1].r_info) != R_PPC_PLTSEQ)
+                           {
+                             r_type = ELF32_R_TYPE (rel[1].r_info);
+                             r_symndx = ELF32_R_SYM (rel[1].r_info);
+                             if (r_symndx >= symtab_hdr->sh_info)
+                               {
+                                 struct elf_link_hash_entry **sym_hashes;
+
+                                 sym_hashes = elf_sym_hashes (ibfd);
+                                 h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+                                 while (h->root.type == bfd_link_hash_indirect
+                                        || h->root.type == bfd_link_hash_warning)
+                                   h = (struct elf_link_hash_entry *) h->root.u.i.link;
+                                 if (h != NULL)
+                                   {
+                                     struct plt_entry *ent = NULL;
+                                     bfd_vma addend = 0;
+
+                                     if (bfd_link_pic (info))
+                                       addend = rel->r_addend;
+                                     ent = find_plt_ent (&h->plt.plist,
+                                                         got2, addend);
+                                     if (ent != NULL
+                                         && ent->plt.refcount > 0)
+                                       ent->plt.refcount -= 1;
+                                   }
+                               }
+                           }
+                         continue;
+                       }
                      expecting_tls_get_addr = 2;
                      tls_set = 0;
                      tls_clear = 0;
                      break;
 
+                   case R_PPC_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))
+                           {
+                             if (elf_section_data (sec)->relocs != relstart)
+                               free (relstart);
+                             return false;
+                           }
+                         insn = bfd_get_32 (ibfd, buf);
+                         /* addis rt,2,imm */
+                         if ((insn & ((0x3fu << 26) | 0x1f << 16))
+                             != ((15u << 26) | (2 << 16)))
+                           {
+                             /* xgettext:c-format */
+                             info->callbacks->minfo
+                               (_("%H: warning: %s unexpected insn %#x.\n"),
+                                ibfd, sec, off, "R_PPC_TPREL16_HA", insn);
+                             htab->do_tls_opt = 0;
+                           }
+                       }
+                     continue;
+
+                   case R_PPC_TPREL16_HI:
+                     htab->do_tls_opt = 0;
+                     continue;
+
                    default:
                      continue;
                    }
@@ -5321,8 +4620,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  if (pass == 0)
                    {
                      if (!expecting_tls_get_addr
-                         || (expecting_tls_get_addr == 1
-                             && !sec->has_tls_get_addr_call))
+                         || !sec->nomark_tls_get_addr)
                        continue;
 
                      if (rel + 1 < relend
@@ -5339,24 +4637,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                                              ibfd, sec, rel->r_offset);
                      if (elf_section_data (sec)->relocs != relstart)
                        free (relstart);
-                     return TRUE;
-                   }
-
-                 if (expecting_tls_get_addr)
-                   {
-                     struct plt_entry *ent;
-                     bfd_vma addend = 0;
-
-                     if (bfd_link_pic (info)
-                         && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
-                       addend = rel[1].r_addend;
-                     ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
-                                         got2, addend);
-                     if (ent != NULL && ent->plt.refcount > 0)
-                       ent->plt.refcount -= 1;
-
-                     if (expecting_tls_get_addr == 2)
-                       continue;
+                     return true;
                    }
 
                  if (h != NULL)
@@ -5370,20 +4651,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      struct plt_entry **local_plt;
                      unsigned char *lgot_masks;
 
-                     if (locsyms == NULL)
-                       {
-                         locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
-                         if (locsyms == NULL)
-                           locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
-                                                           symtab_hdr->sh_info,
-                                                           0, NULL, NULL, NULL);
-                         if (locsyms == NULL)
-                           {
-                             if (elf_section_data (sec)->relocs != relstart)
-                               free (relstart);
-                             return FALSE;
-                           }
-                       }
                      lgot_refs = elf_local_got_refcounts (ibfd);
                      if (lgot_refs == NULL)
                        abort ();
@@ -5395,6 +4662,36 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      got_count = &lgot_refs[r_symndx];
                    }
 
+                 /* If we don't have old-style __tls_get_addr calls
+                    without TLSGD/TLSLD marker relocs, and we haven't
+                    found a new-style __tls_get_addr call with a
+                    marker for this symbol, then we either have a
+                    broken object file or an -mlongcall style
+                    indirect call to __tls_get_addr without a marker.
+                    Disable optimization in this case.  */
+                 if ((tls_clear & (TLS_GD | TLS_LD)) != 0
+                     && !sec->nomark_tls_get_addr
+                     && ((*tls_mask & (TLS_TLS | TLS_MARK))
+                         != (TLS_TLS | TLS_MARK)))
+                   continue;
+
+                 if (expecting_tls_get_addr == 1 + !sec->nomark_tls_get_addr)
+                   {
+                     struct plt_entry *ent;
+                     bfd_vma addend = 0;
+
+                     if (bfd_link_pic (info)
+                         && (ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24
+                             || ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTCALL))
+                       addend = rel[1].r_addend;
+                     ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
+                                         got2, addend);
+                     if (ent != NULL && ent->plt.refcount > 0)
+                       ent->plt.refcount -= 1;
+                   }
+                 if (tls_clear == 0)
+                   continue;
+
                  if (tls_set == 0)
                    {
                      /* We managed to get rid of a got entry.  */
@@ -5409,66 +4706,39 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
              if (elf_section_data (sec)->relocs != relstart)
                free (relstart);
            }
-
-       if (locsyms != NULL
-           && (symtab_hdr->contents != (unsigned char *) locsyms))
-         {
-           if (!info->keep_memory)
-             free (locsyms);
-           else
-             symtab_hdr->contents = (unsigned char *) locsyms;
-         }
       }
-  htab->do_tls_opt = 1;
-  return TRUE;
+  return true;
 }
 \f
-/* Find dynamic relocs for H that apply to read-only sections.  */
-
-static asection *
-readonly_dynrelocs (struct elf_link_hash_entry *h)
-{
-  struct elf_dyn_relocs *p;
-
-  for (p = ppc_elf_hash_entry (h)->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 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_elf_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 H has pc-relative dynamic relocs.  */
 
-static bfd_boolean
+static bool
 pc_dynrelocs (struct elf_link_hash_entry *h)
 {
   struct elf_dyn_relocs *p;
 
-  for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
+  for (p = h->dyn_relocs; p != NULL; p = p->next)
     if (p->pc_count != 0)
-      return TRUE;
-  return FALSE;
+      return true;
+  return false;
 }
 
 /* Adjust a symbol defined by a dynamic object and referenced by a
@@ -5477,7 +4747,7 @@ pc_dynrelocs (struct elf_link_hash_entry *h)
    change the definition to something the rest of the link can
    understand.  */
 
-static bfd_boolean
+static bool
 ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                               struct elf_link_hash_entry *h)
 {
@@ -5504,12 +4774,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
-      bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, h)
+      bool local = (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.  */
       if (!bfd_link_pic (info) && 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.  */
@@ -5518,7 +4788,11 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || (h->type != STT_GNU_IFUNC && local))
+         || (h->type != STT_GNU_IFUNC
+             && local
+             && (htab->can_convert_all_inline_plt
+                 || (ppc_elf_hash_entry (h)->tls_mask
+                     & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)))
        {
          /* A PLT entry is not required/allowed when:
 
@@ -5549,24 +4823,24 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
               || (h->non_got_ref
                   && !h->ref_regular_nonweak
                   && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)))
-             && !htab->is_vxworks
+             && htab->elf.target_os != is_vxworks
              && !ppc_elf_hash_entry (h)->has_sda_refs
-             && !readonly_dynrelocs (h))
+             && !_bfd_elf_readonly_dynrelocs (h))
            {
              h->pointer_equality_needed = 0;
-             /* If we haven't seen a branch reloc then we don't need
-                a plt entry.  */
-             if (!h->needs_plt)
+             /* If we haven't seen a branch reloc and the symbol
+                isn't an ifunc then we don't need a plt entry.  */
+             if (!h->needs_plt && h->type != STT_GNU_IFUNC)
                h->plt.plist = NULL;
            }
          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;
        }
       h->protected_def = 0;
       /* Function symbols can't have copy relocs.  */
-      return TRUE;
+      return true;
     }
   else
     h->plt.plist = NULL;
@@ -5583,8 +4857,8 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       if (def->root.u.def.section == htab->elf.sdynbss
          || def->root.u.def.section == htab->elf.sdynrelro
          || def->root.u.def.section == htab->dynsbss)
-       ppc_elf_hash_entry (h)->dyn_relocs = NULL;
-      return TRUE;
+       h->dyn_relocs = NULL;
+      return true;
     }
 
   /* This is a reference to a symbol defined by a dynamic object which
@@ -5597,7 +4871,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (bfd_link_pic (info))
     {
       h->protected_def = 0;
-      return TRUE;
+      return true;
     }
 
   /* If there are no references to this symbol that do not use the
@@ -5605,7 +4879,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (!h->non_got_ref)
     {
       h->protected_def = 0;
-      return TRUE;
+      return true;
     }
 
   /* Protected variables do not work with .dynbss.  The copy in
@@ -5620,12 +4894,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          && htab->params->pic_fixup == 0
          && info->disable_target_specific_optimizations <= 1)
        htab->params->pic_fixup = 1;
-      return TRUE;
+      return true;
     }
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
   if (info->nocopyreloc)
-    return TRUE;
+    return true;
 
    /* If we don't find any dynamic relocs in read-only sections, then
       we'll be keeping the dynamic relocs and avoiding the copy reloc.
@@ -5635,10 +4909,10 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       executable.  */
   if (ELIMINATE_COPY_RELOCS
       && !ppc_elf_hash_entry (h)->has_sda_refs
-      && !htab->is_vxworks
+      && htab->elf.target_os != is_vxworks
       && !h->def_regular
       && !alias_readonly_dynrelocs (h))
-    return TRUE;
+    return true;
 
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
@@ -5679,7 +4953,7 @@ ppc_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);
 }
 \f
@@ -5689,7 +4963,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
    is xxxxxxxx.plt_pic32.<callee>, and for -fPIC
    xxxxxxxx.got2.plt_pic32.<callee>.  */
 
-static bfd_boolean
+static bool
 add_stub_sym (struct plt_entry *ent,
              struct elf_link_hash_entry *h,
              struct bfd_link_info *info)
@@ -5712,15 +4986,15 @@ add_stub_sym (struct plt_entry *ent,
     len3 = strlen (ent->sec->name);
   name = bfd_malloc (len1 + len2 + len3 + 9);
   if (name == NULL)
-    return FALSE;
+    return false;
   sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff);
   if (ent->sec)
     memcpy (name + 8, ent->sec->name, len3);
   memcpy (name + 8 + len3, stub, len2);
   memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1);
-  sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
+  sh = elf_link_hash_lookup (&htab->elf, name, true, false, false);
   if (sh == NULL)
-    return FALSE;
+    return false;
   if (sh->root.type == bfd_link_hash_new)
     {
       sh->root.type = bfd_link_hash_defined;
@@ -5733,7 +5007,7 @@ add_stub_sym (struct plt_entry *ent,
       sh->non_elf = 0;
       sh->root.linker_def = 1;
     }
-  return TRUE;
+  return true;
 }
 
 /* Allocate NEED contiguous space in .got, and return the offset.
@@ -5787,7 +5061,7 @@ got_entries_needed (int tls_mask)
       need = 0;
       if ((tls_mask & TLS_GD) != 0)
        need += 8;
-      if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
+      if ((tls_mask & (TLS_TPREL | TLS_GDIE)) != 0)
        need += 4;
       if ((tls_mask & TLS_DTPREL) != 0)
        need += 4;
@@ -5795,26 +5069,9 @@ got_entries_needed (int tls_mask)
   return need;
 }
 
-/* Calculate size of relocs needed for symbol given its TLS_MASK and
-   NEEDed GOT entries.  KNOWN says a TPREL offset can be calculated at
-   link time.  */
-
-static inline unsigned int
-got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
-{
-  /* All the entries we allocated need relocs.
-     Except IE in executable with a local symbol.  We could also omit
-     the DTPREL reloc on the second word of a GD entry under the same
-     condition as that for IE, but ld.so needs to differentiate
-     LD and GD entries.  */
-  if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known)
-    need -= 4;
-  return need * sizeof (Elf32_External_Rela) / 4;
-}
-
 /* 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)
 {
@@ -5828,22 +5085,33 @@ 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 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 = inf;
   struct ppc_elf_link_hash_entry *eh;
   struct ppc_elf_link_hash_table *htab;
   struct elf_dyn_relocs *p;
-  bfd_boolean dyn;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   htab = ppc_elf_hash_table (info);
   eh = (struct ppc_elf_link_hash_entry *) h;
@@ -5859,12 +5127,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
       /* Make sure this symbol is output as a dynamic symbol.  */
       if (!ensure_undef_dynamic (info, &eh->elf))
-       return FALSE;
+       return false;
 
       need = 0;
-      if ((eh->tls_mask & TLS_LD) != 0)
+      if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
        {
-         if (!eh->elf.def_dynamic)
+         if (SYMBOL_REFERENCES_LOCAL (info, &eh->elf))
            /* We'll just use htab->tlsld_got.offset.  This should
               always be the case.  It's a little odd if we have
               a local dynamic reloc against a non-local symbol.  */
@@ -5878,19 +5146,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       else
        {
          eh->elf.got.offset = allocate_got (htab, need);
-         if ((bfd_link_pic (info)
+         if (((bfd_link_pic (info)
+               && !((eh->tls_mask & TLS_TLS) != 0
+                    && bfd_link_executable (info)
+                    && SYMBOL_REFERENCES_LOCAL (info, &eh->elf))
+               && !bfd_is_abs_symbol (&h->root))
               || (htab->elf.dynamic_sections_created
                   && eh->elf.dynindx != -1
                   && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
              && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
            {
              asection *rsec;
-             bfd_boolean tprel_known = (bfd_link_executable (info)
-                                        && SYMBOL_REFERENCES_LOCAL (info,
-                                                                    &eh->elf));
 
-             need = got_relocs_needed (eh->tls_mask, need, tprel_known);
-             if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic)
+             need *= sizeof (Elf32_External_Rela) / 4;
+             if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
                need -= sizeof (Elf32_External_Rela);
              rsec = htab->elf.srelgot;
              if (eh->elf.type == STT_GNU_IFUNC)
@@ -5906,19 +5175,19 @@ 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)
     ;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -5938,7 +5207,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        {
          struct elf_dyn_relocs **pp;
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+         for (pp = &h->dyn_relocs; (p = *pp) != NULL; )
            {
              p->count -= p->pc_count;
              p->pc_count = 0;
@@ -5949,11 +5218,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
 
-      if (htab->is_vxworks)
+      if (htab->elf.target_os == is_vxworks)
        {
          struct elf_dyn_relocs **pp;
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+         for (pp = &h->dyn_relocs; (p = *pp) != NULL; )
            {
              if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
                *pp = p->next;
@@ -5962,11 +5231,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
 
-      if (eh->dyn_relocs != NULL)
+      if (h->dyn_relocs != NULL)
        {
          /* Make sure this symbol is output as a dynamic symbol.  */
          if (!ensure_undef_dynamic (info, h))
-           return FALSE;
+           return false;
        }
     }
   else if (ELIMINATE_COPY_RELOCS)
@@ -5974,7 +5243,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       /* For the non-pic case, discard space for relocs against
         symbols which turn out to need copy relocs or are not
         dynamic.  */
-      if (h->dynamic_adjusted
+      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)
          && !(h->protected_def
@@ -5984,17 +5257,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        {
          /* Make sure this symbol is output as a dynamic symbol.  */
          if (!ensure_undef_dynamic (info, h))
-           return FALSE;
+           return false;
 
          if (h->dynindx == -1)
-           eh->dyn_relocs = NULL;
+           h->dyn_relocs = NULL;
        }
       else
-       eh->dyn_relocs = NULL;
+       h->dyn_relocs = NULL;
     }
 
   /* Allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  for (p = h->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
       if (eh->elf.type == STT_GNU_IFUNC)
@@ -6002,21 +5275,44 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       sreloc->size += p->count * sizeof (Elf32_External_Rela);
     }
 
-  /* Handle PLT relocs.  Done last, after dynindx has settled.  */
-  dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
-  if (dyn || h->type == STT_GNU_IFUNC)
+  /* Handle PLT relocs.  Done last, after dynindx has settled.
+     We might need a PLT entry when the symbol
+     a) is dynamic, or
+     b) is an ifunc, or
+     c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+     d) has plt16 relocs and we are linking statically.  */
+  if ((htab->elf.dynamic_sections_created && h->dynindx != -1)
+      || h->type == STT_GNU_IFUNC
+      || (h->needs_plt && h->dynamic_adjusted)
+      || (h->needs_plt
+         && h->def_regular
+         && !htab->elf.dynamic_sections_created
+         && !htab->can_convert_all_inline_plt
+         && (ppc_elf_hash_entry (h)->tls_mask
+             & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
     {
       struct plt_entry *ent;
-      bfd_boolean doneone = FALSE;
-      bfd_vma plt_offset = 0, glink_offset = 0;
+      bool doneone = false;
+      bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
 
       for (ent = h->plt.plist; ent != NULL; ent = ent->next)
        if (ent->plt.refcount > 0)
          {
-           asection *s = htab->elf.splt;
+           asection *s;
+           bool dyn;
 
+           if (!ensure_undef_dynamic (info, h))
+             return false;
+
+           dyn = !use_local_plt (info, h);
+           s = htab->elf.splt;
            if (!dyn)
-             s = htab->elf.iplt;
+             {
+               if (h->type == STT_GNU_IFUNC)
+                 s = htab->elf.iplt;
+               else
+                 s = htab->pltlocal;
+             }
 
            if (htab->plt_type == PLT_NEW || !dyn)
              {
@@ -6027,25 +5323,30 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                  }
                ent->plt.offset = plt_offset;
 
-               s = htab->glink;
-               if (!doneone || bfd_link_pic (info))
-                 {
-                   glink_offset = s->size;
-                   s->size += GLINK_ENTRY_SIZE (htab, h);
-                 }
-               if (!doneone
-                   && !bfd_link_pic (info)
-                   && h->def_dynamic
-                   && !h->def_regular)
+               if (s == htab->pltlocal)
+                 ent->glink_offset = glink_offset;
+               else
                  {
-                   h->root.u.def.section = s;
-                   h->root.u.def.value = glink_offset;
-                 }
-               ent->glink_offset = glink_offset;
+                   s = htab->glink;
+                   if (!doneone || bfd_link_pic (info))
+                     {
+                       glink_offset = s->size;
+                       s->size += GLINK_ENTRY_SIZE (htab, h);
+                     }
+                   if (!doneone
+                       && !bfd_link_pic (info)
+                       && h->def_dynamic
+                       && !h->def_regular)
+                     {
+                       h->root.u.def.section = s;
+                       h->root.u.def.value = glink_offset;
+                     }
+                   ent->glink_offset = glink_offset;
 
-               if (htab->params->emit_stub_syms
-                   && !add_stub_sym (ent, h, info))
-                 return FALSE;
+                   if (htab->params->emit_stub_syms
+                       && !add_stub_sym (ent, h, info))
+                     return false;
+                 }
              }
            else
              {
@@ -6098,7 +5399,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            if (!doneone)
              {
                if (!dyn)
-                 htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+                 {
+                   if (h->type == STT_GNU_IFUNC)
+                     {
+                       s = htab->elf.irelplt;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                   else if (bfd_link_pic (info))
+                     {
+                       s = htab->relpltlocal;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                 }
                else
                  {
                    htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
@@ -6127,7 +5439,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                        htab->elf.sgotplt->size += 4;
                      }
                  }
-               doneone = TRUE;
+               doneone = true;
              }
          }
        else
@@ -6145,34 +5457,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       h->needs_plt = 0;
     }
 
-  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 *info_p)
-{
-  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 *) info_p;
-
-      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;
 }
 
 static const unsigned char glink_eh_frame_cie[] =
@@ -6191,13 +5476,13 @@ static const unsigned char glink_eh_frame_cie[] =
 
 /* Set the sizes of the dynamic sections.  */
 
-static bfd_boolean
+static bool
 ppc_elf_size_dynamic_sections (bfd *output_bfd,
                               struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
   asection *s;
-  bfd_boolean relocs;
+  bool relocs;
   bfd *ibfd;
 
 #ifdef DEBUG
@@ -6235,6 +5520,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      Elf_Internal_Sym *isym;
 
       if (!is_ppc_elf (ibfd))
        continue;
@@ -6256,7 +5543,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
-             else if (htab->is_vxworks
+             else if (htab->elf.target_os == is_vxworks
                       && strcmp (p->sec->output_section->name,
                                  ".tls_vars") == 0)
                {
@@ -6291,12 +5578,22 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       local_plt = (struct plt_entry **) end_local_got;
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (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;
+       }
 
-      for (; local_got < end_local_got; ++local_got, ++lgot_masks)
+      for (isym = local_syms;
+          local_got < end_local_got;
+          ++local_got, ++lgot_masks, ++isym)
        if (*local_got > 0)
          {
            unsigned int need;
-           if ((*lgot_masks & TLS_LD) != 0)
+           if ((*lgot_masks & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
              htab->tlsld_got.refcount += 1;
            need = got_entries_needed (*lgot_masks);
            if (need == 0)
@@ -6304,14 +5601,16 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
            else
              {
                *local_got = allocate_got (htab, need);
-               if (bfd_link_pic (info))
+               if (bfd_link_pic (info)
+                   && !((*lgot_masks & TLS_TLS) != 0
+                        && bfd_link_executable (info))
+                   && isym->st_shndx != SHN_ABS)
                  {
                    asection *srel;
-                   bfd_boolean tprel_known = bfd_link_executable (info);
 
-                   need = got_relocs_needed (*lgot_masks, need, tprel_known);
+                   need *= sizeof (Elf32_External_Rela) / 4;
                    srel = htab->elf.srelgot;
-                   if ((*lgot_masks & PLT_IFUNC) != 0)
+                   if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
                      srel = htab->elf.irelplt;
                    srel->size += need;
                  }
@@ -6320,20 +5619,30 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
        else
          *local_got = (bfd_vma) -1;
 
-      if (htab->is_vxworks)
+      if (htab->elf.target_os == is_vxworks)
        continue;
 
       /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
-      for (; local_plt < end_local_plt; ++local_plt)
+      lgot_masks = (char *) end_local_plt;
+      for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
        {
          struct plt_entry *ent;
-         bfd_boolean doneone = FALSE;
-         bfd_vma plt_offset = 0, glink_offset = 0;
+         bool doneone = false;
+         bfd_vma plt_offset = 0, glink_offset = (bfd_vma) -1;
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               s = htab->elf.iplt;
+               if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                 s = htab->elf.iplt;
+               else if (htab->can_convert_all_inline_plt
+                        || (*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+                 {
+                   ent->plt.offset = (bfd_vma) -1;
+                   continue;
+                 }
+               else
+                 s = htab->pltlocal;
 
                if (!doneone)
                  {
@@ -6342,9 +5651,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                  }
                ent->plt.offset = plt_offset;
 
-               s = htab->glink;
-               if (!doneone || bfd_link_pic (info))
+               if (s != htab->pltlocal && (!doneone || bfd_link_pic (info)))
                  {
+                   s = htab->glink;
                    glink_offset = s->size;
                    s->size += GLINK_ENTRY_SIZE (htab, NULL);
                  }
@@ -6352,13 +5661,31 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
                if (!doneone)
                  {
-                   htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
-                   doneone = TRUE;
+                   if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                     {
+                       s = htab->elf.irelplt;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                   else if (bfd_link_pic (info))
+                     {
+                       s = htab->relpltlocal;
+                       s->size += sizeof (Elf32_External_Rela);
+                     }
+                   doneone = true;
                  }
              }
            else
              ent->plt.offset = (bfd_vma) -1;
        }
+
+      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 global sym dynamic relocs.  */
@@ -6367,7 +5694,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->tlsld_got.refcount > 0)
     {
       htab->tlsld_got.offset = allocate_got (htab, 8);
-      if (bfd_link_pic (info))
+      if (bfd_link_dll (info))
        htab->elf.srelgot->size += sizeof (Elf32_External_Rela);
     }
   else
@@ -6426,9 +5753,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
        {
          struct elf_link_hash_entry *sh;
          sh = elf_link_hash_lookup (&htab->elf, "__glink",
-                                    TRUE, FALSE, FALSE);
+                                    true, false, false);
          if (sh == NULL)
-           return FALSE;
+           return false;
          if (sh->root.type == bfd_link_hash_new)
            {
              sh->root.type = bfd_link_hash_defined;
@@ -6442,9 +5769,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
              sh->root.linker_def = 1;
            }
          sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
-                                    TRUE, FALSE, FALSE);
+                                    true, false, false);
          if (sh == NULL)
-           return FALSE;
+           return false;
          if (sh->root.type == bfd_link_hash_new)
            {
              sh->root.type = bfd_link_hash_defined;
@@ -6478,10 +5805,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* We've now determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
-  relocs = FALSE;
+  relocs = false;
   for (s = htab->elf.dynobj->sections; s != NULL; s = s->next)
     {
-      bfd_boolean strip_section = TRUE;
+      bool strip_section = true;
 
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
@@ -6493,11 +5820,12 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
             we've exported dynamic symbols from them we must leave them.
             It's too late to tell BFD to get rid of the symbols.  */
          if (htab->elf.hplt != NULL)
-           strip_section = FALSE;
+           strip_section = false;
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
       else if (s == htab->elf.iplt
+              || s == htab->pltlocal
               || s == htab->glink
               || s == htab->glink_eh_frame
               || s == htab->elf.sgotplt
@@ -6513,13 +5841,12 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
        {
          strip_section = (s->flags & SEC_KEEP) == 0;
        }
-      else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s),
-                            ".rela"))
+      else if (startswith (bfd_section_name (s), ".rela"))
        {
          if (s->size != 0)
            {
              /* Remember whether there are any relocation sections.  */
-             relocs = TRUE;
+             relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -6553,7 +5880,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       /* Allocate memory for the section contents.  */
       s->contents = bfd_zalloc (htab->elf.dynobj, s->size);
       if (s->contents == NULL)
-       return FALSE;
+       return false;
     }
 
   if (htab->elf.dynamic_sections_created)
@@ -6566,56 +5893,22 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (bfd_link_executable (info))
-       {
-         if (!add_dynamic_entry (DT_DEBUG, 0))
-           return FALSE;
-       }
-
-      if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
-       {
-         if (!add_dynamic_entry (DT_PLTGOT, 0)
-             || !add_dynamic_entry (DT_PLTRELSZ, 0)
-             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
-             || !add_dynamic_entry (DT_JMPREL, 0))
-           return FALSE;
-       }
+      if (!_bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info,
+                                                   relocs))
+       return false;
 
       if (htab->plt_type == PLT_NEW
          && htab->glink != NULL
          && htab->glink->size != 0)
        {
          if (!add_dynamic_entry (DT_PPC_GOT, 0))
-           return FALSE;
+           return false;
          if (!htab->params->no_tls_get_addr_opt
              && htab->tls_get_addr != NULL
              && htab->tls_get_addr->plt.plist != NULL
              && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
-           return FALSE;
+           return false;
        }
-
-      if (relocs)
-       {
-         if (!add_dynamic_entry (DT_RELA, 0)
-             || !add_dynamic_entry (DT_RELASZ, 0)
-             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
-           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 (elf_hash_table (info), maybe_set_textrel,
-                               info);
-
-      if ((info->flags & DF_TEXTREL) != 0)
-       {
-         if (!add_dynamic_entry (DT_TEXTREL, 0))
-           return FALSE;
-       }
-      if (htab->is_vxworks
-         && !elf_vxworks_add_dynamic_entries (output_bfd, info))
-       return FALSE;
    }
 #undef add_dynamic_entry
 
@@ -6679,7 +5972,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                  == htab->glink_eh_frame->size);
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output
@@ -6724,14 +6017,14 @@ ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info)
 
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
-static bfd_boolean
+static bool
 ppc_elf_hash_symbol (struct elf_link_hash_entry *h)
 {
   if (h->plt.plist != NULL
       && !h->def_regular
       && (!h->pointer_equality_needed
          || !h->ref_regular_nonweak))
-    return FALSE;
+    return false;
 
   return _bfd_elf_hash_symbol (h);
 }
@@ -6771,11 +6064,11 @@ struct ppc_elf_relax_info
    space for the workaround has its size extended so that we can
    add trampolines at the end of the section.  */
 
-static bfd_boolean
+static bool
 ppc_elf_relax_section (bfd *abfd,
                       asection *isec,
                       struct bfd_link_info *link_info,
-                      bfd_boolean *again)
+                      bool *again)
 {
   struct one_branch_fixup
   {
@@ -6795,30 +6088,30 @@ ppc_elf_relax_section (bfd *abfd,
   struct one_branch_fixup *branch_fixups = NULL;
   struct ppc_elf_relax_info *relax_info = NULL;
   unsigned changes = 0;
-  bfd_boolean workaround_change;
+  bool workaround_change;
   struct ppc_elf_link_hash_table *htab;
   bfd_size_type trampbase, trampoff, newsize, picfixup_size;
   asection *got2;
-  bfd_boolean maybe_pasted;
+  bool maybe_pasted;
 
-  *again = FALSE;
+  *again = false;
 
   /* No need to do anything with non-alloc or non-code sections.  */
   if ((isec->flags & SEC_ALLOC) == 0
       || (isec->flags & SEC_CODE) == 0
       || (isec->flags & SEC_LINKER_CREATED) != 0
       || isec->size < 4)
-    return TRUE;
+    return true;
 
   /* We cannot represent the required PIC relocs in the output, so don't
      do anything.  The linker doesn't support mixing -shared and -r
      anyway.  */
   if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info))
-    return TRUE;
+    return true;
 
   htab = ppc_elf_hash_table (link_info);
   if (htab == NULL)
-    return TRUE;
+    return true;
 
   isec->size = (isec->size + 3) & -4;
   if (isec->rawsize == 0)
@@ -6837,7 +6130,7 @@ ppc_elf_relax_section (bfd *abfd,
          elf_section_data (isec)->sec_info
            = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info));
          if (elf_section_data (isec)->sec_info == NULL)
-           return FALSE;
+           return false;
        }
       relax_info = elf_section_data (isec)->sec_info;
       trampbase -= relax_info->workaround_size;
@@ -6878,6 +6171,7 @@ ppc_elf_relax_section (bfd *abfd,
          bfd_byte *hit_addr;
          unsigned long t0;
          struct elf_link_hash_entry *h;
+         Elf_Internal_Sym *isym;
          struct plt_entry **plist;
          unsigned char sym_type;
 
@@ -6886,6 +6180,7 @@ ppc_elf_relax_section (bfd *abfd,
            case R_PPC_REL24:
            case R_PPC_LOCAL24PC:
            case R_PPC_PLTREL24:
+           case R_PPC_PLTCALL:
              max_branch_offset = 1 << 25;
              break;
 
@@ -6905,57 +6200,32 @@ ppc_elf_relax_section (bfd *abfd,
            }
 
          /* Get the value of the symbol referred to by the reloc.  */
-         h = NULL;
-         if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
-           {
-             /* A local symbol.  */
-             Elf_Internal_Sym *isym;
+         if (!get_sym_h (&h, &isym, &tsec, NULL, &isymbuf,
+                         ELF32_R_SYM (irel->r_info), abfd))
+           goto error_return;
 
-             /* Read this BFD's local symbols.  */
-             if (isymbuf == NULL)
-               {
-                 isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
-                 if (isymbuf == NULL)
-                   isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
-                                                   symtab_hdr->sh_info, 0,
-                                                   NULL, NULL, NULL);
-                 if (isymbuf == 0)
-                   goto error_return;
-               }
-             isym = isymbuf + ELF32_R_SYM (irel->r_info);
-             if (isym->st_shndx == SHN_UNDEF)
-               tsec = bfd_und_section_ptr;
+         if (isym != NULL)
+           {
+             if (tsec != NULL)
+               ;
              else if (isym->st_shndx == SHN_ABS)
                tsec = bfd_abs_section_ptr;
-             else if (isym->st_shndx == SHN_COMMON)
-               tsec = bfd_com_section_ptr;
              else
-               tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+               continue;
 
              toff = isym->st_value;
              sym_type = ELF_ST_TYPE (isym->st_info);
            }
          else
            {
-             /* Global symbol handling.  */
-             unsigned long indx;
-
-             indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
-             h = elf_sym_hashes (abfd)[indx];
-
-             while (h->root.type == bfd_link_hash_indirect
-                    || h->root.type == bfd_link_hash_warning)
-               h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
-             if (h->root.type == bfd_link_hash_defined
-                 || h->root.type == bfd_link_hash_defweak)
-               {
-                 tsec = h->root.u.def.section;
-                 toff = h->root.u.def.value;
-               }
+             if (tsec != NULL)
+               toff = h->root.u.def.value;
              else if (h->root.type == bfd_link_hash_undefined
                       || h->root.type == bfd_link_hash_undefweak)
                {
+                 unsigned long indx;
+
+                 indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
                  tsec = bfd_und_section_ptr;
                  toff = bfd_link_relocatable (link_info) ? indx : 0;
                }
@@ -7083,6 +6353,17 @@ ppc_elf_relax_section (bfd *abfd,
          if (tsec == isec)
            continue;
 
+         /* toff is used for the symbol index when the symbol is
+            undefined and we're doing a relocatable link, so we can't
+            support addends.  It would be possible to do so by
+            putting the addend in one_branch_fixup but addends on
+            branches are rare so it hardly seems worth supporting.  */
+         if (bfd_link_relocatable (link_info)
+             && tsec == bfd_und_section_ptr
+             && r_type != R_PPC_PLTREL24
+             && irel->r_addend != 0)
+           continue;
+
          /* There probably isn't any reason to handle symbols in
             SEC_MERGE sections;  SEC_MERGE doesn't seem a likely
             attribute for a code section, and we are only looking at
@@ -7106,7 +6387,8 @@ ppc_elf_relax_section (bfd *abfd,
                 a section symbol should not include the addend;  Such an
                 access is presumed to be an offset from "sym";  The
                 location of interest is just "sym".  */
-             if (sym_type == STT_SECTION)
+             if (sym_type == STT_SECTION
+                 && r_type != R_PPC_PLTREL24)
                toff += irel->r_addend;
 
              toff
@@ -7114,7 +6396,8 @@ ppc_elf_relax_section (bfd *abfd,
                                              elf_section_data (tsec)->sec_info,
                                              toff);
 
-             if (sym_type != STT_SECTION)
+             if (sym_type != STT_SECTION
+                 && r_type != R_PPC_PLTREL24)
                toff += irel->r_addend;
            }
          /* PLTREL24 addends are special.  */
@@ -7131,6 +6414,16 @@ ppc_elf_relax_section (bfd *abfd,
 
          roff = irel->r_offset;
 
+         /* Avoid creating a lot of unnecessary fixups when
+            relocatable if the output section size is such that a
+            fixup can be created at final link.
+            The max_branch_offset adjustment allows for some number
+            of other fixups being needed at final link.  */
+         if (bfd_link_relocatable (link_info)
+             && (isec->output_section->rawsize - (isec->output_offset + roff)
+                 < max_branch_offset - (max_branch_offset >> 4)))
+           continue;
+
          /* If the branch is in range, no need to do anything.  */
          if (tsec != bfd_und_section_ptr
              && (!bfd_link_relocatable (link_info)
@@ -7255,7 +6548,7 @@ ppc_elf_relax_section (bfd *abfd,
        }
     }
 
-  workaround_change = FALSE;
+  workaround_change = false;
   newsize = trampoff;
   if (htab->params->ppc476_workaround
       && (!bfd_link_relocatable (link_info)
@@ -7279,7 +6572,7 @@ ppc_elf_relax_section (bfd *abfd,
          if (relax_info->workaround_size < newsize)
            {
              relax_info->workaround_size = newsize;
-             workaround_change = TRUE;
+             workaround_change = true;
            }
          /* Ensure relocate_section is called.  */
          isec->flags |= SEC_RELOC;
@@ -7349,12 +6642,11 @@ ppc_elf_relax_section (bfd *abfd,
       rel_hdr = _bfd_elf_single_rel_hdr (isec);
       rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
     }
-  else if (internal_relocs != NULL
-          && elf_section_data (isec)->relocs != internal_relocs)
+  else if (elf_section_data (isec)->relocs != internal_relocs)
     free (internal_relocs);
 
   *again = changes != 0 || workaround_change;
-  return TRUE;
+  return true;
 
  error_return:
   while (branch_fixups != NULL)
@@ -7363,15 +6655,13 @@ ppc_elf_relax_section (bfd *abfd,
       branch_fixups = branch_fixups->next;
       free (f);
     }
-  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+  if ((unsigned char *) isymbuf != symtab_hdr->contents)
     free (isymbuf);
-  if (contents != NULL
-      && elf_section_data (isec)->this_hdr.contents != contents)
+  if (elf_section_data (isec)->this_hdr.contents != contents)
     free (contents);
-  if (internal_relocs != NULL
-      && elf_section_data (isec)->relocs != internal_relocs)
+  if (elf_section_data (isec)->relocs != internal_relocs)
     free (internal_relocs);
-  return FALSE;
+  return false;
 }
 \f
 /* What to do when ld finds relocations against symbols defined in
@@ -7532,7 +6822,7 @@ write_glink_stub (struct elf_link_hash_entry *h, struct plt_entry *ent,
 
 /* Return true if symbol is defined statically.  */
 
-static bfd_boolean
+static bool
 is_static_defined (struct elf_link_hash_entry *h)
 {
   return ((h->root.type == bfd_link_hash_defined
@@ -7550,7 +6840,7 @@ _bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
 {
   unsigned int rtra;
 
-  if ((insn & (0x3f << 26)) != 31 << 26)
+  if ((insn & (0x3fu << 26)) != 31 << 26)
     return 0;
 
   if (reg == 0 || ((insn >> 11) & 0x1f) == reg)
@@ -7568,13 +6858,13 @@ _bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
               || ((insn & (0x1f << 6)) >= 16 << 6
                   && (insn & (0x1f << 6)) < 24 << 6)))
     /* load and store indexed -> dform.  */
-    insn = (32 | ((insn >> 6) & 0x1f)) << 26;
+    insn = (32u | ((insn >> 6) & 0x1f)) << 26;
   else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1)
     /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
-    insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
+    insn = ((58u | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
   else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1)
     /* lwax -> lwa.  */
-    insn = (58 << 26) | 2;
+    insn = (58u << 26) | 2;
   else
     return 0;
   insn |= rtra;
@@ -7589,36 +6879,36 @@ unsigned int
 _bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
 {
   if ((insn & (0x1f << 16)) == reg << 16
-      && ((insn & (0x3f << 26)) == 14u << 26 /* addi */
-         || (insn & (0x3f << 26)) == 15u << 26 /* addis */
-         || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
-         || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
-         || (insn & (0x3f << 26)) == 36u << 26 /* stw */
-         || (insn & (0x3f << 26)) == 38u << 26 /* stb */
-         || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
-         || (insn & (0x3f << 26)) == 42u << 26 /* lha */
-         || (insn & (0x3f << 26)) == 44u << 26 /* sth */
-         || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
-         || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
-         || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
-         || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
-         || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
-         || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
-         || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+      && ((insn & (0x3fu << 26)) == 14u << 26 /* addi */
+         || (insn & (0x3fu << 26)) == 15u << 26 /* addis */
+         || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */
+         || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */
+         || (insn & (0x3fu << 26)) == 36u << 26 /* stw */
+         || (insn & (0x3fu << 26)) == 38u << 26 /* stb */
+         || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */
+         || (insn & (0x3fu << 26)) == 42u << 26 /* lha */
+         || (insn & (0x3fu << 26)) == 44u << 26 /* sth */
+         || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */
+         || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */
+         || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */
+         || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */
+         || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */
+         || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */
+         || ((insn & (0x3fu << 26)) == 58u << 26 /* lwa,ld,lmd */
              && (insn & 3) != 1)
-         || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+         || ((insn & (0x3fu << 26)) == 62u << 26 /* std, stmd */
              && ((insn & 3) == 0 || (insn & 3) == 3))))
     {
       insn &= ~(0x1f << 16);
     }
   else if ((insn & (0x1f << 21)) == reg << 21
-          && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */
-              || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */
-              || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */))
+          && ((insn & (0x3eu << 26)) == 24u << 26 /* ori, oris */
+              || (insn & (0x3eu << 26)) == 26u << 26 /* xori,xoris */
+              || (insn & (0x3eu << 26)) == 28u << 26 /* andi,andis */))
     {
       insn &= ~(0x1f << 21);
       insn |= (insn & (0x1f << 16)) << 5;
-      if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */)
+      if ((insn & (0x3eu << 26)) == 26u << 26 /* xori,xoris */)
        insn -= 2 >> 26;  /* convert to ori,oris */
     }
   else
@@ -7626,20 +6916,20 @@ _bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
   return insn;
 }
 
-static bfd_boolean
+static bool
 is_insn_ds_form (unsigned int insn)
 {
-  return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */
-         || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */
-         || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */
-         || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */);
+  return ((insn & (0x3fu << 26)) == 58u << 26 /* ld,ldu,lwa */
+         || (insn & (0x3fu << 26)) == 62u << 26 /* std,stdu,stq */
+         || (insn & (0x3fu << 26)) == 57u << 26 /* lfdp */
+         || (insn & (0x3fu << 26)) == 61u << 26 /* stfdp */);
 }
 
-static bfd_boolean
+static bool
 is_insn_dq_form (unsigned int insn)
 {
-  return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
-         || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+  return ((insn & (0x3fu << 26)) == 56u << 26 /* lq */
+         || ((insn & (0x3fu << 26)) == (61u << 26) /* lxv, stxv */
              && (insn & 3) == 1));
 }
 
@@ -7672,7 +6962,7 @@ is_insn_dq_form (unsigned int insn)
    section, which means that the addend must be adjusted
    accordingly.  */
 
-static bfd_boolean
+static int
 ppc_elf_relocate_section (bfd *output_bfd,
                          struct bfd_link_info *info,
                          bfd *input_bfd,
@@ -7691,9 +6981,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Rela outrel;
   asection *got2;
   bfd_vma *local_got_offsets;
-  bfd_boolean ret = TRUE;
+  bool ret = true;
   bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
-  bfd_boolean is_vxworks_tls;
+  bool is_vxworks_tls;
   unsigned int picfixup_size = 0;
   struct ppc_elf_relax_info *relax_info = NULL;
 
@@ -7705,6 +6995,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      (bfd_link_relocatable (info)) ? " (relocatable)" : "");
 #endif
 
+  if (!is_ppc_elf (input_bfd))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return false;
+    }
+
   got2 = bfd_get_section_by_name (input_bfd, ".got2");
 
   /* Initialize howto table if not already done.  */
@@ -7717,7 +7013,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
   sym_hashes = elf_sym_hashes (input_bfd);
   /* We have to handle relocations in vxworks .tls_vars sections
      specially, because the dynamic loader is 'weird'.  */
-  is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
+  is_vxworks_tls = (htab->elf.target_os == is_vxworks && bfd_link_pic (info)
                    && !strcmp (input_section->output_section->name,
                                ".tls_vars"));
   if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
@@ -7737,10 +7033,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
       unsigned long r_symndx;
       bfd_vma relocation;
       bfd_vma branch_bit, from;
-      bfd_boolean unresolved_reloc;
-      bfd_boolean warned;
+      bool unresolved_reloc, save_unresolved_reloc;
+      bool warned;
       unsigned int tls_type, tls_mask, tls_gd;
-      struct plt_entry **ifunc;
+      struct plt_entry **ifunc, **plt_list;
       struct reloc_howto_struct alt_howto;
 
     again:
@@ -7748,8 +7044,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
       sym = NULL;
       sec = NULL;
       h = NULL;
-      unresolved_reloc = FALSE;
-      warned = FALSE;
+      unresolved_reloc = false;
+      warned = false;
       r_symndx = ELF32_R_SYM (rel->r_info);
 
       if (r_symndx < symtab_hdr->sh_info)
@@ -7762,7 +7058,7 @@ ppc_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,
@@ -7782,7 +7078,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
            howto = ppc_elf_howto_table[r_type];
 
          _bfd_clear_contents (howto, input_bfd, input_section,
-                              contents + rel->r_offset);
+                              contents, rel->r_offset);
          wrel->r_offset = rel->r_offset;
          wrel->r_info = 0;
          wrel->r_addend = 0;
@@ -7850,7 +7146,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16_LO:
          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))
            {
              bfd_vma insn;
 
@@ -7867,7 +7164,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_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, 4))
            {
              bfd_vma insn;
 
@@ -7887,14 +7185,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_GOT_TLSGD16_HI:
        case R_PPC_GOT_TLSGD16_HA:
-         tls_gd = TLS_TPRELGD;
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+         tls_gd = TLS_GDIE;
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && offset_in_range (input_section, rel->r_offset - d_offset, 4))
            goto tls_gdld_hi;
          break;
 
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_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 - d_offset, 4))
            {
            tls_gdld_hi:
              if ((tls_mask & tls_gd) != 0)
@@ -7912,14 +7212,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_GOT_TLSGD16:
        case R_PPC_GOT_TLSGD16_LO:
-         tls_gd = TLS_TPRELGD;
-         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
+         tls_gd = TLS_GDIE;
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && offset_in_range (input_section, rel->r_offset - d_offset, 4))
            goto tls_ldgd_opt;
          break;
 
        case R_PPC_GOT_TLSLD16:
        case R_PPC_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 - d_offset, 4))
            {
              unsigned int insn1, insn2;
              bfd_vma offset;
@@ -7931,7 +7233,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 stays with its arg setup insns, ie. that the next
                 reloc is the __tls_get_addr call associated with
                 the current reloc.  Edit both insns.  */
-             if (input_section->has_tls_get_addr_call
+             if (input_section->nomark_tls_get_addr
                  && rel + 1 < relend
                  && branch_reloc_hash_match (input_bfd, rel + 1,
                                              htab->tls_get_addr))
@@ -7946,8 +7248,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  /* IE */
                  insn1 &= (0x1f << 21) | (0x1f << 16);
-                 insn1 |= 32 << 26;    /* lwz */
-                 if (offset != (bfd_vma) -1)
+                 insn1 |= 32u << 26;   /* lwz */
+                 if (offset != (bfd_vma) -1
+                     && offset_in_range (input_section, offset, 4))
                    {
                      rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
                      insn2 = 0x7c631214;       /* add 3,3,2 */
@@ -7980,7 +7283,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    }
                  r_type = R_PPC_TPREL16_HA;
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
-                 if (offset != (bfd_vma) -1)
+                 if (offset != (bfd_vma) -1
+                     && offset_in_range (input_section, offset, 4))
                    {
                      rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
                      rel[1].r_offset = offset + d_offset;
@@ -8002,12 +7306,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_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, 4))
            {
              unsigned int insn2;
              bfd_vma offset = rel->r_offset;
 
-             if ((tls_mask & TLS_TPRELGD) != 0)
+             if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+               {
+                 bfd_put_32 (input_bfd, NOP, contents + offset);
+                 rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+                 break;
+               }
+
+             if ((tls_mask & TLS_GDIE) != 0)
                {
                  /* IE */
                  r_type = R_PPC_NONE;
@@ -8030,10 +7342,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_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, 4))
            {
              unsigned int insn2;
 
+             if (is_plt_seq_reloc (ELF32_R_TYPE (rel[1].r_info)))
+               {
+                 bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
+                 rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
+                 break;
+               }
+
              for (r_symndx = 0;
                   r_symndx < symtab_hdr->sh_info;
                   r_symndx++)
@@ -8076,24 +7396,51 @@ ppc_elf_relocate_section (bfd *output_bfd,
          /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
-         {
-           bfd_vma insn;
+         if (offset_in_range (input_section, rel->r_offset, 4))
+           {
+             unsigned int insn;
 
-           insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
-           insn &= ~BRANCH_PREDICT_BIT;
-           insn |= branch_bit;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~BRANCH_PREDICT_BIT;
+             insn |= branch_bit;
 
-           from = (rel->r_offset
-                   + input_section->output_offset
-                   + input_section->output_section->vma);
+             from = (rel->r_offset
+                     + input_section->output_offset
+                     + input_section->output_section->vma);
 
-           /* Invert 'y' bit if not the default.  */
-           if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
-             insn ^= BRANCH_PREDICT_BIT;
+             /* Invert 'y' bit if not the default.  */
+             if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
+               insn ^= BRANCH_PREDICT_BIT;
 
-           bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
-           break;
-         }
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+           }
+         break;
+
+       case R_PPC_PLT16_HA:
+         if (offset_in_range (input_section, rel->r_offset - d_offset, 4))
+           {
+             unsigned int insn;
+
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
+             if ((insn & (0x3fu << 26)) == 15u << 26
+                 && (insn & (0x1f << 16)) != 0)
+               {
+                 if (!bfd_link_pic (info))
+                   {
+                     /* Convert addis to lis.  */
+                     insn &= ~(0x1f << 16);
+                     bfd_put_32 (input_bfd, insn,
+                                 contents + rel->r_offset - d_offset);
+                   }
+               }
+             else if (bfd_link_pic (info))
+               info->callbacks->einfo
+                 (_("%P: %H: error: %s with unexpected instruction %x\n"),
+                  input_bfd, input_section, rel->r_offset,
+                  "R_PPC_PLT16_HA", insn);
+           }
+         break;
        }
 
       if (ELIMINATE_COPY_RELOCS
@@ -8108,11 +7455,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
             variable defined in a shared library to PIC.  */
          unsigned int insn;
 
-         if (r_type == R_PPC_ADDR16_HA)
+         if (r_type == R_PPC_ADDR16_HA
+             && 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 & (0x3f << 26)) == (15u << 26)
+             if ((insn & (0x3fu << 26)) == (15u << 26)
                  && (insn & (0x1f << 16)) == 0 /* lis */)
                {
                  bfd_byte *p;
@@ -8171,32 +7519,34 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   input_bfd, input_section, (uint64_t) rel->r_offset,
                   "R_PPC_ADDR16_HA", insn);
            }
-         else if (r_type == R_PPC_ADDR16_LO)
+         else if (r_type == R_PPC_ADDR16_LO
+                  && 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 & (0x3f << 26)) == 14u << 26    /* addi */
-                 || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
-                 || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
-                 || (insn & (0x3f << 26)) == 36u << 26 /* stw */
-                 || (insn & (0x3f << 26)) == 38u << 26 /* stb */
-                 || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
-                 || (insn & (0x3f << 26)) == 42u << 26 /* lha */
-                 || (insn & (0x3f << 26)) == 44u << 26 /* sth */
-                 || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
-                 || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
-                 || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
-                 || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
-                 || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
-                 || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
-                 || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+             if ((insn & (0x3fu << 26)) == 14u << 26    /* addi */
+                 || (insn & (0x3fu << 26)) == 32u << 26 /* lwz */
+                 || (insn & (0x3fu << 26)) == 34u << 26 /* lbz */
+                 || (insn & (0x3fu << 26)) == 36u << 26 /* stw */
+                 || (insn & (0x3fu << 26)) == 38u << 26 /* stb */
+                 || (insn & (0x3fu << 26)) == 40u << 26 /* lhz */
+                 || (insn & (0x3fu << 26)) == 42u << 26 /* lha */
+                 || (insn & (0x3fu << 26)) == 44u << 26 /* sth */
+                 || (insn & (0x3fu << 26)) == 46u << 26 /* lmw */
+                 || (insn & (0x3fu << 26)) == 47u << 26 /* stmw */
+                 || (insn & (0x3fu << 26)) == 48u << 26 /* lfs */
+                 || (insn & (0x3fu << 26)) == 50u << 26 /* lfd */
+                 || (insn & (0x3fu << 26)) == 52u << 26 /* stfs */
+                 || (insn & (0x3fu << 26)) == 54u << 26 /* stfd */
+                 || ((insn & (0x3fu << 26)) == 58u << 26 /* lwa,ld,lmd */
                      && (insn & 3) != 1)
-                 || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+                 || ((insn & (0x3fu << 26)) == 62u << 26 /* std, stmd */
                      && ((insn & 3) == 0 || (insn & 3) == 3)))
                {
                  /* Arrange to apply the reloc addend, if any.  */
                  relocation = 0;
-                 unresolved_reloc = FALSE;
+                 unresolved_reloc = false;
                  rel->r_info = ELF32_R_INFO (0, r_type);
                }
              else
@@ -8210,7 +7560,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        }
 
       ifunc = NULL;
-      if (!htab->is_vxworks)
+      if (htab->elf.target_os != is_vxworks)
        {
          struct plt_entry *ent;
 
@@ -8232,10 +7582,17 @@ ppc_elf_relocate_section (bfd *output_bfd,
          ent = NULL;
          if (ifunc != NULL
              && (!bfd_link_pic (info)
-                 || is_branch_reloc (r_type)))
+                 || is_branch_reloc (r_type)
+                 || r_type == R_PPC_PLT16_LO
+                 || r_type == R_PPC_PLT16_HI
+                 || r_type == R_PPC_PLT16_HA))
            {
              addend = 0;
-             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
+             if (bfd_link_pic (info)
+                 && (r_type == R_PPC_PLTREL24
+                     || r_type == R_PPC_PLT16_LO
+                     || r_type == R_PPC_PLT16_HI
+                     || r_type == R_PPC_PLT16_HA))
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
            }
@@ -8262,34 +7619,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
                       input_bfd, input_section, rel->r_offset, sym_name);
                }
-             if (h == NULL && (ent->plt.offset & 1) == 0)
-               {
-                 Elf_Internal_Rela rela;
-                 bfd_byte *loc;
-
-                 rela.r_offset = (htab->elf.iplt->output_section->vma
-                                  + htab->elf.iplt->output_offset
-                                  + ent->plt.offset);
-                 rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
-                 rela.r_addend = relocation;
-                 loc = htab->elf.irelplt->contents;
-                 loc += (htab->elf.irelplt->reloc_count++
-                         * sizeof (Elf32_External_Rela));
-                 bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-                 htab->local_ifunc_resolver = 1;
-
-                 ent->plt.offset |= 1;
-               }
-             if (h == NULL && (ent->glink_offset & 1) == 0)
-               {
-                 unsigned char *p = ((unsigned char *) htab->glink->contents
-                                     + ent->glink_offset);
-
-                 write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
-                 ent->glink_offset |= 1;
-               }
 
-             unresolved_reloc = FALSE;
+             unresolved_reloc = false;
              if (htab->plt_type == PLT_NEW
                  || !htab->elf.dynamic_sections_created
                  || h == NULL
@@ -8305,53 +7636,27 @@ ppc_elf_relocate_section (bfd *output_bfd,
        }
 
       addend = rel->r_addend;
+      save_unresolved_reloc = unresolved_reloc;
       howto = NULL;
       if (r_type < R_PPC_max)
        howto = ppc_elf_howto_table[r_type];
 
-      switch (r_type)
-       {
-       default:
-         break;
-
-       case R_PPC_TPREL16_HA:
-         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
-           {
-             bfd_byte *p = contents + (rel->r_offset & ~3);
-             unsigned int insn = bfd_get_32 (input_bfd, p);
-             if ((insn & ((0x3f << 26) | 0x1f << 16))
-                 != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
-               /* xgettext:c-format */
-               info->callbacks->minfo
-                 (_("%H: warning: %s unexpected insn %#x.\n"),
-                  input_bfd, input_section, rel->r_offset, howto->name, insn);
-             else
-               bfd_put_32 (input_bfd, NOP, p);
-           }
-         break;
-
-       case R_PPC_TPREL16_LO:
-         if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
-           {
-             bfd_byte *p = contents + (rel->r_offset & ~3);
-             unsigned int insn = bfd_get_32 (input_bfd, p);
-             insn &= ~(0x1f << 16);
-             insn |= 2 << 16;
-             bfd_put_32 (input_bfd, insn, p);
-           }
-         break;
-       }
-
       tls_type = 0;
       switch (r_type)
        {
        default:
-         /* xgettext:c-format */
-         _bfd_error_handler (_("%pB: %s unsupported"),
-                             input_bfd, howto->name);
+       de_fault:
+         if (howto)
+           /* xgettext:c-format */
+           _bfd_error_handler (_("%pB: %s unsupported"),
+                               input_bfd, howto->name);
+         else
+           /* xgettext:c-format */
+           _bfd_error_handler (_("%pB: reloc %#x unsupported"),
+                               input_bfd, r_type);
 
          bfd_set_error (bfd_error_bad_value);
-         ret = FALSE;
+         ret = false;
          goto copy_reloc;
 
        case R_PPC_NONE:
@@ -8413,8 +7718,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
            indx = 0;
            if (tls_type == (TLS_TLS | TLS_LD)
-               && (h == NULL
-                   || !h->def_dynamic))
+               && SYMBOL_REFERENCES_LOCAL (info, h))
              offp = &htab->tlsld_got.offset;
            else if (h != NULL)
              {
@@ -8430,7 +7734,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                else
                  {
                    indx = h->dynindx;
-                   unresolved_reloc = FALSE;
+                   unresolved_reloc = false;
                  }
                offp = &h->got.offset;
              }
@@ -8449,14 +7753,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
              off &= ~1;
            else
              {
-               unsigned int tls_m = (tls_mask
-                                     & (TLS_LD | TLS_GD | TLS_DTPREL
-                                        | TLS_TPREL | TLS_TPRELGD));
+               unsigned int tls_m = ((tls_mask & TLS_TLS) != 0
+                                     ? tls_mask & (TLS_LD | TLS_GD | TLS_DTPREL
+                                                   | TLS_TPREL | TLS_GDIE)
+                                     : 0);
 
                if (offp == &htab->tlsld_got.offset)
                  tls_m = TLS_LD;
-               else if (h == NULL
-                        || !h->def_dynamic)
+               else if ((tls_m & TLS_LD) != 0
+                        && SYMBOL_REFERENCES_LOCAL (info, h))
                  tls_m &= ~TLS_LD;
 
                /* We might have multiple got entries for this sym.
@@ -8480,7 +7785,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                        tls_ty = TLS_TLS | TLS_DTPREL;
                        tls_m &= ~TLS_DTPREL;
                      }
-                   else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0)
+                   else if ((tls_m & (TLS_TPREL | TLS_GDIE)) != 0)
                      {
                        tls_ty = TLS_TLS | TLS_TPREL;
                        tls_m = 0;
@@ -8490,11 +7795,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    if (indx != 0
                        || (bfd_link_pic (info)
                            && (h == NULL
-                               || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
-                               || offp == &htab->tlsld_got.offset)
-                           && !(tls_ty == (TLS_TLS | TLS_TPREL)
+                               || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+                           && !(tls_ty != 0
                                 && bfd_link_executable (info)
-                                && SYMBOL_REFERENCES_LOCAL (info, h))))
+                                && SYMBOL_REFERENCES_LOCAL (info, h))
+                           && (h != NULL
+                               ? !bfd_is_abs_symbol (&h->root)
+                               : sym->st_shndx != SHN_ABS)))
                      {
                        asection *rsec = htab->elf.srelgot;
                        bfd_byte * loc;
@@ -8602,8 +7909,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                if (tls_type != (TLS_TLS | TLS_LD))
                  {
                    if ((tls_mask & TLS_LD) != 0
-                       && !(h == NULL
-                            || !h->def_dynamic))
+                       && !SYMBOL_REFERENCES_LOCAL (info, h))
                      off += 8;
                    if (tls_type != (TLS_TLS | TLS_GD))
                      {
@@ -8652,7 +7958,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                                    input_bfd,
                                                    input_section,
                                                    rel->r_offset,
-                                                   TRUE);
+                                                   true);
              goto copy_reloc;
            }
          if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info))
@@ -8688,7 +7994,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_TPREL16_HA:
          if (h != NULL
              && h->root.type == bfd_link_hash_undefweak
-             && h->dynindx == -1)
+             && h->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
@@ -8773,11 +8080,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
          if (bfd_link_pic (info)
              ? ((h == NULL
-                 || ppc_elf_hash_entry (h)->dyn_relocs != NULL)
+                 || h->dyn_relocs != NULL)
                 && ((h != NULL && pc_dynrelocs (h))
                     || must_be_dyn_reloc (info, r_type)))
              : (h != NULL
-                && ppc_elf_hash_entry (h)->dyn_relocs != NULL))
+                && h->dyn_relocs != NULL))
            {
              int skip;
              bfd_byte *loc;
@@ -8804,13 +8111,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
 
+             /* Optimize unaligned reloc use.  */
+             if ((r_type == R_PPC_ADDR32 && (outrel.r_offset & 3) != 0)
+                 || (r_type == R_PPC_UADDR32 && (outrel.r_offset & 3) == 0))
+               r_type ^= R_PPC_ADDR32 ^ R_PPC_UADDR32;
+             if ((r_type == R_PPC_ADDR16 && (outrel.r_offset & 1) != 0)
+                 || (r_type == R_PPC_UADDR16 && (outrel.r_offset & 1) == 0))
+               r_type ^= R_PPC_ADDR16 ^ R_PPC_UADDR16;
+
              if (skip)
                memset (&outrel, 0, sizeof outrel);
              else if (!SYMBOL_REFERENCES_LOCAL (info, h))
                {
                  indx = h->dynindx;
                  BFD_ASSERT (indx != -1);
-                 unresolved_reloc = FALSE;
+                 unresolved_reloc = false;
                  outrel.r_info = ELF32_R_INFO (indx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
@@ -8841,14 +8156,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
                             input_bfd, input_section, rel->r_offset,
                             howto->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);
-                         ret = FALSE;
+                         ret = false;
                        }
                      else
                        {
@@ -8861,19 +8176,27 @@ ppc_elf_relocate_section (bfd *output_bfd,
                             but ld.so expects buggy relocs.
                             FIXME: Why not always use a zero index?  */
                          osec = sec->output_section;
-                         indx = elf_section_data (osec)->dynindx;
-                         if (indx == 0)
+                         if ((osec->flags & SEC_THREAD_LOCAL) != 0)
+                           {
+                             osec = htab->elf.tls_sec;
+                             indx = 0;
+                           }
+                         else
                            {
-                             osec = htab->elf.text_index_section;
                              indx = elf_section_data (osec)->dynindx;
+                             if (indx == 0)
+                               {
+                                 osec = htab->elf.text_index_section;
+                                 indx = elf_section_data (osec)->dynindx;
+                               }
+                             BFD_ASSERT (indx != 0);
                            }
-                         BFD_ASSERT (indx != 0);
-#ifdef DEBUG
-                         if (indx == 0)
-                           printf ("indx=%ld section=%s flags=%08x name=%s\n",
-                                   indx, osec->name, osec->flags,
-                                   h->root.root.string);
-#endif
+
+                         /* ld.so doesn't expect buggy TLS relocs.
+                            Don't leave the symbol value in the
+                            addend for them.  */
+                         if (IS_PPC_TLS_RELOC (r_type))
+                           outrel.r_addend -= osec->vma;
                        }
 
                      outrel.r_info = ELF32_R_INFO (indx, r_type);
@@ -8894,7 +8217,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    htab->maybe_local_ifunc_resolver = 1;
                }
              if (sreloc == NULL)
-               return FALSE;
+               return false;
 
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
@@ -8940,66 +8263,73 @@ ppc_elf_relocate_section (bfd *output_bfd,
          /* Fall through.  */
 
        case R_PPC_RELAX:
-         {
-           const int *stub;
-           size_t size;
-           size_t insn_offset = rel->r_offset;
-           unsigned int insn;
-
-           if (bfd_link_pic (info))
-             {
-               relocation -= (input_section->output_section->vma
-                              + input_section->output_offset
-                              + rel->r_offset - 4);
-               stub = shared_stub_entry;
-               bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12);
-               bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8);
-               bfd_put_32 (input_bfd, stub[2], contents + insn_offset - 4);
-               stub += 3;
-               size = ARRAY_SIZE (shared_stub_entry) - 3;
-             }
-           else
-             {
-               stub = stub_entry;
-               size = ARRAY_SIZE (stub_entry);
-             }
-
-           relocation += addend;
-           if (bfd_link_relocatable (info))
-             relocation = 0;
-
-           /* First insn is HA, second is LO.  */
-           insn = *stub++;
-           insn |= ((relocation + 0x8000) >> 16) & 0xffff;
-           bfd_put_32 (input_bfd, insn, contents + insn_offset);
-           insn_offset += 4;
+         if (bfd_link_pic (info)
+             ? offset_in_range (input_section, rel->r_offset - 12,
+                                ARRAY_SIZE (shared_stub_entry) * 4)
+             : offset_in_range (input_section, rel->r_offset,
+                                ARRAY_SIZE (stub_entry) * 4))
+           {
+             const int *stub;
+             size_t size;
+             size_t insn_offset = rel->r_offset;
+             unsigned int insn;
 
-           insn = *stub++;
-           insn |= relocation & 0xffff;
-           bfd_put_32 (input_bfd, insn, contents + insn_offset);
-           insn_offset += 4;
-           size -= 2;
+             if (bfd_link_pic (info))
+               {
+                 relocation -= (input_section->output_section->vma
+                                + input_section->output_offset
+                                + rel->r_offset - 4);
+                 stub = shared_stub_entry;
+                 bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12);
+                 bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8);
+                 bfd_put_32 (input_bfd, stub[2], contents + insn_offset - 4);
+                 stub += 3;
+                 size = ARRAY_SIZE (shared_stub_entry) - 3;
+               }
+             else
+               {
+                 stub = stub_entry;
+                 size = ARRAY_SIZE (stub_entry);
+               }
 
-           while (size != 0)
-             {
-               insn = *stub++;
-               --size;
-               bfd_put_32 (input_bfd, insn, contents + insn_offset);
-               insn_offset += 4;
-             }
+             relocation += addend;
+             if (bfd_link_relocatable (info))
+               relocation = 0;
+
+             /* First insn is HA, second is LO.  */
+             insn = *stub++;
+             insn |= ((relocation + 0x8000) >> 16) & 0xffff;
+             bfd_put_32 (input_bfd, insn, contents + insn_offset);
+             insn_offset += 4;
+
+             insn = *stub++;
+             insn |= relocation & 0xffff;
+             bfd_put_32 (input_bfd, insn, contents + insn_offset);
+             insn_offset += 4;
+             size -= 2;
+
+             while (size != 0)
+               {
+                 insn = *stub++;
+                 --size;
+                 bfd_put_32 (input_bfd, insn, contents + insn_offset);
+                 insn_offset += 4;
+               }
 
-           /* Rewrite the reloc and convert one of the trailing nop
-              relocs to describe this relocation.  */
-           BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
-           /* The relocs are at the bottom 2 bytes */
-           wrel->r_offset = rel->r_offset + d_offset;
-           wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
-           wrel->r_addend = rel->r_addend;
-           memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
-           wrel++, rel++;
-           wrel->r_offset += 4;
-           wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
-         }
+             /* Rewrite the reloc and convert one of the trailing nop
+                relocs to describe this relocation.  */
+             BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
+             /* The relocs are at the bottom 2 bytes */
+             wrel->r_offset = rel->r_offset + d_offset;
+             wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
+             wrel->r_addend = rel->r_addend;
+             memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
+             wrel++, rel++;
+             wrel->r_offset += 4;
+             wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
+           }
+         else
+           goto de_fault;
          continue;
 
          /* Indirect .sdata relocation.  */
@@ -9007,7 +8337,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          BFD_ASSERT (htab->sdata[0].section != NULL);
          if (!is_static_defined (htab->sdata[0].sym))
            {
-             unresolved_reloc = TRUE;
+             unresolved_reloc = true;
              break;
            }
          relocation
@@ -9021,7 +8351,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          BFD_ASSERT (htab->sdata[1].section != NULL);
          if (!is_static_defined (htab->sdata[1].sym))
            {
-             unresolved_reloc = TRUE;
+             unresolved_reloc = true;
              break;
            }
          relocation
@@ -9037,13 +8367,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_TOC16:                       /* phony GOT16 relocations */
          if (sec == NULL || sec->output_section == NULL)
            {
-             unresolved_reloc = TRUE;
+             unresolved_reloc = true;
              break;
            }
-         BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec),
-                             ".got") == 0
-                     || strcmp (bfd_get_section_name (sec->owner, sec),
-                                ".cgot") == 0);
+         BFD_ASSERT (strcmp (bfd_section_name (sec), ".got") == 0
+                     || strcmp (bfd_section_name (sec), ".cgot") == 0);
 
          addend -= sec->output_section->vma + sec->output_offset + 0x8000;
          break;
@@ -9066,7 +8394,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  /* Relocation is to the entry for this symbol in the
                     procedure linkage table.  */
-                 unresolved_reloc = FALSE;
+                 unresolved_reloc = false;
                  if (htab->plt_type == PLT_NEW)
                    relocation = (htab->glink->output_section->vma
                                  + htab->glink->output_offset
@@ -9084,6 +8412,63 @@ ppc_elf_relocate_section (bfd *output_bfd,
          addend = 0;
          break;
 
+       case R_PPC_PLTSEQ:
+       case R_PPC_PLTCALL:
+       case R_PPC_PLT16_LO:
+       case R_PPC_PLT16_HI:
+       case R_PPC_PLT16_HA:
+         plt_list = NULL;
+         if (h != NULL)
+           plt_list = &h->plt.plist;
+         else if (ifunc != NULL)
+           plt_list = ifunc;
+         else if (local_got_offsets != NULL)
+           {
+             struct plt_entry **local_plt;
+             local_plt = (struct plt_entry **) (local_got_offsets
+                                                + symtab_hdr->sh_info);
+             plt_list = local_plt + r_symndx;
+           }
+         unresolved_reloc = true;
+         if (plt_list != NULL)
+           {
+             struct plt_entry *ent;
+
+             ent = find_plt_ent (plt_list, got2,
+                                 bfd_link_pic (info) ? addend : 0);
+             if (ent != NULL && ent->plt.offset != (bfd_vma) -1)
+               {
+                 asection *plt;
+
+                 unresolved_reloc = false;
+                 plt = htab->elf.splt;
+                 if (use_local_plt (info, h))
+                   {
+                     if (ifunc != NULL)
+                       plt = htab->elf.iplt;
+                     else
+                       plt = htab->pltlocal;
+                   }
+                 relocation = (plt->output_section->vma
+                               + plt->output_offset
+                               + ent->plt.offset);
+                 if (bfd_link_pic (info))
+                   {
+                     bfd_vma got = 0;
+
+                     if (ent->addend >= 32768)
+                       got = (ent->addend
+                              + ent->sec->output_section->vma
+                              + ent->sec->output_offset);
+                     else
+                       got = SYM_VAL (htab->elf.hgot);
+                     relocation -= got;
+                   }
+               }
+           }
+         addend = 0;
+         break;
+
          /* Relocate against _SDA_BASE_.  */
        case R_PPC_SDAREL16:
          {
@@ -9094,12 +8479,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                || sec->output_section == NULL
                || !is_static_defined (sda))
              {
-               unresolved_reloc = TRUE;
+               unresolved_reloc = true;
                break;
              }
            addend -= SYM_VAL (sda);
 
-           name = bfd_get_section_name (output_bfd, sec->output_section);
+           name = bfd_section_name (sec->output_section);
            if (!(strcmp (name, ".sdata") == 0
                  || strcmp (name, ".sbss") == 0))
              {
@@ -9125,12 +8510,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                || sec->output_section == NULL
                || !is_static_defined (sda))
              {
-               unresolved_reloc = TRUE;
+               unresolved_reloc = true;
                break;
              }
            addend -= SYM_VAL (sda);
 
-           name = bfd_get_section_name (output_bfd, sec->output_section);
+           name = bfd_section_name (sec->output_section);
            if (!(strcmp (name, ".sdata2") == 0
                  || strcmp (name, ".sbss2") == 0))
              {
@@ -9148,143 +8533,164 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_VLE_LO16A:
          relocation = relocation + addend;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16a_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16a_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
        case R_PPC_VLE_LO16D:
          relocation = relocation + addend;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16d_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16d_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
        case R_PPC_VLE_HI16A:
          relocation = (relocation + addend) >> 16;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16a_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16a_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
        case R_PPC_VLE_HI16D:
          relocation = (relocation + addend) >> 16;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16d_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16d_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
        case R_PPC_VLE_HA16A:
          relocation = (relocation + addend + 0x8000) >> 16;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16a_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16a_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
        case R_PPC_VLE_HA16D:
          relocation = (relocation + addend + 0x8000) >> 16;
-         ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                              contents + rel->r_offset, relocation,
-                              split16d_type, htab->params->vle_reloc_fixup);
-         goto copy_reloc;
+         r = ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                  contents + rel->r_offset, relocation,
+                                  split16d_type,
+                                  htab->params->vle_reloc_fixup);
+         goto report_reloc;
 
          /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
        case R_PPC_EMB_SDA21:
        case R_PPC_VLE_SDA21:
        case R_PPC_EMB_RELSDA:
        case R_PPC_VLE_SDA21_LO:
-         {
-           const char *name;
-           int reg;
-           unsigned int insn;
-           struct elf_link_hash_entry *sda = NULL;
+         if (!offset_in_range (input_section, rel->r_offset, 4))
+           {
+             r = bfd_reloc_outofrange;
+             goto report_reloc;
+           }
+         else
+           {
+             const char *name;
+             int reg;
+             unsigned int insn;
+             struct elf_link_hash_entry *sda = NULL;
 
-           if (sec == NULL || sec->output_section == NULL)
-             {
-               unresolved_reloc = TRUE;
-               break;
-             }
+             if (sec == NULL || sec->output_section == NULL)
+               {
+                 unresolved_reloc = true;
+                 break;
+               }
 
-           name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (strcmp (name, ".sdata") == 0
-               || strcmp (name, ".sbss") == 0)
-             {
-               reg = 13;
-               sda = htab->sdata[0].sym;
-             }
-           else if (strcmp (name, ".sdata2") == 0
-                    || strcmp (name, ".sbss2") == 0)
-             {
-               reg = 2;
-               sda = htab->sdata[1].sym;
-             }
-           else if (strcmp (name, ".PPC.EMB.sdata0") == 0
-                    || strcmp (name, ".PPC.EMB.sbss0") == 0)
-             {
-               reg = 0;
-             }
-           else
-             {
-               _bfd_error_handler
-                 /* xgettext:c-format */
-                 (_("%pB: the target (%s) of a %s relocation is "
-                    "in the wrong output section (%s)"),
-                  input_bfd,
-                  sym_name,
-                  howto->name,
-                  name);
+             name = bfd_section_name (sec->output_section);
+             if (strcmp (name, ".sdata") == 0
+                 || strcmp (name, ".sbss") == 0)
+               {
+                 reg = 13;
+                 sda = htab->sdata[0].sym;
+               }
+             else if (strcmp (name, ".sdata2") == 0
+                      || strcmp (name, ".sbss2") == 0)
+               {
+                 reg = 2;
+                 sda = htab->sdata[1].sym;
+               }
+             else if (strcmp (name, ".PPC.EMB.sdata0") == 0
+                      || strcmp (name, ".PPC.EMB.sbss0") == 0)
+               {
+                 reg = 0;
+               }
+             else
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: the target (%s) of a %s relocation is "
+                      "in the wrong output section (%s)"),
+                    input_bfd,
+                    sym_name,
+                    howto->name,
+                    name);
 
-               bfd_set_error (bfd_error_bad_value);
-               ret = FALSE;
-               goto copy_reloc;
-             }
+                 bfd_set_error (bfd_error_bad_value);
+                 ret = false;
+                 goto copy_reloc;
+               }
 
-           if (sda != NULL)
-             {
-               if (!is_static_defined (sda))
-                 {
-                   unresolved_reloc = TRUE;
-                   break;
-                 }
-               addend -= SYM_VAL (sda);
-             }
+             if (sda != NULL)
+               {
+                 if (!is_static_defined (sda))
+                   {
+                     unresolved_reloc = true;
+                     break;
+                   }
+                 addend -= SYM_VAL (sda);
+               }
 
-           insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
-           if (reg == 0
-               && (r_type == R_PPC_VLE_SDA21
-                   || r_type == R_PPC_VLE_SDA21_LO))
-             {
-               relocation = relocation + addend;
-               addend = 0;
-
-               /* Force e_li insn, keeping RT from original insn.  */
-               insn &= 0x1f << 21;
-               insn |= 28u << 26;
-
-               /* We have an li20 field, bits 17..20, 11..15, 21..31.  */
-               /* Top 4 bits of value to 17..20.  */
-               insn |= (relocation & 0xf0000) >> 5;
-               /* Next 5 bits of the value to 11..15.  */
-               insn |= (relocation & 0xf800) << 5;
-               /* And the final 11 bits of the value to bits 21 to 31.  */
-               insn |= relocation & 0x7ff;
-
-               bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
-
-               if (r_type == R_PPC_VLE_SDA21
-                   && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
-                 goto overflow;
-               goto copy_reloc;
-             }
-           else if (r_type == R_PPC_EMB_SDA21
-                    || r_type == R_PPC_VLE_SDA21
-                    || r_type == R_PPC_VLE_SDA21_LO)
-             {
-               /* Fill in register field.  */
-               insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
-             }
-           bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
-         }
+             if (r_type == R_PPC_EMB_RELSDA)
+               break;
+
+             /* The PowerPC Embedded Application Binary Interface
+                version 1.0 insanely chose to specify R_PPC_EMB_SDA21
+                operating on a 24-bit field at r_offset.  GNU as and
+                GNU ld have always assumed R_PPC_EMB_SDA21 operates on
+                a 32-bit bit insn at r_offset.  Cope with object file
+                producers that possibly comply with the EABI in
+                generating an odd r_offset for big-endian objects.  */
+             if (r_type == R_PPC_EMB_SDA21)
+               rel->r_offset &= ~1;
+
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             if (reg == 0
+                 && (r_type == R_PPC_VLE_SDA21
+                     || r_type == R_PPC_VLE_SDA21_LO))
+               {
+                 relocation = relocation + addend;
+                 addend = 0;
+
+                 /* Force e_li insn, keeping RT from original insn.  */
+                 insn &= 0x1f << 21;
+                 insn |= 28u << 26;
+
+                 /* We have an li20 field, bits 17..20, 11..15, 21..31.  */
+                 /* Top 4 bits of value to 17..20.  */
+                 insn |= (relocation & 0xf0000) >> 5;
+                 /* Next 5 bits of the value to 11..15.  */
+                 insn |= (relocation & 0xf800) << 5;
+                 /* And the final 11 bits of the value to bits 21 to 31.  */
+                 insn |= relocation & 0x7ff;
+
+                 bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+                 r = bfd_reloc_ok;
+                 if (r_type == R_PPC_VLE_SDA21
+                     && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
+                   r = bfd_reloc_overflow;
+                 goto report_reloc;
+               }
+             /* Fill in register field.  */
+             insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+           }
          break;
 
        case R_PPC_VLE_SDAREL_LO16A:
@@ -9293,95 +8699,113 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_VLE_SDAREL_HI16D:
        case R_PPC_VLE_SDAREL_HA16A:
        case R_PPC_VLE_SDAREL_HA16D:
-         {
-           bfd_vma value;
-           const char *name;
-           struct elf_link_hash_entry *sda = NULL;
-
-           if (sec == NULL || sec->output_section == NULL)
-             {
-               unresolved_reloc = TRUE;
-               break;
-             }
+         if (!offset_in_range (input_section, rel->r_offset, 4))
+           r = bfd_reloc_outofrange;
+         else
+           {
+             bfd_vma value;
+             const char *name;
+             struct elf_link_hash_entry *sda = NULL;
 
-           name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (strcmp (name, ".sdata") == 0
-               || strcmp (name, ".sbss") == 0)
-             sda = htab->sdata[0].sym;
-           else if (strcmp (name, ".sdata2") == 0
-                    || strcmp (name, ".sbss2") == 0)
-             sda = htab->sdata[1].sym;
-           else
-             {
-               _bfd_error_handler
-                 /* xgettext:c-format */
-                 (_("%pB: the target (%s) of a %s relocation is "
-                    "in the wrong output section (%s)"),
-                  input_bfd,
-                  sym_name,
-                  howto->name,
-                  name);
+             if (sec == NULL || sec->output_section == NULL)
+               {
+                 unresolved_reloc = true;
+                 break;
+               }
 
-               bfd_set_error (bfd_error_bad_value);
-               ret = FALSE;
-               goto copy_reloc;
-             }
+             name = bfd_section_name (sec->output_section);
+             if (strcmp (name, ".sdata") == 0
+                 || strcmp (name, ".sbss") == 0)
+               sda = htab->sdata[0].sym;
+             else if (strcmp (name, ".sdata2") == 0
+                      || strcmp (name, ".sbss2") == 0)
+               sda = htab->sdata[1].sym;
+             else
+               {
+                 _bfd_error_handler
+                   /* xgettext:c-format */
+                   (_("%pB: the target (%s) of a %s relocation is "
+                      "in the wrong output section (%s)"),
+                    input_bfd,
+                    sym_name,
+                    howto->name,
+                    name);
 
-           if (sda == NULL || !is_static_defined (sda))
-             {
-               unresolved_reloc = TRUE;
-               break;
-             }
-           value = relocation + addend - SYM_VAL (sda);
+                 bfd_set_error (bfd_error_bad_value);
+                 ret = false;
+                 goto copy_reloc;
+               }
 
-           if (r_type == R_PPC_VLE_SDAREL_LO16A)
-             ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                  contents + rel->r_offset, value,
-                                  split16a_type,
-                                  htab->params->vle_reloc_fixup);
-           else if (r_type == R_PPC_VLE_SDAREL_LO16D)
-             ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                  contents + rel->r_offset, value,
-                                  split16d_type,
-                                  htab->params->vle_reloc_fixup);
-           else if (r_type == R_PPC_VLE_SDAREL_HI16A)
-             {
-               value = value >> 16;
-               ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                    contents + rel->r_offset, value,
-                                    split16a_type,
-                                    htab->params->vle_reloc_fixup);
-             }
-           else if (r_type == R_PPC_VLE_SDAREL_HI16D)
-             {
-               value = value >> 16;
-               ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                    contents + rel->r_offset, value,
-                                    split16d_type,
-                                    htab->params->vle_reloc_fixup);
-             }
-           else if (r_type == R_PPC_VLE_SDAREL_HA16A)
-             {
-               value = (value + 0x8000) >> 16;
-               ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                    contents + rel->r_offset, value,
-                                    split16a_type,
-                                    htab->params->vle_reloc_fixup);
-             }
-           else if (r_type == R_PPC_VLE_SDAREL_HA16D)
-             {
-               value = (value + 0x8000) >> 16;
-               ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
-                                    contents + rel->r_offset, value,
-                                    split16d_type,
-                                    htab->params->vle_reloc_fixup);
-             }
-         }
-         goto copy_reloc;
+             if (sda == NULL || !is_static_defined (sda))
+               {
+                 unresolved_reloc = true;
+                 break;
+               }
+             value = relocation + addend - SYM_VAL (sda);
+
+             if (r_type == R_PPC_VLE_SDAREL_LO16A)
+               r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                        rel->r_offset,
+                                        contents + rel->r_offset, value,
+                                        split16a_type,
+                                        htab->params->vle_reloc_fixup);
+             else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+               r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                        rel->r_offset,
+                                        contents + rel->r_offset, value,
+                                        split16d_type,
+                                        htab->params->vle_reloc_fixup);
+             else if (r_type == R_PPC_VLE_SDAREL_HI16A)
+               {
+                 value = value >> 16;
+                 r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                          rel->r_offset,
+                                          contents + rel->r_offset, value,
+                                          split16a_type,
+                                          htab->params->vle_reloc_fixup);
+               }
+             else if (r_type == R_PPC_VLE_SDAREL_HI16D)
+               {
+                 value = value >> 16;
+                 r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                          rel->r_offset,
+                                          contents + rel->r_offset, value,
+                                          split16d_type,
+                                          htab->params->vle_reloc_fixup);
+               }
+             else if (r_type == R_PPC_VLE_SDAREL_HA16A)
+               {
+                 value = (value + 0x8000) >> 16;
+                 r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                          rel->r_offset,
+                                          contents + rel->r_offset, value,
+                                          split16a_type,
+                                          htab->params->vle_reloc_fixup);
+               }
+             else if (r_type == R_PPC_VLE_SDAREL_HA16D)
+               {
+                 value = (value + 0x8000) >> 16;
+                 r = ppc_elf_vle_split16 (input_bfd, input_section,
+                                          rel->r_offset,
+                                          contents + rel->r_offset, value,
+                                          split16d_type,
+                                          htab->params->vle_reloc_fixup);
+               }
+             else
+               abort ();
+           }
+         goto report_reloc;
 
        case R_PPC_VLE_ADDR20:
-         ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset, relocation);
-         continue;
+         if (!offset_in_range (input_section, rel->r_offset, 4))
+           r = bfd_reloc_outofrange;
+         else
+           {
+             ppc_elf_vle_split20 (output_bfd, contents + rel->r_offset,
+                                  relocation);
+             r = bfd_reloc_ok;
+           }
+         goto report_reloc;
 
          /* Relocate against the beginning of the section.  */
        case R_PPC_SECTOFF:
@@ -9390,7 +8814,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_SECTOFF_HA:
          if (sec == NULL || sec->output_section == NULL)
            {
-             unresolved_reloc = TRUE;
+             unresolved_reloc = true;
              break;
            }
          addend -= sec->output_section->vma;
@@ -9412,9 +8836,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_IRELATIVE:
        case R_PPC_PLT32:
        case R_PPC_PLTREL32:
-       case R_PPC_PLT16_LO:
-       case R_PPC_PLT16_HI:
-       case R_PPC_PLT16_HA:
        case R_PPC_ADDR30:
        case R_PPC_EMB_RELSEC16:
        case R_PPC_EMB_RELST_LO:
@@ -9426,10 +8847,88 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              input_bfd, howto->name);
 
          bfd_set_error (bfd_error_invalid_operation);
-         ret = FALSE;
+         ret = false;
          goto copy_reloc;
        }
 
+      switch (r_type)
+       {
+       default:
+         break;
+
+       case R_PPC_TPREL16_HA:
+         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);
+             bfd_put_32 (input_bfd, NOP, p);
+           }
+         break;
+
+       case R_PPC_TPREL16_LO:
+         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);
+             unsigned int insn = bfd_get_32 (input_bfd, p);
+             insn &= ~(0x1f << 16);
+             insn |= 2 << 16;
+             bfd_put_32 (input_bfd, insn, p);
+           }
+         break;
+       }
+
+      switch (r_type)
+       {
+       default:
+         break;
+
+       case R_PPC_PLTCALL:
+         if (unresolved_reloc)
+           {
+             if (offset_in_range (input_section, rel->r_offset, 4))
+               {
+                 bfd_byte *p = contents + rel->r_offset;
+                 unsigned int insn = bfd_get_32 (input_bfd, p);
+                 insn &= 1;
+                 bfd_put_32 (input_bfd, B | insn, p);
+                 unresolved_reloc = save_unresolved_reloc;
+                 r_type = R_PPC_REL24;
+                 howto = ppc_elf_howto_table[r_type];
+               }
+           }
+         else if (htab->plt_type != PLT_NEW)
+           info->callbacks->einfo
+             (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
+              input_bfd, input_section, rel->r_offset,
+              howto->name);
+         break;
+
+       case R_PPC_PLTSEQ:
+       case R_PPC_PLT16_HA:
+       case R_PPC_PLT16_LO:
+         if (unresolved_reloc)
+           {
+             if (offset_in_range (input_section, rel->r_offset & ~3, 4))
+               {
+                 bfd_byte *p = contents + (rel->r_offset & ~3);
+                 bfd_put_32 (input_bfd, NOP, p);
+                 unresolved_reloc = false;
+                 r_type = R_PPC_NONE;
+                 howto = ppc_elf_howto_table[r_type];
+               }
+           }
+         else if (htab->plt_type != PLT_NEW)
+           info->callbacks->einfo
+             (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
+              input_bfd, input_section, rel->r_offset,
+              howto->name);
+         break;
+       }
+
       /* Do any further special processing.  */
       switch (r_type)
        {
@@ -9482,36 +8981,37 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_GOT_DTPREL16_LO:
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16_LO:
-         {
-           /* The 32-bit ABI lacks proper relocations to deal with
-              certain 64-bit instructions.  Prevent damage to bits
-              that make up part of the insn opcode.  */
-           unsigned int insn, mask, lobit;
-
-           insn = bfd_get_32 (input_bfd,
-                              contents + rel->r_offset - d_offset);
-           mask = 0;
-           if (is_insn_ds_form (insn))
-             mask = 3;
-           else if (is_insn_dq_form (insn))
-             mask = 15;
-           else
-             break;
-           relocation += addend;
-           addend = insn & mask;
-           lobit = mask & relocation;
-           if (lobit != 0)
-             {
-               relocation ^= lobit;
-               info->callbacks->einfo
-                 /* xgettext:c-format */
-                 (_("%H: error: %s against `%s' not a multiple of %u\n"),
-                  input_bfd, input_section, rel->r_offset,
-                  howto->name, sym_name, mask + 1);
-               bfd_set_error (bfd_error_bad_value);
-               ret = FALSE;
-             }
-         }
+         if (offset_in_range (input_section, rel->r_offset - d_offset, 4))
+           {
+             /* The 32-bit ABI lacks proper relocations to deal with
+                certain 64-bit instructions.  Prevent damage to bits
+                that make up part of the insn opcode.  */
+             unsigned int insn, mask, lobit;
+
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
+             mask = 0;
+             if (is_insn_ds_form (insn))
+               mask = 3;
+             else if (is_insn_dq_form (insn))
+               mask = 15;
+             else
+               break;
+             relocation += addend;
+             addend = insn & mask;
+             lobit = mask & relocation;
+             if (lobit != 0)
+               {
+                 relocation ^= lobit;
+                 info->callbacks->einfo
+                   /* xgettext:c-format */
+                   (_("%H: error: %s against `%s' not a multiple of %u\n"),
+                    input_bfd, input_section, rel->r_offset,
+                    howto->name, sym_name, mask + 1);
+                 bfd_set_error (bfd_error_bad_value);
+                 ret = false;
+               }
+           }
          break;
        }
 
@@ -9538,7 +9038,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
             input_bfd, input_section, rel->r_offset,
             howto->name,
             sym_name);
-         ret = FALSE;
+         ret = false;
        }
 
       /* 16-bit fields in insns mostly have signed values, but a
@@ -9546,7 +9046,8 @@ ppc_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;
 
@@ -9555,11 +9056,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
              unsigned int insn;
 
              insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
-             if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+             if ((insn & (0x3fu << 26)) == 10u << 26 /* cmpli */)
                complain = complain_overflow_bitfield;
-             else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
-                      || (insn & (0x3f << 26)) == 24u << 26 /* ori */
-                      || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+             else if ((insn & (0x3fu << 26)) == 28u << 26 /* andi */
+                      || (insn & (0x3fu << 26)) == 24u << 26 /* ori */
+                      || (insn & (0x3fu << 26)) == 26u << 26 /* xori */)
                complain = complain_overflow_unsigned;
            }
          if (howto->complain_on_overflow != complain)
@@ -9573,7 +9074,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
       if (r_type == R_PPC_REL16DX_HA)
        {
          /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
-         if (rel->r_offset + 4 > input_section->size)
+         if (offset_in_range (input_section, rel->r_offset, 4))
            r = bfd_reloc_outofrange;
          else
            {
@@ -9595,11 +9096,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
        r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
                                      rel->r_offset, relocation, addend);
 
+    report_reloc:
       if (r != bfd_reloc_ok)
        {
          if (r == bfd_reloc_overflow)
            {
-           overflow:
              /* On code like "if (foo) foo();" don't report overflow
                 on a branch to zero when foo is undefined.  */
              if (!warned
@@ -9618,7 +9119,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                (_("%H: %s reloc against `%s': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
                 howto->name, sym_name, (int) r);
-             ret = FALSE;
+             ret = false;
            }
        }
     copy_reloc:
@@ -9703,13 +9204,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
        {
          bfd_vma offset = addr - start_addr;
          Elf_Internal_Rela *lo, *hi;
-         bfd_boolean is_data;
+         bool is_data;
          bfd_vma patch_off, patch_addr;
          unsigned int insn;
 
          /* Do we have a data reloc at this offset?  If so, leave
             the word alone.  */
-         is_data = FALSE;
+         is_data = false;
          lo = relocs;
          hi = relend;
          rel = NULL;
@@ -9728,7 +9229,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                    case R_PPC_UADDR32:
                    case R_PPC_REL32:
                    case R_PPC_ADDR30:
-                     is_data = TRUE;
+                     is_data = true;
                      break;
                    default:
                      break;
@@ -9783,10 +9284,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
             . new_page:                new_page:
             .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
-         if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
-             || ((insn & (0x3f << 26)) == (16u << 26)      /* bc,bcl,bca,bcla*/
+         if ((insn & (0x3fu << 26)) == (18u << 26)         /* b,bl,ba,bla */
+             || ((insn & (0x3fu << 26)) == (16u << 26)     /* bc,bcl,bca,bcla*/
                  && (insn & (0x14 << 21)) == (0x14 << 21)) /*   with BO=0x14 */
-             || ((insn & (0x3f << 26)) == (19u << 26)
+             || ((insn & (0x3fu << 26)) == (19u << 26)
                  && (insn & (0x3ff << 1)) == (16u << 1)    /* bclr,bclrl */
                  && (insn & (0x14 << 21)) == (0x14 << 21)))/*   with BO=0x14 */
            continue;
@@ -9870,7 +9371,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          else
            rel = NULL;
 
-         if ((insn & (0x3f << 26)) == (16u << 26) /* bc */
+         if ((insn & (0x3fu << 26)) == (16u << 26) /* bc */
              && (insn & 2) == 0 /* relative */)
            {
              bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
@@ -9947,40 +9448,31 @@ ppc_elf_relocate_section (bfd *output_bfd,
   return ret;
 }
 \f
-/* Finish up dynamic symbol handling.  We set the contents of various
-   dynamic sections here.  */
+/* Write out the PLT relocs and entries for H.  */
 
-static bfd_boolean
-ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
-                              struct bfd_link_info *info,
-                              struct elf_link_hash_entry *h,
-                              Elf_Internal_Sym *sym)
+static bool
+write_global_sym_plt (struct elf_link_hash_entry *h, void *inf)
 {
-  struct ppc_elf_link_hash_table *htab;
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
   struct plt_entry *ent;
-  bfd_boolean doneone;
-
-#ifdef DEBUG
-  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
-          h->root.root.string);
-#endif
-
-  htab = ppc_elf_hash_table (info);
-  BFD_ASSERT (htab->elf.dynobj != NULL);
+  bool doneone;
 
-  doneone = FALSE;
+  doneone = false;
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
       {
+       bool dyn = !use_local_plt (info, h);
+
        if (!doneone)
          {
            Elf_Internal_Rela rela;
            bfd_byte *loc;
            bfd_vma reloc_index;
+           asection *plt = htab->elf.splt;
+           asection *relplt = htab->elf.srelplt;
 
-           if (htab->plt_type == PLT_NEW
-               || !htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
+           if (htab->plt_type == PLT_NEW || !dyn)
              reloc_index = ent->plt.offset / 4;
            else
              {
@@ -9993,9 +9485,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
            /* This symbol has an entry in the procedure linkage table.
               Set it up.  */
-           if (htab->plt_type == PLT_VXWORKS
-               && htab->elf.dynamic_sections_created
-               && h->dynindx != -1)
+           if (htab->plt_type == PLT_VXWORKS && dyn)
              {
                bfd_vma got_offset;
                const bfd_vma *plt_entry;
@@ -10010,29 +9500,29 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                /* Fill in the .plt on VxWorks.  */
                if (bfd_link_pic (info))
                  {
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
-                               htab->elf.splt->contents + ent->plt.offset + 0);
-                   bfd_put_32 (output_bfd,
+                               plt->contents + ent->plt.offset + 0);
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_offset),
-                               htab->elf.splt->contents + ent->plt.offset + 4);
+                               plt->contents + ent->plt.offset + 4);
                  }
                else
                  {
                    bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
 
-                   bfd_put_32 (output_bfd,
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[0] | PPC_HA (got_loc),
-                               htab->elf.splt->contents + ent->plt.offset + 0);
-                   bfd_put_32 (output_bfd,
+                               plt->contents + ent->plt.offset + 0);
+                   bfd_put_32 (info->output_bfd,
                                plt_entry[1] | PPC_LO (got_loc),
-                               htab->elf.splt->contents + ent->plt.offset + 4);
+                               plt->contents + ent->plt.offset + 4);
                  }
 
-               bfd_put_32 (output_bfd, plt_entry[2],
-                           htab->elf.splt->contents + ent->plt.offset + 8);
-               bfd_put_32 (output_bfd, plt_entry[3],
-                           htab->elf.splt->contents + ent->plt.offset + 12);
+               bfd_put_32 (info->output_bfd, plt_entry[2],
+                           plt->contents + ent->plt.offset + 8);
+               bfd_put_32 (info->output_bfd, plt_entry[3],
+                           plt->contents + ent->plt.offset + 12);
 
                /* This instruction is an immediate load.  The value loaded is
                   the byte offset of the R_PPC_JMP_SLOT relocation from the
@@ -10040,30 +9530,30 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   low-order 16 bits of the load instruction.  */
                /* NOTE: It appears that this is now an index rather than a
                   prescaled offset.  */
-               bfd_put_32 (output_bfd,
+               bfd_put_32 (info->output_bfd,
                            plt_entry[4] | reloc_index,
-                           htab->elf.splt->contents + ent->plt.offset + 16);
+                           plt->contents + ent->plt.offset + 16);
                /* This instruction is a PC-relative branch whose target is
                   the start of the PLT section.  The address of this branch
                   instruction is 20 bytes beyond the start of this PLT entry.
                   The address is encoded in bits 6-29, inclusive.  The value
                   stored is right-shifted by two bits, permitting a 26-bit
                   offset.  */
-               bfd_put_32 (output_bfd,
+               bfd_put_32 (info->output_bfd,
                            (plt_entry[5]
                             | (-(ent->plt.offset + 20) & 0x03fffffc)),
-                           htab->elf.splt->contents + ent->plt.offset + 20);
-               bfd_put_32 (output_bfd, plt_entry[6],
-                           htab->elf.splt->contents + ent->plt.offset + 24);
-               bfd_put_32 (output_bfd, plt_entry[7],
-                           htab->elf.splt->contents + ent->plt.offset + 28);
+                           plt->contents + ent->plt.offset + 20);
+               bfd_put_32 (info->output_bfd, plt_entry[6],
+                           plt->contents + ent->plt.offset + 24);
+               bfd_put_32 (info->output_bfd, plt_entry[7],
+                           plt->contents + ent->plt.offset + 28);
 
                /* Fill in the GOT entry corresponding to this PLT slot with
                   the address immediately after the "bctr" instruction
                   in this PLT entry.  */
-               bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
-                                        + htab->elf.splt->output_offset
-                                        + ent->plt.offset + 16),
+               bfd_put_32 (info->output_bfd, (plt->output_section->vma
+                                              + plt->output_offset
+                                              + ent->plt.offset + 16),
                            htab->elf.sgotplt->contents + got_offset);
 
                if (!bfd_link_pic (info))
@@ -10075,23 +9565,23 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                         * sizeof (Elf32_External_Rela));
 
                    /* Provide the @ha relocation for the first instruction.  */
-                   rela.r_offset = (htab->elf.splt->output_section->vma
-                                    + htab->elf.splt->output_offset
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
                                     + ent->plt.offset + 2);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_HA);
                    rela.r_addend = got_offset;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide the @l relocation for the second instruction.  */
-                   rela.r_offset = (htab->elf.splt->output_section->vma
-                                    + htab->elf.splt->output_offset
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
                                     + ent->plt.offset + 6);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_LO);
                    rela.r_addend = got_offset;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide a relocation for the GOT entry corresponding to this
@@ -10102,7 +9592,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
                                                R_PPC_ADDR32);
                    rela.r_addend = ent->plt.offset + 16;
-                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
                  }
 
                /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
@@ -10113,119 +9603,97 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                rela.r_offset = (htab->elf.sgotplt->output_section->vma
                                 + htab->elf.sgotplt->output_offset
                                 + got_offset);
-
+               rela.r_addend = 0;
              }
            else
              {
-               asection *splt = htab->elf.splt;
-               if (!htab->elf.dynamic_sections_created
-                   || h->dynindx == -1)
-                 splt = htab->elf.iplt;
-
-               rela.r_offset = (splt->output_section->vma
-                                + splt->output_offset
-                                + ent->plt.offset);
-               if (htab->plt_type == PLT_OLD
-                   || !htab->elf.dynamic_sections_created
-                   || h->dynindx == -1)
+               rela.r_addend = 0;
+               if (!dyn)
                  {
-                   /* We don't need to fill in the .plt.  The ppc dynamic
-                      linker will fill it in.  */
+                   if (h->type == STT_GNU_IFUNC)
+                     {
+                       plt = htab->elf.iplt;
+                       relplt = htab->elf.irelplt;
+                     }
+                   else
+                     {
+                       plt = htab->pltlocal;
+                       relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                     }
+                   if (h->def_regular
+                       && (h->root.type == bfd_link_hash_defined
+                           || h->root.type == bfd_link_hash_defweak))
+                     rela.r_addend = SYM_VAL (h);
                  }
-               else
+
+               if (relplt == NULL)
                  {
-                   bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
-                                  + htab->glink->output_section->vma
-                                  + htab->glink->output_offset);
-                   bfd_put_32 (output_bfd, val,
-                               splt->contents + ent->plt.offset);
+                   loc = plt->contents + ent->plt.offset;
+                   bfd_put_32 (info->output_bfd, rela.r_addend, loc);
                  }
-             }
-
-           /* Fill in the entry in the .rela.plt section.  */
-           rela.r_addend = 0;
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
-             {
-               BFD_ASSERT (h->type == STT_GNU_IFUNC
-                           && h->def_regular
-                           && (h->root.type == bfd_link_hash_defined
-                               || h->root.type == bfd_link_hash_defweak));
-               rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
-               rela.r_addend = SYM_VAL (h);
-             }
-           else
-             rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+               else
+                 {
+                   rela.r_offset = (plt->output_section->vma
+                                    + plt->output_offset
+                                    + ent->plt.offset);
 
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
-             {
-               loc = (htab->elf.irelplt->contents
-                      + (htab->elf.irelplt->reloc_count++
-                         * sizeof (Elf32_External_Rela)));
-               htab->local_ifunc_resolver = 1;
-             }
-           else
-             {
-               loc = (htab->elf.srelplt->contents
-                      + reloc_index * sizeof (Elf32_External_Rela));
-               if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-                 htab->maybe_local_ifunc_resolver = 1;
+                   if (htab->plt_type == PLT_OLD || !dyn)
+                     {
+                       /* We don't need to fill in the .plt.  The ppc dynamic
+                          linker will fill it in.  */
+                     }
+                   else
+                     {
+                       bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+                                      + htab->glink->output_section->vma
+                                      + htab->glink->output_offset);
+                       bfd_put_32 (info->output_bfd, val,
+                                   plt->contents + ent->plt.offset);
+                     }
+                 }
              }
-           bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
-           if (!h->def_regular)
+           if (relplt != NULL)
              {
-               /* Mark the symbol as undefined, rather than as
-                  defined in the .plt section.  Leave the value if
-                  there were any relocations where pointer equality
-                  matters (this is a clue for the dynamic linker, to
-                  make function pointer comparisons work between an
-                  application and shared library), otherwise set it
-                  to zero.  */
-               sym->st_shndx = SHN_UNDEF;
-               if (!h->pointer_equality_needed)
-                 sym->st_value = 0;
-               else if (!h->ref_regular_nonweak)
+               /* Fill in the entry in the .rela.plt section.  */
+               if (!dyn)
                  {
-                   /* This breaks function pointer comparisons, but
-                      that is better than breaking tests for a NULL
-                      function pointer.  */
-                   sym->st_value = 0;
+                   if (h->type == STT_GNU_IFUNC)
+                     rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                   else
+                     rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+                   loc = relplt->contents + (relplt->reloc_count++
+                                             * sizeof (Elf32_External_Rela));
+                   htab->local_ifunc_resolver = 1;
                  }
+               else
+                 {
+                   rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
+                   loc = relplt->contents + (reloc_index
+                                             * sizeof (Elf32_External_Rela));
+                   if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+                     htab->maybe_local_ifunc_resolver = 1;
+                 }
+               bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
              }
-           else if (h->type == STT_GNU_IFUNC
-                    && !bfd_link_pic (info))
-             {
-               /* Set the value of ifunc symbols in a non-pie
-                  executable to the glink entry.  This is to avoid
-                  text relocations.  We can't do this for ifunc in
-                  allocate_dynrelocs, as we do for normal dynamic
-                  function symbols with plt entries, because we need
-                  to keep the original value around for the ifunc
-                  relocation.  */
-               sym->st_shndx = (_bfd_elf_section_from_bfd_section
-                                (output_bfd, htab->glink->output_section));
-               sym->st_value = (ent->glink_offset
-                                + htab->glink->output_offset
-                                + htab->glink->output_section->vma);
-             }
-           doneone = TRUE;
+           doneone = true;
          }
 
-       if (htab->plt_type == PLT_NEW
-           || !htab->elf.dynamic_sections_created
-           || h->dynindx == -1)
+       if (htab->plt_type == PLT_NEW || !dyn)
          {
            unsigned char *p;
-           asection *splt = htab->elf.splt;
+           asection *plt = htab->elf.splt;
 
-           if (!htab->elf.dynamic_sections_created
-               || h->dynindx == -1)
-             splt = htab->elf.iplt;
+           if (!dyn)
+             {
+               if (h->type == STT_GNU_IFUNC)
+                 plt = htab->elf.iplt;
+               else
+                 break;
+             }
 
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
-           write_glink_stub (h, ent, splt, p, info);
+           write_glink_stub (h, ent, plt, p, info);
 
            if (!bfd_link_pic (info))
              /* We only need one non-PIC glink stub.  */
@@ -10234,6 +9702,176 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
        else
          break;
       }
+  return true;
+}
+
+/* Finish up PLT handling.  */
+
+bool
+ppc_finish_symbols (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  bfd *ibfd;
+
+  if (!htab)
+    return true;
+
+  elf_link_hash_traverse (&htab->elf, write_global_sym_plt, info);
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      bfd_vma *local_got, *end_local_got;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc_elf (ibfd))
+       continue;
+
+      local_got = elf_local_got_offsets (ibfd);
+      if (!local_got)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_local_got = local_got + locsymcount;
+      local_plt = (struct plt_entry **) end_local_got;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+       for (ent = *lplt; ent != NULL; ent = ent->next)
+         {
+           if (ent->plt.offset != (bfd_vma) -1)
+             {
+               Elf_Internal_Sym *sym;
+               asection *sym_sec;
+               asection *plt, *relplt;
+               bfd_byte *loc;
+               bfd_vma val;
+               Elf_Internal_Rela rela;
+               unsigned char *p;
+
+               if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+                               lplt - local_plt, ibfd))
+                 {
+                   if (symtab_hdr->contents != (unsigned char *) local_syms)
+                     free (local_syms);
+                   return false;
+                 }
+
+               val = sym->st_value;
+               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;
+                   plt = htab->elf.iplt;
+                   relplt = htab->elf.irelplt;
+                   rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
+                 }
+               else
+                 {
+                   plt = htab->pltlocal;
+                   if (bfd_link_pic (info))
+                     {
+                       relplt = htab->relpltlocal;
+                       rela.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
+                     }
+                   else
+                     {
+                       loc = plt->contents + ent->plt.offset;
+                       bfd_put_32 (info->output_bfd, val, loc);
+                       continue;
+                     }
+                 }
+
+               rela.r_offset = (ent->plt.offset
+                                + plt->output_offset
+                                + plt->output_section->vma);
+               rela.r_addend = val;
+               loc = relplt->contents + (relplt->reloc_count++
+                                         * sizeof (Elf32_External_Rela));
+               bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
+
+               p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+               write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
+             }
+         }
+
+      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;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static bool
+ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
+                              struct bfd_link_info *info,
+                              struct elf_link_hash_entry *h,
+                              Elf_Internal_Sym *sym)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+  struct plt_entry *ent;
+
+#ifdef DEBUG
+  fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s",
+          h->root.root.string);
+#endif
+
+  if (!h->def_regular
+      || (h->type == STT_GNU_IFUNC && !bfd_link_pic (info)))
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+       {
+         if (!h->def_regular)
+           {
+             /* Mark the symbol as undefined, rather than as
+                defined in the .plt section.  Leave the value if
+                there were any relocations where pointer equality
+                matters (this is a clue for the dynamic linker, to
+                make function pointer comparisons work between an
+                application and shared library), otherwise set it
+                to zero.  */
+             sym->st_shndx = SHN_UNDEF;
+             if (!h->pointer_equality_needed)
+               sym->st_value = 0;
+             else if (!h->ref_regular_nonweak)
+               {
+                 /* This breaks function pointer comparisons, but
+                    that is better than breaking tests for a NULL
+                    function pointer.  */
+                 sym->st_value = 0;
+               }
+           }
+         else
+           {
+             /* Set the value of ifunc symbols in a non-pie
+                executable to the glink entry.  This is to avoid
+                text relocations.  We can't do this for ifunc in
+                allocate_dynrelocs, as we do for normal dynamic
+                function symbols with plt entries, because we need
+                to keep the original value around for the ifunc
+                relocation.  */
+             sym->st_shndx
+               = (_bfd_elf_section_from_bfd_section
+                  (info->output_bfd, htab->glink->output_section));
+             sym->st_value = (ent->glink_offset
+                              + htab->glink->output_offset
+                              + htab->glink->output_section->vma);
+           }
+         break;
+       }
 
   if (h->needs_copy)
     {
@@ -10268,7 +9906,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
   fprintf (stderr, "\n");
 #endif
 
-  return TRUE;
+  return true;
 }
 \f
 static enum elf_reloc_type_class
@@ -10296,7 +9934,7 @@ ppc_elf_reloc_type_class (const struct bfd_link_info *info,
 \f
 /* Finish up the dynamic sections.  */
 
-static bfd_boolean
+static bool
 ppc_elf_finish_dynamic_sections (bfd *output_bfd,
                                 struct bfd_link_info *info)
 {
@@ -10304,7 +9942,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   struct ppc_elf_link_hash_table *htab;
   bfd_vma got;
   bfd *dynobj;
-  bfd_boolean ret = TRUE;
+  bool ret = true;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
@@ -10336,7 +9974,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
          switch (dyn.d_tag)
            {
            case DT_PLTGOT:
-             if (htab->is_vxworks)
+             if (htab->elf.target_os == is_vxworks)
                s = htab->elf.sgotplt;
              else
                s = htab->elf.splt;
@@ -10368,7 +10006,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              continue;
 
            default:
-             if (htab->is_vxworks
+             if (htab->elf.target_os == is_vxworks
                  && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
                break;
              continue;
@@ -10413,14 +10051,14 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
                              (htab->elf.sgotplt != NULL
                               ? htab->elf.sgotplt : htab->elf.sgot));
          bfd_set_error (bfd_error_bad_value);
-         ret = FALSE;
+         ret = false;
        }
 
       elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4;
     }
 
   /* Fill in the first entry in the VxWorks procedure linkage table.  */
-  if (htab->is_vxworks
+  if (htab->elf.target_os == is_vxworks
       && htab->elf.splt != NULL
       && htab->elf.splt->size != 0
       && htab->elf.splt->output_section != bfd_abs_section_ptr)
@@ -10725,7 +10363,7 @@ ppc_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;
     }
 
   return ret;
@@ -10738,14 +10376,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define ELF_ARCH               bfd_arch_powerpc
 #define ELF_TARGET_ID          PPC32_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC
-#ifdef __QNXTARGET__
-#define ELF_MAXPAGESIZE                0x1000
-#define ELF_COMMONPAGESIZE     0x1000
-#else
 #define ELF_MAXPAGESIZE                0x10000
-#define ELF_COMMONPAGESIZE     0x10000
-#endif
-#define ELF_MINPAGESIZE                0x1000
+#define ELF_COMMONPAGESIZE     0x1000
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
@@ -10834,6 +10466,9 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 
 #undef  ELF_OSABI
 
+#undef ELF_TARGET_OS
+#define ELF_TARGET_OS          is_vxworks
+
 /* VxWorks uses the elf default section flags for .plt.  */
 static const struct bfd_elf_special_section *
 ppc_elf_vxworks_get_sec_type_attr (bfd *abfd, asection *sec)
@@ -10859,7 +10494,6 @@ ppc_elf_vxworks_link_hash_table_create (bfd *abfd)
     {
       struct ppc_elf_link_hash_table *htab
        = (struct ppc_elf_link_hash_table *)ret;
-      htab->is_vxworks = 1;
       htab->plt_type = PLT_VXWORKS;
       htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
       htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;
@@ -10869,7 +10503,7 @@ ppc_elf_vxworks_link_hash_table_create (bfd *abfd)
 }
 
 /* Tweak magic VxWorks symbols as they are loaded.  */
-static bfd_boolean
+static bool
 ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
                                 struct bfd_link_info *info,
                                 Elf_Internal_Sym *sym,
@@ -10880,16 +10514,16 @@ ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
 {
   if (!elf_vxworks_add_symbol_hook (abfd, info, sym, namep, flagsp, secp,
                                    valp))
-    return FALSE;
+    return false;
 
   return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp);
 }
 
-static void
-ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+static bool
+ppc_elf_vxworks_final_write_processing (bfd *abfd)
 {
-  ppc_elf_final_write_processing (abfd, linker);
-  elf_vxworks_final_write_processing (abfd, linker);
+  ppc_final_write_processing (abfd);
+  return elf_vxworks_final_write_processing (abfd);
 }
 
 /* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so
@@ -10932,6 +10566,5 @@ ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
 
 #undef elf32_bed
 #define elf32_bed                              ppc_elf_vxworks_bed
-#undef elf_backend_post_process_headers
 
 #include "elf32-target.h"