Delete duplicate target short-cuts to dynamic sections
[external/binutils.git] / bfd / elf32-ppc.c
index 04c2d6a..35a505c 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright (C) 1994-2014 Free Software Foundation, Inc.
+   Copyright (C) 1994-2016 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -35,7 +35,7 @@
 #include "elf32-ppc.h"
 #include "elf-vxworks.h"
 #include "dwarf2.h"
-#include "elf-linux-psinfo.h"
+#include "opcode/ppc.h"
 
 typedef enum split16_format_type
 {
@@ -187,8 +187,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   /* This reloc does nothing.  */
   HOWTO (R_PPC_NONE,           /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
@@ -414,7 +414,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -430,7 +430,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_LO",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -446,7 +446,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -462,7 +462,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -477,8 +477,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         26,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_signed,  /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLTREL24",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -497,7 +497,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_COPY",          /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -513,7 +513,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GLOB_DAT",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -528,7 +528,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_JMP_SLOT",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -623,7 +623,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT32",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -639,7 +639,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLTREL32",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -655,7 +655,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_LO",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -671,7 +671,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -687,7 +687,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -703,7 +703,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SDAREL16",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -718,7 +718,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF",       /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -733,7 +733,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_LO",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -748,7 +748,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_HI",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -763,7 +763,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_HA",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1239,7 +1239,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR32",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1254,7 +1254,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1269,7 +1269,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_ADDR16_LO", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1284,7 +1284,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16_HI", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1301,7 +1301,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16_HA", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1318,7 +1318,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDAI16",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1335,7 +1335,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA2I16",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1351,7 +1351,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA2REL",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1368,7 +1368,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA21",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1392,7 +1392,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_RELSDA",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1426,7 +1426,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         "R_PPC_VLE_REL15",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfe,                  /* dst_mask */
+        0xfffe,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
   /* A relative 24 bit branch.  */
@@ -1452,11 +1452,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_VLE_LO16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* The 16 LSBS in split16d format.  */
@@ -1467,11 +1467,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_LO16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_LO16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 split16a format.  */
@@ -1482,11 +1482,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HI16A",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HI16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 split16d format.  */
@@ -1497,11 +1497,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HI16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HI16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (High Adjusted) in split16a format.  */
@@ -1512,11 +1512,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HA16A",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HA16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (High Adjusted) in split16d format.  */
@@ -1527,11 +1527,11 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HA16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HA16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
@@ -1544,8 +1544,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_SDA21",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDA21",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
@@ -1559,7 +1559,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_VLE_SDA21_LO",  /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1573,12 +1573,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_LO16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_LO16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16d format.  */
@@ -1588,72 +1588,72 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_LO16D",              /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_LO16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16A,       /* type */
+  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 */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HI16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HI16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16D,       /* type */
+  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 */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HI16D",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HI16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16A,       /* type */
+  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 */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HA16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HA16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f007ff,             /* dst_mask */
+        0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16D,       /* type */
+  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 */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HA16D",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HA16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x1f07ff,              /* dst_mask */
+        0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   HOWTO (R_PPC_IRELATIVE,      /* type */
@@ -1663,7 +1663,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_IRELATIVE",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1731,6 +1731,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* 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 */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1769,7 +1784,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_TOC16",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1804,30 +1819,28 @@ struct elf_external_ppc_linux_prpsinfo32
     char pr_psargs[80];                        /* Initial part of arg list.  */
   };
 
-/* Helper macro to swap (properly handling endianess) things from the
-   `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32'
-   structure.
-
-   Note that FROM should be a pointer, and TO should be the explicit type.  */
-
-#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to)             \
-  do                                                                 \
-    {                                                                \
-      H_PUT_8 (abfd, from->pr_state, &to.pr_state);                  \
-      H_PUT_8 (abfd, from->pr_sname, &to.pr_sname);                  \
-      H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb);                    \
-      H_PUT_8 (abfd, from->pr_nice, &to.pr_nice);                    \
-      H_PUT_32 (abfd, from->pr_flag, to.pr_flag);                    \
-      H_PUT_32 (abfd, from->pr_uid, to.pr_uid);                              \
-      H_PUT_32 (abfd, from->pr_gid, to.pr_gid);                              \
-      H_PUT_32 (abfd, from->pr_pid, to.pr_pid);                              \
-      H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid);                    \
-      H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp);                    \
-      H_PUT_32 (abfd, from->pr_sid, to.pr_sid);                              \
-      strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname));    \
-      strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
-    } while (0)
+/* Helper function to copy an elf_internal_linux_prpsinfo in host
+   endian to an elf_external_ppc_linux_prpsinfo32 in target endian.  */
 
+static inline void
+swap_ppc_linux_prpsinfo32_out (bfd *obfd,
+                              const struct elf_internal_linux_prpsinfo *from,
+                              struct elf_external_ppc_linux_prpsinfo32 *to)
+{
+  bfd_put_8 (obfd, from->pr_state, &to->pr_state);
+  bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
+  bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
+  bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
+  bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
+  bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
+  bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
+  bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
+  bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
+  bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
+  bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
+  strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
+  strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
+}
 \f
 /* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */
 
@@ -1989,6 +2002,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_LO16_PCREL:         r = R_PPC_REL16_LO;             break;
     case BFD_RELOC_HI16_PCREL:         r = R_PPC_REL16_HI;             break;
     case BFD_RELOC_HI16_S_PCREL:       r = R_PPC_REL16_HA;             break;
+    case BFD_RELOC_PPC_REL16DX_HA:     r = R_PPC_REL16DX_HA;           break;
     case BFD_RELOC_VTABLE_INHERIT:     r = R_PPC_GNU_VTINHERIT;        break;
     case BFD_RELOC_VTABLE_ENTRY:       r = R_PPC_GNU_VTENTRY;          break;
     }
@@ -2019,19 +2033,30 @@ ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                       arelent *cache_ptr,
                       Elf_Internal_Rela *dst)
 {
+  unsigned int r_type;
+
   /* Initialize howto table if not already done.  */
   if (!ppc_elf_howto_table[R_PPC_ADDR32])
     ppc_elf_howto_init ();
 
-  BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
-  cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)];
+  r_type = ELF32_R_TYPE (dst->r_info);
+  if (r_type >= R_PPC_max)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%B: unrecognised PPC reloc number: %d"),
+                         abfd, r_type);
+      bfd_set_error (bfd_error_bad_value);
+      r_type = R_PPC_NONE;
+    }
+  cache_ptr->howto = ppc_elf_howto_table[r_type];
 
   /* Just because the above assert didn't trigger doesn't mean that
      ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation.  */
   if (!cache_ptr->howto)
     {
-      (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
-                             abfd, ELF32_R_TYPE (dst->r_info));
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%B: invalid relocation type %d"),
+                         abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
 
       cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
@@ -2049,7 +2074,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
                         bfd *output_bfd,
                         char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_vma relocation;
+  enum elf_ppc_reloc_type r_type;
+  long insn;
+  bfd_size_type octets;
+  bfd_vma value;
 
   if (output_bfd != NULL)
     {
@@ -2057,23 +2085,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       return bfd_reloc_ok;
     }
 
-  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
-    return bfd_reloc_outofrange;
-
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
-
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc_entry->addend;
-  if (reloc_entry->howto->pc_relative)
-    relocation -= reloc_entry->address;
-
-  reloc_entry->addend += (relocation & 0x8000) << 1;
-
-  return bfd_reloc_continue;
+  reloc_entry->addend += 0x8000;
+  r_type = reloc_entry->howto->type;
+  if (r_type != R_PPC_REL16DX_HA)
+    return bfd_reloc_continue;
+
+  value = 0;
+  if (!bfd_is_com_section (symbol->section))
+    value = symbol->value;
+  value += (reloc_entry->addend
+           + symbol->section->output_offset
+           + symbol->section->output_section->vma);
+  value -= (reloc_entry->address
+           + input_section->output_offset
+           + input_section->output_section->vma);
+  value >>= 16;
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+  insn &= ~0x1fffc1;
+  insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+  return bfd_reloc_ok;
 }
 
 static bfd_reloc_status_type
@@ -2166,13 +2199,94 @@ ppc_elf_mkobject (bfd *abfd)
                                  PPC32_ELF_DATA);
 }
 
+/* When defaulting arch/mach, decode apuinfo to find a better match.  */
+
+bfd_boolean
+_bfd_elf_ppc_set_arch (bfd *abfd)
+{
+  unsigned long mach = 0;
+  asection *s;
+  unsigned char *contents;
+
+  if (abfd->arch_info->bits_per_word == 32
+      && bfd_big_endian (abfd))
+    {
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0)
+         break;
+      if (s != NULL)
+       mach = bfd_mach_ppc_vle;
+    }
+
+  if (mach == 0)
+    {
+      s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+      if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+       {
+         unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
+         unsigned int i;
+
+         for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4)
+           {
+             unsigned int val = bfd_get_32 (abfd, contents + i);
+             switch (val >> 16)
+               {
+               case PPC_APUINFO_PMR:
+               case PPC_APUINFO_RFMCI:
+                 if (mach == 0)
+                   mach = bfd_mach_ppc_titan;
+                 break;
+
+               case PPC_APUINFO_ISEL:
+               case PPC_APUINFO_CACHELCK:
+                 if (mach == bfd_mach_ppc_titan)
+                   mach = bfd_mach_ppc_e500mc;
+                 break;
+
+               case PPC_APUINFO_SPE:
+               case PPC_APUINFO_EFS:
+               case PPC_APUINFO_BRLOCK:
+                 if (mach != bfd_mach_ppc_vle)
+                   mach = bfd_mach_ppc_e500;
+                 break;
+
+               case PPC_APUINFO_VLE:
+                 mach = bfd_mach_ppc_vle;
+                 break;
+
+               default:
+                 mach = -1ul;
+               }
+           }
+         free (contents);
+       }
+    }
+
+  if (mach != 0 && mach != -1ul)
+    {
+      const bfd_arch_info_type *arch;
+
+      for (arch = abfd->arch_info->next; arch; arch = arch->next)
+       if (arch->mach == mach)
+         {
+           abfd->arch_info = arch;
+           break;
+         }
+    }
+  return TRUE;
+}
+
 /* Fix bad default arch selected for a 32 bit input bfd when the
-   default is 64 bit.  */
+   default is 64 bit.  Also select arch based on apuinfo.  */
 
 static bfd_boolean
 ppc_elf_object_p (bfd *abfd)
 {
-  if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64)
+  if (!abfd->arch_info->the_default)
+    return TRUE;
+
+  if (abfd->arch_info->bits_per_word == 64)
     {
       Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
 
@@ -2183,7 +2297,7 @@ ppc_elf_object_p (bfd *abfd)
          BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
        }
     }
-  return TRUE;
+  return _bfd_elf_ppc_set_arch (abfd);
 }
 
 /* Function to set whether a module needs the -mrelocatable bit set.  */
@@ -2264,14 +2378,15 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 }
 
 char *
-elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz,
-                                     const struct elf_internal_linux_prpsinfo *prpsinfo)
+elfcore_write_ppc_linux_prpsinfo32
+  (bfd *abfd,
+   char *buf,
+   int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
 {
   struct elf_external_ppc_linux_prpsinfo32 data;
 
-  memset (&data, 0, sizeof (data));
-  PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
-
+  swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
   return elfcore_write_note (abfd, buf, bufsiz,
                             "CORE", NT_PRPSINFO, &data, sizeof (data));
 }
@@ -2332,18 +2447,6 @@ ppc_elf_lookup_section_flags (char *flag_name)
   return 0;
 }
 
-/* Add the VLE flag if required.  */
-
-bfd_boolean
-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
-{
-  if (bfd_get_mach (abfd) == bfd_mach_ppc_vle
-      && (shdr->sh_flags & SHF_EXECINSTR) != 0)
-    shdr->sh_flags |= SHF_PPC_VLE;
-
-  return TRUE;
-}
-
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -2423,10 +2526,7 @@ bfd_boolean
 ppc_elf_modify_segment_map (bfd *abfd,
                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
-  struct elf_segment_map *m, *n;
-  bfd_size_type amt;
-  unsigned int j, k;
-  bfd_boolean sect0_vle, sectj_vle;
+  struct elf_segment_map *m;
 
   /* At this point in the link, output sections have already been sorted by
      LMA and assigned to segments.  All that is left to do is to ensure
@@ -2436,25 +2536,59 @@ ppc_elf_modify_segment_map (bfd *abfd,
 
   for (m = elf_seg_map (abfd); m != NULL; m = m->next)
     {
-      if (m->count == 0)
+      struct elf_segment_map *n;
+      bfd_size_type amt;
+      unsigned int j, k;
+      unsigned int p_flags;
+
+      if (m->p_type != PT_LOAD || m->count == 0)
        continue;
 
-      sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
-      for (j = 1; j < m->count; ++j)
+      for (p_flags = PF_R, j = 0; j != m->count; ++j)
        {
-         sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
+         if ((m->sections[j]->flags & SEC_READONLY) == 0)
+           p_flags |= PF_W;
+         if ((m->sections[j]->flags & SEC_CODE) != 0)
+           {
+             p_flags |= PF_X;
+             if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+               p_flags |= PF_PPC_VLE;
+             break;
+           }
+       }
+      if (j != m->count)
+       while (++j != m->count)
+         {
+           unsigned int p_flags1 = PF_R;
 
-         if (sectj_vle != sect0_vle)
-           break;
-        }
-      if (j >= m->count)
+           if ((m->sections[j]->flags & SEC_READONLY) == 0)
+             p_flags1 |= PF_W;
+           if ((m->sections[j]->flags & SEC_CODE) != 0)
+             {
+               p_flags1 |= PF_X;
+               if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+                 p_flags1 |= PF_PPC_VLE;
+               if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0)
+                 break;
+             }
+           p_flags |= p_flags1;
+         }
+      /* If we're splitting a segment which originally contained rw
+        sections then those sections might now only be in one of the
+        two parts.  So always set p_flags if splitting, even if we
+        are being called for objcopy with p_flags_valid set.  */
+      if (j != m->count || !m->p_flags_valid)
+       {
+         m->p_flags_valid = 1;
+         m->p_flags = p_flags;
+       }
+      if (j == m->count)
        continue;
 
-      /* sections 0..j-1 stay in this (current) segment,
+      /* Sections 0..j-1 stay in this (current) segment,
         the remainder are put in a new segment.
         The scan resumes with the new segment.  */
 
-      /* Fix the new segment.  */
       amt = sizeof (struct elf_segment_map);
       amt += (m->count - j - 1) * sizeof (asection *);
       n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
@@ -2462,20 +2596,13 @@ ppc_elf_modify_segment_map (bfd *abfd,
         return FALSE;
 
       n->p_type = PT_LOAD;
-      n->p_flags = PF_X | PF_R;
-      if (sectj_vle)
-        n->p_flags |= PF_PPC_VLE;
       n->count = m->count - j;
       for (k = 0; k < n->count; ++k)
-        {
-          n->sections[k] = m->sections[j+k];
-          m->sections[j+k] = NULL;
-       }
+       n->sections[k] = m->sections[j + k];
+      m->count = j;
+      m->p_size_valid = 0;
       n->next = m->next;
       m->next = n;
-
-      /* Fix the current segment  */
-      m->count = j;
     }
 
   return TRUE;
@@ -2488,16 +2615,16 @@ ppc_elf_modify_segment_map (bfd *abfd,
 
 static const struct bfd_elf_special_section ppc_elf_special_sections[] =
 {
-  { STRING_COMMA_LEN (".plt"),             0, SHT_NOBITS,   SHF_ALLOC + SHF_EXECINSTR },
-  { STRING_COMMA_LEN (".sbss"),           -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
-  { STRING_COMMA_LEN (".sbss2"),          -2, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".sdata"),          -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { STRING_COMMA_LEN (".sdata2"),         -2, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".tags"),            0, SHT_ORDERED,  SHF_ALLOC },
-  { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE,     0 },
-  { STRING_COMMA_LEN (".PPC.EMB.sbss0"),   0, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".PPC.EMB.sdata0"),  0, SHT_PROGBITS, SHF_ALLOC },
-  { NULL,                              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC },
+  { STRING_COMMA_LEN (APUINFO_SECTION_NAME), 0, SHT_NOTE, 0 },
+  { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { NULL, 0, 0, 0, 0 }
 };
 
 /* This is what we want for new plt/got.  */
@@ -2606,9 +2733,6 @@ apuinfo_list_finish (void)
   head = NULL;
 }
 
-#define APUINFO_SECTION_NAME   ".PPC.EMB.apuinfo"
-#define APUINFO_LABEL          "APUinfo"
-
 /* Scan the input BFDs and create a linked list of
    the APUinfo values that will need to be emitted.  */
 
@@ -2637,6 +2761,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
       if (asec == NULL)
        continue;
 
+      /* xgettext:c-format */
       error_message = _("corrupt %s section in %B");
       length = asec->size;
       if (length < 20)
@@ -2656,6 +2781,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
       if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
          || (bfd_bread (buffer, length, ibfd) != length))
        {
+         /* xgettext:c-format */
          error_message = _("unable to read in %s section from %B");
          goto fail;
        }
@@ -2697,6 +2823,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
       if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
        {
          ibfd = abfd;
+         /* xgettext:c-format */
          error_message = _("warning: unable to set size of %s section in %B");
        }
     }
@@ -2706,7 +2833,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
     free (buffer);
 
   if (error_message)
-    (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
+    _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
 }
 
 /* Prevent the output section from accumulating the input sections'
@@ -2746,7 +2873,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
   buffer = bfd_malloc (length);
   if (buffer == NULL)
     {
-      (*_bfd_error_handler)
+      _bfd_error_handler
        (_("failed to allocate space for new APUinfo section."));
       return;
     }
@@ -2766,10 +2893,10 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
     }
 
   if (length != asec->size)
-    (*_bfd_error_handler) (_("failed to compute new APUinfo section."));
+    _bfd_error_handler (_("failed to compute new APUinfo section."));
 
   if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
-    (*_bfd_error_handler) (_("failed to install new APUinfo section."));
+    _bfd_error_handler (_("failed to install new APUinfo section."));
 
   free (buffer);
 
@@ -2919,7 +3046,6 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
     }
 
   count = relplt->size / sizeof (Elf32_External_Rela);
-  stub_vma = glink_vma - (bfd_vma) count * 16;
   /* If the stubs are those for -shared/-pie then we might have
      multiple stubs for each plt entry.  If that is the case then
      there is no way to associate stubs with their plt entries short
@@ -2950,9 +3076,10 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
   if (s == NULL)
     return -1;
 
+  stub_vma = glink_vma;
   names = (char *) (s + count + 1 + (resolv_vma != 0));
-  p = relplt->relocation;
-  for (i = 0; i < count; i++, p++)
+  p = relplt->relocation + count - 1;
+  for (i = 0; i < count; i++)
     {
       size_t len;
 
@@ -2963,6 +3090,9 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
        s->flags |= BSF_GLOBAL;
       s->flags |= BSF_SYNTHETIC;
       s->section = glink;
+      stub_vma -= 16;
+      if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
+       stub_vma -= 32;
       s->value = stub_vma - glink->vma;
       s->name = names;
       s->udata.p = NULL;
@@ -2979,7 +3109,7 @@ ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
       memcpy (names, "@plt", sizeof ("@plt"));
       names += sizeof ("@plt");
       ++s;
-      stub_vma += 16;
+      --p;
     }
 
   /* Add a symbol at the start of the glink branch table.  */
@@ -3071,7 +3201,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
     case R_PPC_TPREL16_LO:
     case R_PPC_TPREL16_HI:
     case R_PPC_TPREL16_HA:
-      return !info->executable;
+      return !bfd_link_executable (info);
     }
 }
 
@@ -3126,7 +3256,11 @@ struct ppc_elf_link_hash_entry
 
   /* Nonzero if we have seen a small data relocation referring to this
      symbol.  */
-  unsigned char has_sda_refs;
+  unsigned char has_sda_refs : 1;
+
+  /* Flag use of given relocations.  */
+  unsigned char has_addr16_ha : 1;
+  unsigned char has_addr16_lo : 1;
 };
 
 #define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
@@ -3141,13 +3275,7 @@ struct ppc_elf_link_hash_table
   struct ppc_elf_params *params;
 
   /* Short-cuts to get to dynamic linker sections.  */
-  asection *got;
-  asection *relgot;
   asection *glink;
-  asection *plt;
-  asection *relplt;
-  asection *iplt;
-  asection *reliplt;
   asection *dynbss;
   asection *relbss;
   asection *dynsbss;
@@ -3159,9 +3287,6 @@ struct ppc_elf_link_hash_table
   /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
   asection *srelplt2;
 
-  /* The .got.plt section (VxWorks only)*/
-  asection *sgotplt;
-
   /* Shortcut to __tls_get_addr.  */
   struct elf_link_hash_entry *tls_get_addr;
 
@@ -3250,7 +3375,8 @@ static struct bfd_link_hash_table *
 ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
-  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 };
+  static struct ppc_elf_params default_params
+    = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0, 0 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -3296,6 +3422,7 @@ ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params)
 
   if (htab)
     htab->params = params;
+  params->pagesize_p2 = bfd_log2 (params->pagesize);
 }
 
 /* Create .got and the related sections.  */
@@ -3304,37 +3431,21 @@ static bfd_boolean
 ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
-  asection *s;
-  flagword flags;
 
   if (!_bfd_elf_create_got_section (abfd, info))
     return FALSE;
 
   htab = ppc_elf_hash_table (info);
-  htab->got = s = bfd_get_linker_section (abfd, ".got");
-  if (s == NULL)
-    abort ();
-
-  if (htab->is_vxworks)
-    {
-      htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt");
-      if (!htab->sgotplt)
-       abort ();
-    }
-  else
+  if (!htab->is_vxworks)
     {
       /* The powerpc .got has a blrl instruction in it.  Mark it
         executable.  */
-      flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
-              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      if (!bfd_set_section_flags (abfd, s, flags))
+      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;
     }
 
-  htab->relgot = bfd_get_linker_section (abfd, ".rela.got");
-  if (!htab->relgot)
-    abort ();
-
   return TRUE;
 }
 
@@ -3397,7 +3508,7 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
 
   flags = SEC_ALLOC | SEC_LINKER_CREATED;
   s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
-  htab->iplt = s;
+  htab->elf.iplt = s;
   if (s == NULL
       || !bfd_set_section_alignment (abfd, s, 4))
     return FALSE;
@@ -3405,7 +3516,7 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
   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->reliplt = s;
+  htab->elf.irelplt = s;
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 2))
     return FALSE;
@@ -3434,7 +3545,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
 
   htab = ppc_elf_hash_table (info);
 
-  if (htab->got == NULL
+  if (htab->elf.sgot == NULL
       && !ppc_elf_create_got (abfd, info))
     return FALSE;
 
@@ -3452,7 +3563,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL)
     return FALSE;
 
-  if (! info->shared)
+  if (! bfd_link_pic (info))
     {
       htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
       flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
@@ -3468,11 +3579,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
     return FALSE;
 
-  htab->relplt = bfd_get_linker_section (abfd, ".rela.plt");
-  htab->plt = s = bfd_get_linker_section (abfd, ".plt");
-  if (s == NULL)
-    abort ();
-
+  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.  */
@@ -3609,7 +3716,7 @@ ppc_elf_add_symbol_hook (bfd *abfd,
                         bfd_vma *valp)
 {
   if (sym->st_shndx == SHN_COMMON
-      && !info->relocatable
+      && !bfd_link_relocatable (info)
       && is_ppc_elf (info->output_bfd)
       && sym->st_size <= elf_gp_size (abfd))
     {
@@ -3636,11 +3743,10 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
-  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+  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 = TRUE;
+    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
 
   return TRUE;
 }
@@ -3832,13 +3938,15 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type)
          || r_type == R_PPC_ADDR24
          || r_type == R_PPC_ADDR14
          || r_type == R_PPC_ADDR14_BRTAKEN
-         || r_type == R_PPC_ADDR14_BRNTAKEN);
+         || r_type == R_PPC_ADDR14_BRNTAKEN
+         || r_type == R_PPC_VLE_REL24);
 }
 
 static void
 bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
 {
-  (*_bfd_error_handler)
+  _bfd_error_handler
+    /* xgettext:c-format */
     (_("%B: relocation %s cannot be used when making a shared object"),
      abfd,
      ppc_elf_howto_table[r_type]->name);
@@ -3863,7 +3971,7 @@ ppc_elf_check_relocs (bfd *abfd,
   asection *got2, *sreloc;
   struct elf_link_hash_entry *tga;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   /* Don't do anything special with non-loaded, non-alloced sections.
@@ -3908,6 +4016,7 @@ ppc_elf_check_relocs (bfd *abfd,
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
       int tls_type;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3928,7 +4037,7 @@ ppc_elf_check_relocs (bfd *abfd,
         This shows up in particular in an R_PPC_ADDR32 in the eabi
         startup code.  */
       if (h != NULL
-         && htab->got == NULL
+         && htab->elf.sgot == NULL
          && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
        {
          if (htab->elf.dynobj == NULL)
@@ -3940,6 +4049,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      ifunc = NULL;
       if (h == NULL && !htab->is_vxworks)
        {
          Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
@@ -3949,8 +4059,6 @@ ppc_elf_check_relocs (bfd *abfd,
 
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
-             struct plt_entry **ifunc;
-
              /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                             PLT_IFUNC);
@@ -3960,14 +4068,14 @@ ppc_elf_check_relocs (bfd *abfd,
              /* STT_GNU_IFUNC symbols must have a PLT entry;
                 In a non-pie executable even when there are
                 no plt calls.  */
-             if (!info->shared
+             if (!bfd_link_pic (info)
                  || is_branch_reloc (r_type))
                {
                  bfd_vma addend = 0;
                  if (r_type == R_PPC_PLTREL24)
                    {
                      ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                     if (info->shared)
+                     if (bfd_link_pic (info))
                        addend = rel->r_addend;
                    }
                  if (!update_plt_info (abfd, ifunc, got2, addend))
@@ -4018,7 +4126,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -4030,7 +4138,7 @@ ppc_elf_check_relocs (bfd *abfd,
          tls_type = TLS_TLS | TLS_DTPREL;
        dogottls:
          sec->has_tls_reloc = 1;
-         /* Fall thru */
+         /* Fall through.  */
 
          /* GOT16 relocations */
        case R_PPC_GOT16:
@@ -4038,7 +4146,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_GOT16_HI:
        case R_PPC_GOT16_HA:
          /* This symbol requires a global offset table entry.  */
-         if (htab->got == NULL)
+         if (htab->elf.sgot == NULL)
            {
              if (htab->elf.dynobj == NULL)
                htab->elf.dynobj = abfd;
@@ -4057,7 +4165,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* We may also need a plt entry if the symbol turns out to be
             an ifunc.  */
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
@@ -4066,7 +4174,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4084,7 +4192,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4102,7 +4210,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
        case R_PPC_SDAREL16:
          htab->sdata[0].sym->ref_regular = 1;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_VLE_SDAREL_LO16A:
        case R_PPC_VLE_SDAREL_LO16D:
@@ -4129,7 +4237,7 @@ ppc_elf_check_relocs (bfd *abfd,
          break;
 
        case R_PPC_EMB_SDA2REL:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4146,7 +4254,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_VLE_SDA21:
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4163,7 +4271,7 @@ 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 (info->shared)
+         if (bfd_link_pic (info))
            {
              bad_shared_reloc (abfd, r_type);
              return FALSE;
@@ -4184,21 +4292,21 @@ ppc_elf_check_relocs (bfd *abfd,
 #ifdef DEBUG
          fprintf (stderr, "Reloc requires a PLT entry\n");
 #endif
-         /* This symbol requires a procedure linkage table entry.  We
-            actually build the entry in finish_dynamic_symbol,
-            because this might be a case of linking PIC code without
-            linking in any dynamic objects, in which case we don't
-            need to generate a procedure linkage table after all.  */
-
+         /* This symbol requires a procedure linkage table entry.  */
          if (h == NULL)
            {
-             /* It does not make sense to have a procedure linkage
-                table entry for a local symbol.  */
-             info->callbacks->einfo (_("%P: %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;
+             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 */
+                   (_("%P: %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;
+               }
            }
          else
            {
@@ -4207,7 +4315,7 @@ ppc_elf_check_relocs (bfd *abfd,
              if (r_type == R_PPC_PLTREL24)
                {
                  ppc_elf_tdata (abfd)->makes_plt_call = 1;
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    addend = rel->r_addend;
                }
              h->needs_plt = 1;
@@ -4234,6 +4342,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          ppc_elf_tdata (abfd)->has_rel16 = 1;
          break;
 
@@ -4273,14 +4382,6 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
-             if (info->shared)
-               {
-                 info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
-                                         abfd, sec, rel->r_offset,
-                                         h->root.root.string);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-               }
              h->needs_plt = 1;
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
@@ -4309,7 +4410,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         if (info->shared)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
@@ -4322,7 +4423,7 @@ ppc_elf_check_relocs (bfd *abfd,
          if (h == NULL
              && got2 != NULL
              && (sec->flags & SEC_CODE) != 0
-             && info->shared
+             && bfd_link_pic (info)
              && htab->plt_type == PLT_UNSET)
            {
              /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
@@ -4357,7 +4458,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_ADDR16_HA:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
@@ -4367,6 +4468,10 @@ ppc_elf_check_relocs (bfd *abfd,
              /* We may need a copy reloc too.  */
              h->non_got_ref = 1;
              h->pointer_equality_needed = 1;
+             if (r_type == R_PPC_ADDR16_HA)
+               ppc_elf_hash_entry (h)->has_addr16_ha = 1;
+             if (r_type == R_PPC_ADDR16_LO)
+               ppc_elf_hash_entry (h)->has_addr16_lo = 1;
            }
          goto dodyn;
 
@@ -4391,7 +4496,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            {
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
@@ -4423,14 +4528,14 @@ ppc_elf_check_relocs (bfd *abfd,
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
                       && (!SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
@@ -4527,68 +4632,98 @@ ppc_elf_check_relocs (bfd *abfd,
   return TRUE;
 }
 \f
-
-/* Merge object attributes from IBFD into OBFD.  Raise an error if
-   there are conflicting attributes.  */
-static bfd_boolean
-ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
+   and OBFD, and merge non-conflicting ones.  */
+void
+_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;
 
-  if (!elf_known_obj_attributes_proc (obfd)[0].i)
-    {
-      /* This is the first object.  Copy the attributes.  */
-      _bfd_elf_copy_obj_attributes (ibfd, obfd);
-
-      /* Use the Tag_null value to indicate the attributes have been
-        initialized.  */
-      elf_known_obj_attributes_proc (obfd)[0].i = 1;
-
-      return TRUE;
-    }
-
   in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
   out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
 
-  /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
-     non-conflicting ones.  */
   in_attr = &in_attrs[Tag_GNU_Power_ABI_FP];
   out_attr = &out_attrs[Tag_GNU_Power_ABI_FP];
+
   if (in_attr->i != out_attr->i)
     {
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
+      int in_fp = in_attr->i & 3;
+      int out_fp = out_attr->i & 3;
+
+      if (in_fp == 0)
        ;
-      else if (out_attr->i == 1 && in_attr->i == 2)
+      else if (out_fp == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i ^= in_fp;
+       }
+      else if (out_fp != 2 && in_fp == 2)
        _bfd_error_handler
+         /* xgettext:c-format */
          (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
-      else if (out_attr->i == 1 && in_attr->i == 3)
+      else if (out_fp == 2 && in_fp != 2)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
-         obfd, ibfd);
-      else if (out_attr->i == 3 && in_attr->i == 1)
+         /* xgettext:c-format */
+         (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+      else if (out_fp == 1 && in_fp == 3)
        _bfd_error_handler
-         (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
-         ibfd, obfd);
-      else if (out_attr->i == 3 && in_attr->i == 2)
+         /* xgettext:c-format */
+         (_("Warning: %B uses double-precision hard float, "
+            "%B uses single-precision hard float"), obfd, ibfd);
+      else if (out_fp == 3 && in_fp == 1)
        _bfd_error_handler
-         (_("Warning: %B uses soft float, %B uses single-precision hard float"),
-         ibfd, obfd);
-      else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
+         /* xgettext:c-format */
+         (_("Warning: %B uses double-precision hard float, "
+            "%B uses single-precision hard float"), ibfd, obfd);
+
+      in_fp = in_attr->i & 0xc;
+      out_fp = out_attr->i & 0xc;
+      if (in_fp == 0)
+       ;
+      else if (out_fp == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i ^= in_fp;
+       }
+      else if (out_fp != 2 * 4 && in_fp == 2 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
-      else if (in_attr->i > 3)
+         /* xgettext:c-format */
+         (_("Warning: %B uses 64-bit long double, "
+            "%B uses 128-bit long double"), ibfd, obfd);
+      else if (in_fp != 2 * 4 && out_fp == 2 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
-          in_attr->i);
-      else
+         /* xgettext:c-format */
+         (_("Warning: %B uses 64-bit long double, "
+            "%B uses 128-bit long double"), obfd, ibfd);
+      else if (out_fp == 1 * 4 && in_fp == 3 * 4)
        _bfd_error_handler
-         (_("Warning: %B uses unknown floating point ABI %d"), obfd,
-          out_attr->i);
+         /* xgettext:c-format */
+         (_("Warning: %B uses IBM long double, "
+            "%B uses IEEE long double"), ibfd, obfd);
+      else if (out_fp == 3 * 4 && in_fp == 1 * 4)
+       _bfd_error_handler
+         /* xgettext:c-format */
+         (_("Warning: %B uses IBM long double, "
+            "%B uses IEEE long double"), obfd, ibfd);
     }
+}
+
+/* Merge object attributes from IBFD into OBFD.  Warn if
+   there are conflicting attributes.  */
+static bfd_boolean
+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;
+
+  _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
+  obfd = info->output_bfd;
+  in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+  out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
 
   /* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and
      merge non-conflicting ones.  */
@@ -4596,48 +4731,38 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
   out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
   if (in_attr->i != out_attr->i)
     {
-      const char *in_abi = NULL, *out_abi = NULL;
-
-      switch (in_attr->i)
-       {
-       case 1: in_abi = "generic"; break;
-       case 2: in_abi = "AltiVec"; break;
-       case 3: in_abi = "SPE"; break;
-       }
+      int in_vec = in_attr->i & 3;
+      int out_vec = out_attr->i & 3;
 
-      switch (out_attr->i)
+      if (in_vec == 0)
+       ;
+      else if (out_vec == 0)
        {
-       case 1: out_abi = "generic"; break;
-       case 2: out_abi = "AltiVec"; break;
-       case 3: out_abi = "SPE"; break;
+         out_attr->type = 1;
+         out_attr->i = in_vec;
        }
-
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
-       ;
       /* For now, allow generic to transition to AltiVec or SPE
         without a warning.  If GCC marked files with their stack
         alignment and used don't-care markings for files which are
         not affected by the vector ABI, we could warn about this
         case too.  */
-      else if (out_attr->i == 1)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 1)
+      else if (in_vec == 1)
        ;
-      else if (in_abi == NULL)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown vector ABI %d"), ibfd,
-          in_attr->i);
-      else if (out_abi == NULL)
+      else if (out_vec == 1)
+       {
+         out_attr->type = 1;
+         out_attr->i = in_vec;
+       }
+      else if (out_vec < in_vec)
        _bfd_error_handler
-         (_("Warning: %B uses unknown vector ABI %d"), obfd,
-          in_attr->i);
-      else
+         /* xgettext:c-format */
+         (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+          obfd, ibfd);
+      else if (out_vec > in_vec)
        _bfd_error_handler
-         (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
-          ibfd, obfd, in_abi, out_abi);
+         /* xgettext:c-format */
+         (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+          ibfd, obfd);
     }
 
   /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
@@ -4646,29 +4771,30 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
   out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
   if (in_attr->i != out_attr->i)
     {
-      out_attr->type = 1;
-      if (out_attr->i == 0)
-       out_attr->i = in_attr->i;
-      else if (in_attr->i == 0)
+      int in_struct = in_attr->i & 3;
+      int out_struct = out_attr->i & 3;
+
+      if (in_struct == 0 || in_struct == 3)
        ;
-      else if (out_attr->i == 1 && in_attr->i == 2)
-       _bfd_error_handler
-         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
-      else if (out_attr->i == 2 && in_attr->i == 1)
-       _bfd_error_handler
-         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
-      else if (in_attr->i > 2)
-       _bfd_error_handler
-         (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
-          in_attr->i);
-      else
-       _bfd_error_handler
-         (_("Warning: %B uses unknown small structure return convention %d"), obfd,
-          out_attr->i);
+      else if (out_struct == 0)
+       {
+         out_attr->type = 1;
+         out_attr->i = in_struct;
+       }
+      else if (out_struct < in_struct)
+       _bfd_error_handler
+         /* xgettext:c-format */
+         (_("Warning: %B uses r3/r4 for small structure returns, "
+            "%B uses memory"), obfd, ibfd);
+      else if (out_struct > in_struct)
+       _bfd_error_handler
+         /* xgettext:c-format */
+         (_("Warning: %B uses r3/r4 for small structure returns, "
+            "%B uses memory"), ibfd, obfd);
     }
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, obfd);
+  _bfd_elf_merge_object_attributes (ibfd, info);
 
   return TRUE;
 }
@@ -4677,8 +4803,9 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
    object file when linking.  */
 
 static bfd_boolean
-ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+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;
@@ -4687,10 +4814,10 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
     return TRUE;
 
   /* Check if we have the same endianness.  */
-  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+  if (! _bfd_generic_verify_endian_match (ibfd, info))
     return FALSE;
 
-  if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
+  if (!ppc_elf_merge_obj_attributes (ibfd, info))
     return FALSE;
 
   new_flags = elf_elfheader (ibfd)->e_flags;
@@ -4716,7 +4843,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
          && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: compiled with -mrelocatable and linked with "
               "modules compiled normally"), ibfd);
        }
@@ -4724,7 +4851,7 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
               && (old_flags & EF_PPC_RELOCATABLE) != 0)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
            (_("%B: compiled normally and linked with "
               "modules compiled with -mrelocatable"), ibfd);
        }
@@ -4751,7 +4878,8 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
       if (new_flags != old_flags)
        {
          error = TRUE;
-         (*_bfd_error_handler)
+         _bfd_error_handler
+           /* xgettext:c-format */
            (_("%B: uses different e_flags (0x%lx) fields "
               "than previous modules (0x%lx)"),
             ibfd, (long) new_flags, (long) old_flags);
@@ -4768,21 +4896,61 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 }
 
 static void
-ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
+ppc_elf_vle_split16 (bfd *input_bfd,
+                    asection *input_section,
+                    unsigned long offset,
+                    bfd_byte *loc,
                     bfd_vma value,
-                    split16_format_type split16_format)
-
+                    split16_format_type split16_format,
+                    bfd_boolean fixup)
 {
-  unsigned int insn, top5;
-
-  insn = bfd_get_32 (output_bfd, loc);
+  unsigned int insn, opcode, top5;
+
+  insn = bfd_get_32 (input_bfd, loc);
+  opcode = insn & 0xf300f800;
+  if (opcode == E_OR2I_INSN
+      || opcode == E_AND2I_DOT_INSN
+      || opcode == E_OR2IS_INSN
+      || opcode == E_LIS_INSN
+      || opcode == E_AND2IS_DOT_INSN)
+    {
+      if (split16_format != split16a_type)
+       {
+         if (fixup)
+           split16_format = split16a_type;
+         else
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%B(%A+0x%lx): expected 16A style relocation on 0x%08x insn"),
+              input_bfd, input_section, offset, opcode);
+       }
+    }
+  else if (opcode == E_ADD2I_DOT_INSN
+          || opcode == E_ADD2IS_INSN
+          || opcode == E_CMP16I_INSN
+          || opcode == E_MULL2I_INSN
+          || opcode == E_CMPL16I_INSN
+          || opcode == E_CMPH16I_INSN
+          || opcode == E_CMPHL16I_INSN)
+    {
+      if (split16_format != split16d_type)
+       {
+         if (fixup)
+           split16_format = split16d_type;
+         else
+           _bfd_error_handler
+             /* xgettext:c-format */
+             (_("%B(%A+0x%lx): expected 16D style relocation on 0x%08x insn"),
+              input_bfd, input_section, offset, opcode);
+       }
+    }
   top5 = value & 0xf800;
-  top5 = top5 << (split16_format == split16a_type ? 9 : 5);
+  top5 = top5 << (split16_format == split16a_type ? 5 : 9);
+  insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x1f007ff);
   insn |= top5;
   insn |= value & 0x7ff;
-  bfd_put_32 (output_bfd, insn, loc);
+  bfd_put_32 (input_bfd, insn, loc);
 }
-
 \f
 /* Choose which PLT scheme to use, and set .plt flags appropriately.
    Returns -1 on error, 0 for old PLT, 1 for new PLT.  */
@@ -4801,7 +4969,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       if (htab->params->plt_style == PLT_OLD)
        htab->plt_type = PLT_OLD;
-      else if (info->shared
+      else if (bfd_link_pic (info)
               && htab->elf.dynamic_sections_created
               && (h = elf_link_hash_lookup (&htab->elf, "_mcount",
                                             FALSE, FALSE, TRUE)) != NULL
@@ -4861,13 +5029,13 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
       /* The new PLT is a loaded section.  */
-      if (htab->plt != NULL
-         && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
+      if (htab->elf.splt != NULL
+         && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.splt, flags))
        return -1;
 
       /* The new GOT is not executable.  */
-      if (htab->got != NULL
-         && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags))
+      if (htab->elf.sgot != NULL
+         && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.sgot, flags))
        return -1;
     }
   else
@@ -4917,7 +5085,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
   const Elf_Internal_Rela *rel, *relend;
   asection *got2;
 
-  if (info->relocatable)
+  if (bfd_link_relocatable (info))
     return TRUE;
 
   if ((sec->flags & SEC_ALLOC) == 0)
@@ -4963,7 +5131,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
       if (!htab->is_vxworks
          && h == NULL
          && local_got_refcounts != NULL
-         && (!info->shared
+         && (!bfd_link_pic (info)
              || is_branch_reloc (r_type)))
        {
          struct plt_entry **local_plt = (struct plt_entry **)
@@ -4976,7 +5144,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
              if (ent->plt.refcount > 0)
@@ -5011,7 +5179,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
            {
              if (h->got.refcount > 0)
                h->got.refcount--;
-             if (!info->shared)
+             if (!bfd_link_pic (info))
                {
                  struct plt_entry *ent;
 
@@ -5034,7 +5202,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_REL32:
          if (h == NULL || h == htab->elf.hgot)
            break;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_ADDR32:
        case R_PPC_ADDR24:
@@ -5047,8 +5215,9 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
-         if (info->shared)
+         if (bfd_link_pic (info))
            break;
+         /* Fall through.  */
 
        case R_PPC_PLT32:
        case R_PPC_PLTREL24:
@@ -5061,7 +5230,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (&h->plt.plist, got2, addend);
              if (ent != NULL && ent->plt.refcount > 0)
@@ -5087,6 +5256,9 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
   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;
@@ -5118,6 +5290,7 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
                  tga->root.type = bfd_link_hash_indirect;
                  tga->root.u.i.link = &opt->root;
                  ppc_elf_copy_indirect_symbol (info, opt, tga);
+                 opt->forced_local = 0;
                  if (opt->dynindx != -1)
                    {
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
@@ -5135,11 +5308,11 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
        htab->params->no_tls_get_addr_opt = TRUE;
     }
   if (htab->plt_type == PLT_NEW
-      && htab->plt != NULL
-      && htab->plt->output_section != NULL)
+      && htab->elf.splt != NULL
+      && htab->elf.splt->output_section != NULL)
     {
-      elf_section_type (htab->plt->output_section) = SHT_PROGBITS;
-      elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
+      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);
@@ -5184,7 +5357,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
   struct ppc_elf_link_hash_table *htab;
   int pass;
 
-  if (info->relocatable || !info->executable)
+  if (!bfd_link_executable (info))
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
@@ -5272,7 +5445,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                    case R_PPC_GOT_TLSLD16:
                    case R_PPC_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC_GOT_TLSLD16_HI:
                    case R_PPC_GOT_TLSLD16_HA:
@@ -5290,7 +5463,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                    case R_PPC_GOT_TLSGD16:
                    case R_PPC_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
-                     /* Fall thru */
+                     /* Fall through.  */
 
                    case R_PPC_GOT_TLSGD16_HI:
                    case R_PPC_GOT_TLSGD16_HA:
@@ -5357,7 +5530,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      struct plt_entry *ent;
                      bfd_vma addend = 0;
 
-                     if (info->shared
+                     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,
@@ -5542,6 +5715,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                   && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
        }
+      h->protected_def = 0;
       return TRUE;
     }
   else
@@ -5568,13 +5742,42 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      only references to the symbol are via the global offset table.
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
-  if (info->shared)
-    return TRUE;
+  if (bfd_link_pic (info))
+    {
+      h->protected_def = 0;
+      return TRUE;
+    }
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
   if (!h->non_got_ref)
-    return TRUE;
+    {
+      h->protected_def = 0;
+      return TRUE;
+    }
+
+  /* Protected variables do not work with .dynbss.  The copy in
+     .dynbss won't be used by the shared library with the protected
+     definition for the variable.  Editing to PIC, or text relocations
+     are preferable to an incorrect program.  */
+  if (h->protected_def)
+    {
+      if (ELIMINATE_COPY_RELOCS
+         && ppc_elf_hash_entry (h)->has_addr16_ha
+         && ppc_elf_hash_entry (h)->has_addr16_lo
+         && htab->params->pic_fixup == 0
+         && info->disable_target_specific_optimizations <= 1)
+       htab->params->pic_fixup = 1;
+      h->non_got_ref = 0;
+      return TRUE;
+    }
+
+  /* If -z nocopyreloc was given, we won't generate them either.  */
+  if (info->nocopyreloc)
+    {
+      h->non_got_ref = 0;
+      return TRUE;
+    }
 
    /* If we didn't find any dynamic relocs in read-only sections, then
       we'll be keeping the dynamic relocs and avoiding the copy reloc.
@@ -5628,7 +5831,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       h->needs_copy = 1;
     }
 
-  return _bfd_elf_adjust_dynamic_copy (h, s);
+  return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 \f
 /* Generate a symbol to mark plt call stubs.  For non-PIC code the sym is
@@ -5648,7 +5851,7 @@ add_stub_sym (struct plt_entry *ent,
   const char *stub;
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     stub = ".plt_pic32.";
   else
     stub = ".plt_call32.";
@@ -5679,6 +5882,7 @@ add_stub_sym (struct plt_entry *ent,
       sh->ref_regular_nonweak = 1;
       sh->forced_local = 1;
       sh->non_elf = 0;
+      sh->root.linker_def = 1;
     }
   return TRUE;
 }
@@ -5694,8 +5898,8 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
 
   if (htab->plt_type == PLT_VXWORKS)
     {
-      where = htab->got->size;
-      htab->got->size += need;
+      where = htab->elf.sgot->size;
+      htab->elf.sgot->size += need;
     }
   else
     {
@@ -5707,14 +5911,14 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
        }
       else
        {
-         if (htab->got->size + need > max_before_header
-             && htab->got->size <= max_before_header)
+         if (htab->elf.sgot->size + need > max_before_header
+             && htab->elf.sgot->size <= max_before_header)
            {
-             htab->got_gap = max_before_header - htab->got->size;
-             htab->got->size = max_before_header + htab->got_header_size;
+             htab->got_gap = max_before_header - htab->elf.sgot->size;
+             htab->elf.sgot->size = max_before_header + htab->got_header_size;
            }
-         where = htab->got->size;
-         htab->got->size += need;
+         where = htab->elf.sgot->size;
+         htab->elf.sgot->size += need;
        }
     }
   return where;
@@ -5756,13 +5960,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              }
 
            dyn = htab->elf.dynamic_sections_created;
-           if (info->shared
+           if (bfd_link_pic (info)
                || h->type == STT_GNU_IFUNC
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
              {
-               asection *s = htab->plt;
+               asection *s = htab->elf.splt;
                if (!dyn || h->dynindx == -1)
-                 s = htab->iplt;
+                 s = htab->elf.iplt;
 
                if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
                  {
@@ -5774,7 +5978,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                    ent->plt.offset = plt_offset;
 
                    s = htab->glink;
-                   if (!doneone || info->shared)
+                   if (!doneone || bfd_link_pic (info))
                      {
                        glink_offset = s->size;
                        s->size += GLINK_ENTRY_SIZE;
@@ -5783,7 +5987,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                          s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
                      }
                    if (!doneone
-                       && !info->shared
+                       && !bfd_link_pic (info)
                        && h->def_dynamic
                        && !h->def_regular)
                      {
@@ -5822,7 +6026,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                           relocations, and is required to make
                           function pointers compare as equal between
                           the normal executable and the shared library.  */
-                       if (! info->shared
+                       if (! bfd_link_pic (info)
                            && h->def_dynamic
                            && !h->def_regular)
                          {
@@ -5848,15 +6052,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                  {
                    if (!htab->elf.dynamic_sections_created
                        || h->dynindx == -1)
-                     htab->reliplt->size += sizeof (Elf32_External_Rela);
+                     htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
                    else
                      {
-                       htab->relplt->size += sizeof (Elf32_External_Rela);
+                       htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
 
                        if (htab->plt_type == PLT_VXWORKS)
                          {
                            /* Allocate space for the unloaded relocations.  */
-                           if (!info->shared
+                           if (!bfd_link_pic (info)
                                && htab->elf.dynamic_sections_created)
                              {
                                if (ent->plt.offset
@@ -5874,7 +6078,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 
                            /* Every PLT entry has an associated GOT entry in
                               .got.plt.  */
-                           htab->sgotplt->size += 4;
+                           htab->elf.sgotplt->size += 4;
                          }
                      }
                    doneone = TRUE;
@@ -5899,7 +6103,13 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     }
 
   eh = (struct ppc_elf_link_hash_entry *) h;
-  if (eh->elf.got.refcount > 0)
+  if (eh->elf.got.refcount > 0
+      || (ELIMINATE_COPY_RELOCS
+         && !eh->elf.def_regular
+         && eh->elf.protected_def
+         && eh->has_addr16_ha
+         && eh->has_addr16_lo
+         && htab->params->pic_fixup > 0))
     {
       bfd_boolean dyn;
       unsigned int need;
@@ -5942,15 +6152,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        {
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
-         if ((info->shared
+         if ((bfd_link_pic (info)
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
                  || eh->elf.root.type != bfd_link_hash_undefweak))
            {
-             asection *rsec = htab->relgot;
+             asection *rsec = htab->elf.srelgot;
 
              if (eh->elf.type == STT_GNU_IFUNC)
-               rsec = htab->reliplt;
+               rsec = htab->elf.irelplt;
              /* All the entries we allocated need relocs.
                 Except LD only needs one.  */
              if ((eh->tls_mask & TLS_LD) != 0
@@ -5973,7 +6183,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
      space for relocs that have become local due to symbol visibility
      changes.  */
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       /* Relocs that use pc_count are those that appear on a call insn,
         or certain REL relocs (see must_be_dyn_reloc) that can be
@@ -6042,7 +6252,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         dynamic.  */
 
       if (!h->non_got_ref
-         && !h->def_regular)
+         && !h->def_regular
+         && !(h->protected_def
+              && eh->has_addr16_ha
+              && eh->has_addr16_lo
+              && htab->params->pic_fixup > 0))
        {
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
@@ -6069,7 +6283,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
       if (eh->elf.type == STT_GNU_IFUNC)
-       sreloc = htab->reliplt;
+       sreloc = htab->elf.irelplt;
       sreloc->size += p->count * sizeof (Elf32_External_Rela);
     }
 
@@ -6130,7 +6344,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
+      if (bfd_link_executable (info) && !info->nointerp)
        {
          s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
          BFD_ASSERT (s != NULL);
@@ -6187,7 +6401,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                {
                  asection *sreloc = elf_section_data (p->sec)->sreloc;
                  if (p->ifunc)
-                   sreloc = htab->reliplt;
+                   sreloc = htab->elf.irelplt;
                  sreloc->size += p->count * sizeof (Elf32_External_Rela);
                  if ((p->sec->output_section->flags
                       & (SEC_READONLY | SEC_ALLOC))
@@ -6230,11 +6444,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
            else
              {
                *local_got = allocate_got (htab, need);
-               if (info->shared)
+               if (bfd_link_pic (info))
                  {
-                   asection *srel = htab->relgot;
+                   asection *srel = htab->elf.srelgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
-                     srel = htab->reliplt;
+                     srel = htab->elf.irelplt;
                    srel->size += need * (sizeof (Elf32_External_Rela) / 4);
                  }
              }
@@ -6255,7 +6469,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               s = htab->iplt;
+               s = htab->elf.iplt;
 
                if (!doneone)
                  {
@@ -6265,7 +6479,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
                ent->plt.offset = plt_offset;
 
                s = htab->glink;
-               if (!doneone || info->shared)
+               if (!doneone || bfd_link_pic (info))
                  {
                    glink_offset = s->size;
                    s->size += GLINK_ENTRY_SIZE;
@@ -6274,7 +6488,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
                if (!doneone)
                  {
-                   htab->reliplt->size += sizeof (Elf32_External_Rela);
+                   htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
                    doneone = TRUE;
                  }
              }
@@ -6289,13 +6503,13 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
   if (htab->tlsld_got.refcount > 0)
     {
       htab->tlsld_got.offset = allocate_got (htab, 8);
-      if (info->shared)
-       htab->relgot->size += sizeof (Elf32_External_Rela);
+      if (bfd_link_pic (info))
+       htab->elf.srelgot->size += sizeof (Elf32_External_Rela);
     }
   else
     htab->tlsld_got.offset = (bfd_vma) -1;
 
-  if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
+  if (htab->elf.sgot != NULL && htab->plt_type != PLT_VXWORKS)
     {
       unsigned int g_o_t = 32768;
 
@@ -6303,17 +6517,17 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
         for old plt/got the got size will be 0 to 32764 (not allocated),
         or 32780 to 65536 (header allocated).  For new plt/got, the
         corresponding ranges are 0 to 32768 and 32780 to 65536.  */
-      if (htab->got->size <= 32768)
+      if (htab->elf.sgot->size <= 32768)
        {
-         g_o_t = htab->got->size;
+         g_o_t = htab->elf.sgot->size;
          if (htab->plt_type == PLT_OLD)
            g_o_t += 4;
-         htab->got->size += htab->got_header_size;
+         htab->elf.sgot->size += htab->got_header_size;
        }
 
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
@@ -6336,7 +6550,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       && htab->elf.dynamic_sections_created)
     {
       htab->glink_pltresolve = htab->glink->size;
-      /* Space for the branch table.  */
+      /* Space for the branch table.  ??? We don't need entries for
+        non-dynamic symbols in this table.  This case can arise with
+        static ifuncs or forced local ifuncs.  */
       htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
       /* Pad out to align the start of PLTresolve.  */
       htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
@@ -6360,6 +6576,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
          sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
                                     TRUE, FALSE, FALSE);
@@ -6375,6 +6592,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
        }
     }
@@ -6387,7 +6605,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
     {
       s = htab->glink_eh_frame;
       s->size = sizeof (glink_eh_frame_cie) + 20;
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          s->size += 4;
          if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
@@ -6405,8 +6623,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
-      if (s == htab->plt
-         || s == htab->got)
+      if (s == htab->elf.splt
+         || s == htab->elf.sgot)
        {
          /* We'd like to strip these sections if they aren't needed, but if
             we've exported dynamic symbols from them we must leave them.
@@ -6416,10 +6634,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (s == htab->iplt
+      else if (s == htab->elf.iplt
               || s == htab->glink
               || s == htab->glink_eh_frame
-              || s == htab->sgotplt
+              || s == htab->elf.sgotplt
               || s == htab->sbss
               || s == htab->dynbss
               || s == htab->dynsbss)
@@ -6484,13 +6702,13 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 #define add_dynamic_entry(TAG, VAL) \
   _bfd_elf_add_dynamic_entry (info, TAG, VAL)
 
-      if (info->executable)
+      if (bfd_link_executable (info))
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
            return FALSE;
        }
 
-      if (htab->plt != NULL && htab->plt->size != 0)
+      if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
        {
          if (!add_dynamic_entry (DT_PLTGOT, 0)
              || !add_dynamic_entry (DT_PLTRELSZ, 0)
@@ -6563,7 +6781,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       /* Augmentation.  */
       p += 1;
 
-      if (info->shared
+      if (bfd_link_pic (info)
          && htab->elf.dynamic_sections_created)
        {
          bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
@@ -6681,6 +6899,7 @@ static const int stub_entry[] =
 struct ppc_elf_relax_info
 {
   unsigned int workaround_size;
+  unsigned int picfixup_size;
 };
 
 /* This function implements long branch trampolines, and the ppc476
@@ -6694,9 +6913,9 @@ ppc_elf_relax_section (bfd *abfd,
                       struct bfd_link_info *link_info,
                       bfd_boolean *again)
 {
-  struct one_fixup
+  struct one_branch_fixup
   {
-    struct one_fixup *next;
+    struct one_branch_fixup *next;
     asection *tsec;
     /* Final link, can use the symbol offset.  For a
        relocatable link we use the symbol's index.  */
@@ -6709,12 +6928,12 @@ ppc_elf_relax_section (bfd *abfd,
   Elf_Internal_Sym *isymbuf = NULL;
   Elf_Internal_Rela *internal_relocs = NULL;
   Elf_Internal_Rela *irel, *irelend = NULL;
-  struct one_fixup *fixups = NULL;
+  struct one_branch_fixup *branch_fixups = NULL;
   struct ppc_elf_relax_info *relax_info = NULL;
   unsigned changes = 0;
   bfd_boolean workaround_change;
   struct ppc_elf_link_hash_table *htab;
-  bfd_size_type trampbase, trampoff, newsize;
+  bfd_size_type trampbase, trampoff, newsize, picfixup_size;
   asection *got2;
   bfd_boolean maybe_pasted;
 
@@ -6730,7 +6949,7 @@ ppc_elf_relax_section (bfd *abfd,
   /* 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 (link_info->relocatable && link_info->shared)
+  if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info))
     return TRUE;
 
   htab = ppc_elf_hash_table (link_info);
@@ -6746,7 +6965,8 @@ ppc_elf_relax_section (bfd *abfd,
              || isec->sec_info_type == SEC_INFO_TYPE_TARGET);
   isec->sec_info_type = SEC_INFO_TYPE_TARGET;
 
-  if (htab->params->ppc476_workaround)
+  if (htab->params->ppc476_workaround
+      || htab->params->pic_fixup > 0)
     {
       if (elf_section_data (isec)->sec_info == NULL)
        {
@@ -6767,8 +6987,9 @@ ppc_elf_relax_section (bfd *abfd,
     trampoff += 4;
 
   symtab_hdr = &elf_symtab_hdr (abfd);
-
-  if (htab->params->branch_trampolines)
+  picfixup_size = 0;
+  if (htab->params->branch_trampolines
+      || htab->params->pic_fixup > 0)
     {
       /* Get a copy of the native relocations.  */
       if (isec->reloc_count != 0)
@@ -6787,9 +7008,9 @@ ppc_elf_relax_section (bfd *abfd,
          unsigned long r_type = ELF32_R_TYPE (irel->r_info);
          bfd_vma toff, roff;
          asection *tsec;
-         struct one_fixup *f;
+         struct one_branch_fixup *f;
          size_t insn_offset = 0;
-         bfd_vma max_branch_offset, val;
+         bfd_vma max_branch_offset = 0, val;
          bfd_byte *hit_addr;
          unsigned long t0;
          struct elf_link_hash_entry *h;
@@ -6810,6 +7031,11 @@ ppc_elf_relax_section (bfd *abfd,
              max_branch_offset = 1 << 15;
              break;
 
+           case R_PPC_ADDR16_HA:
+             if (htab->params->pic_fixup > 0)
+               break;
+             continue;
+
            default:
              continue;
            }
@@ -6867,7 +7093,7 @@ ppc_elf_relax_section (bfd *abfd,
                       || h->root.type == bfd_link_hash_undefweak)
                {
                  tsec = bfd_und_section_ptr;
-                 toff = link_info->relocatable ? indx : 0;
+                 toff = bfd_link_relocatable (link_info) ? indx : 0;
                }
              else
                continue;
@@ -6875,8 +7101,7 @@ ppc_elf_relax_section (bfd *abfd,
              /* If this branch is to __tls_get_addr then we may later
                 optimise away the call.  We won't be needing a long-
                 branch stub in that case.  */
-             if (link_info->executable
-                 && !link_info->relocatable
+             if (bfd_link_executable (link_info)
                  && h == htab->tls_get_addr
                  && irel != internal_relocs)
                {
@@ -6931,6 +7156,17 @@ ppc_elf_relax_section (bfd *abfd,
              sym_type = h->type;
            }
 
+         if (r_type == R_PPC_ADDR16_HA)
+           {
+             if (h != NULL
+                 && !h->def_regular
+                 && h->protected_def
+                 && ppc_elf_hash_entry (h)->has_addr16_ha
+                 && ppc_elf_hash_entry (h)->has_addr16_lo)
+               picfixup_size += 12;
+             continue;
+           }
+
          /* The condition here under which we call find_plt_ent must
             match that in relocate_section.  If we call find_plt_ent here
             but not in relocate_section, or vice versa, then the branch
@@ -6956,7 +7192,7 @@ ppc_elf_relax_section (bfd *abfd,
              bfd_vma addend = 0;
              struct plt_entry *ent;
 
-             if (r_type == R_PPC_PLTREL24 && link_info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info))
                addend = irel->r_addend;
              ent = find_plt_ent (plist, got2, addend);
              if (ent != NULL)
@@ -6971,7 +7207,7 @@ ppc_elf_relax_section (bfd *abfd,
                    }
                  else
                    {
-                     tsec = htab->plt;
+                     tsec = htab->elf.splt;
                      toff = ent->plt.offset;
                    }
                }
@@ -7022,7 +7258,7 @@ ppc_elf_relax_section (bfd *abfd,
            toff += irel->r_addend;
 
          /* Attempted -shared link of non-pic code loses.  */
-         if ((!link_info->relocatable
+         if ((!bfd_link_relocatable (link_info)
               && tsec == bfd_und_section_ptr)
              || tsec->output_section == NULL
              || (tsec->owner != NULL
@@ -7033,7 +7269,7 @@ ppc_elf_relax_section (bfd *abfd,
 
          /* If the branch is in range, no need to do anything.  */
          if (tsec != bfd_und_section_ptr
-             && (!link_info->relocatable
+             && (!bfd_link_relocatable (link_info)
                  /* A relocatable link may have sections moved during
                     final link, so do not presume they remain in range.  */
                  || tsec->output_section == isec->output_section))
@@ -7048,7 +7284,7 @@ ppc_elf_relax_section (bfd *abfd,
            }
 
          /* Look for an existing fixup to this address.  */
-         for (f = fixups; f ; f = f->next)
+         for (f = branch_fixups; f ; f = f->next)
            if (f->tsec == tsec && f->toff == toff)
              break;
 
@@ -7063,7 +7299,7 @@ ppc_elf_relax_section (bfd *abfd,
                   one.  We'll report an error later.  */
                continue;
 
-             if (link_info->shared)
+             if (bfd_link_pic (link_info))
                {
                  size = 4 * ARRAY_SIZE (shared_stub_entry);
                  insn_offset = 12;
@@ -7074,7 +7310,7 @@ ppc_elf_relax_section (bfd *abfd,
                  insn_offset = 0;
                }
              stub_rtype = R_PPC_RELAX;
-             if (tsec == htab->plt
+             if (tsec == htab->elf.splt
                  || tsec == htab->glink)
                {
                  stub_rtype = R_PPC_RELAX_PLT;
@@ -7093,11 +7329,11 @@ ppc_elf_relax_section (bfd *abfd,
 
              /* Record the fixup so we don't do it again this section.  */
              f = bfd_malloc (sizeof (*f));
-             f->next = fixups;
+             f->next = branch_fixups;
              f->tsec = tsec;
              f->toff = toff;
              f->trampoff = trampoff;
-             fixups = f;
+             branch_fixups = f;
 
              trampoff += size;
              changes++;
@@ -7147,10 +7383,10 @@ ppc_elf_relax_section (bfd *abfd,
            }
        }
 
-      while (fixups != NULL)
+      while (branch_fixups != NULL)
        {
-         struct one_fixup *f = fixups;
-         fixups = fixups->next;
+         struct one_branch_fixup *f = branch_fixups;
+         branch_fixups = branch_fixups->next;
          free (f);
        }
     }
@@ -7158,7 +7394,7 @@ ppc_elf_relax_section (bfd *abfd,
   workaround_change = FALSE;
   newsize = trampoff;
   if (htab->params->ppc476_workaround
-      && (!link_info->relocatable
+      && (!bfd_link_relocatable (link_info)
          || isec->output_section->alignment_power >= htab->params->pagesize_p2))
     {
       bfd_vma addr, end_addr;
@@ -7174,7 +7410,7 @@ ppc_elf_relax_section (bfd *abfd,
          /* Keep space aligned, to ensure the patch code itself does
             not cross a page.  Don't decrease size calculated on a
             previous pass as otherwise we might never settle on a layout.  */
-         newsize = 15 - (end_addr & 15);
+         newsize = 15 - ((end_addr - 1) & 15);
          newsize += crossings * 16;
          if (relax_info->workaround_size < newsize)
            {
@@ -7187,7 +7423,15 @@ ppc_elf_relax_section (bfd *abfd,
       newsize = trampoff + relax_info->workaround_size;
     }
 
-  if (changes || workaround_change)
+  if (htab->params->pic_fixup > 0)
+    {
+      picfixup_size -= relax_info->picfixup_size;
+      if (picfixup_size != 0)
+       relax_info->picfixup_size += picfixup_size;
+      newsize += relax_info->picfixup_size;
+    }
+
+  if (changes != 0 || picfixup_size != 0 || workaround_change)
     isec->size = newsize;
 
   if (isymbuf != NULL
@@ -7214,6 +7458,7 @@ ppc_elf_relax_section (bfd *abfd,
        }
     }
 
+  changes += picfixup_size;
   if (changes != 0)
     {
       /* Append sufficient NOP relocs so we can write out relocation
@@ -7248,10 +7493,10 @@ ppc_elf_relax_section (bfd *abfd,
   return TRUE;
 
  error_return:
-  while (fixups != NULL)
+  while (branch_fixups != NULL)
     {
-      struct one_fixup *f = fixups;
-      fixups = fixups->next;
+      struct one_branch_fixup *f = branch_fixups;
+      branch_fixups = branch_fixups->next;
       free (f);
     }
   if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
@@ -7357,7 +7602,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
         + plt_sec->output_section->vma
         + plt_sec->output_offset);
 
-  if (info->shared)
+  if (bfd_link_pic (info))
     {
       bfd_vma got = 0;
 
@@ -7514,7 +7759,9 @@ is_insn_ds_form (unsigned int insn)
 static bfd_boolean
 is_insn_dq_form (unsigned int insn)
 {
-  return (insn & (0x3f << 26)) == 56u << 26; /* lq */
+  return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+         || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+             && (insn & 3) == 1));
 }
 
 /* The RELOCATE_SECTION function is called by the ELF backend linker
@@ -7560,20 +7807,23 @@ ppc_elf_relocate_section (bfd *output_bfd,
   struct elf_link_hash_entry **sym_hashes;
   struct ppc_elf_link_hash_table *htab;
   Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *wrel;
   Elf_Internal_Rela *relend;
   Elf_Internal_Rela outrel;
   asection *got2;
   bfd_vma *local_got_offsets;
   bfd_boolean ret = TRUE;
-  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
+  bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
   bfd_boolean is_vxworks_tls;
+  unsigned int picfixup_size = 0;
+  struct ppc_elf_relax_info *relax_info = NULL;
 
 #ifdef DEBUG
   _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
                      "%ld relocations%s",
                      input_bfd, input_section,
                      (long) input_section->reloc_count,
-                     (info->relocatable) ? " (relocatable)" : "");
+                     (bfd_link_relocatable (info)) ? " (relocatable)" : "");
 #endif
 
   got2 = bfd_get_section_by_name (input_bfd, ".got2");
@@ -7588,12 +7838,14 @@ 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 && info->shared
+  is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
                    && !strcmp (input_section->output_section->name,
                                ".tls_vars"));
-  rel = relocs;
+  if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+    relax_info = elf_section_data (input_section)->sec_info;
+  rel = wrel = relocs;
   relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
+  for (; rel < relend; wrel++, rel++)
     {
       enum elf_ppc_reloc_type r_type;
       bfd_vma addend;
@@ -7612,6 +7864,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
       struct plt_entry **ifunc;
       struct reloc_howto_struct alt_howto;
 
+    again:
       r_type = ELF32_R_TYPE (rel->r_info);
       sym = NULL;
       sec = NULL;
@@ -7648,11 +7901,25 @@ ppc_elf_relocate_section (bfd *output_bfd,
          howto = NULL;
          if (r_type < R_PPC_max)
            howto = ppc_elf_howto_table[r_type];
-         RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
-                                          rel, 1, relend, howto, 0, contents);
+
+         _bfd_clear_contents (howto, input_bfd, input_section,
+                              contents + rel->r_offset);
+         wrel->r_offset = rel->r_offset;
+         wrel->r_info = 0;
+         wrel->r_addend = 0;
+
+         /* For ld -r, remove relocations in debug sections against
+            sections defined in discarded sections.  Not done for
+            non-debug to preserve relocs in .eh_frame which the
+            eh_frame editing code expects to be present.  */
+         if (bfd_link_relocatable (info)
+             && (input_section->flags & SEC_DEBUGGING))
+           wrel--;
+
+         continue;
        }
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        {
          if (got2 != NULL
              && r_type == R_PPC_PLTREL24
@@ -7665,7 +7932,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (r_type != R_PPC_RELAX_PLT
              && r_type != R_PPC_RELAX_PLTREL24
              && r_type != R_PPC_RELAX)
-           continue;
+           goto copy_reloc;
        }
 
       /* TLS optimizations.  Replace instruction sequences and relocs
@@ -7708,10 +7975,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
            {
              bfd_vma insn;
 
-             insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
              insn &= 31 << 21;
              insn |= 0x3c020000;       /* addis 0,2,0 */
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+             bfd_put_32 (input_bfd, insn,
+                         contents + rel->r_offset - d_offset);
              r_type = R_PPC_TPREL16_HA;
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
            }
@@ -7723,11 +7992,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
            {
              bfd_vma insn;
 
-             insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
              insn = _bfd_elf_ppc_at_tls_transform (insn, 2);
              if (insn == 0)
                abort ();
-             bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
              r_type = R_PPC_TPREL16_LO;
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
 
@@ -7754,8 +8023,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          + R_PPC_GOT_TPREL16);
              else
                {
-                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  rel->r_offset -= d_offset;
+                 bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
                  r_type = R_PPC_NONE;
                }
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -7788,18 +8057,22 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  && branch_reloc_hash_match (input_bfd, rel + 1,
                                              htab->tls_get_addr))
                offset = rel[1].r_offset;
+             /* We read the low GOT_TLS insn because we need to keep
+                the destination reg.  It may be something other than
+                the usual r3, and moved to r3 before the call by
+                intervening code.  */
+             insn1 = bfd_get_32 (input_bfd,
+                                 contents + rel->r_offset - d_offset);
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
-                 insn1 = bfd_get_32 (output_bfd,
-                                     contents + rel->r_offset - d_offset);
-                 insn1 &= (1 << 26) - 1;
+                 insn1 &= (0x1f << 21) | (0x1f << 16);
                  insn1 |= 32 << 26;    /* lwz */
                  if (offset != (bfd_vma) -1)
                    {
                      rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
                      insn2 = 0x7c631214;       /* add 3,3,2 */
-                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                     bfd_put_32 (input_bfd, insn2, contents + offset);
                    }
                  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                            + R_PPC_GOT_TPREL16);
@@ -7808,7 +8081,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              else
                {
                  /* LE */
-                 insn1 = 0x3c620000;   /* addis 3,2,0 */
+                 insn1 &= 0x1f << 21;
+                 insn1 |= 0x3c020000;  /* addis r,2,0 */
                  if (tls_gd == 0)
                    {
                      /* Was an LD reloc.  */
@@ -7833,17 +8107,16 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      rel[1].r_offset = offset + d_offset;
                      rel[1].r_addend = rel->r_addend;
                      insn2 = 0x38630000;       /* addi 3,3,0 */
-                     bfd_put_32 (output_bfd, insn2, contents + offset);
+                     bfd_put_32 (input_bfd, insn2, contents + offset);
                    }
                }
-             bfd_put_32 (output_bfd, insn1,
+             bfd_put_32 (input_bfd, insn1,
                          contents + rel->r_offset - d_offset);
              if (tls_gd == 0)
                {
                  /* We changed the symbol on an LD reloc.  Start over
                     in order to get h, sym, sec etc. right.  */
-                 rel--;
-                 continue;
+                 goto again;
                }
            }
          break;
@@ -7868,7 +8141,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  insn2 = 0x38630000;   /* addi 3,3,0 */
                }
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
-             bfd_put_32 (output_bfd, insn2, contents + offset);
+             bfd_put_32 (input_bfd, insn2, contents + offset);
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (offset == rel[1].r_offset);
              rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
@@ -7896,13 +8169,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
              rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
              rel->r_offset += d_offset;
              insn2 = 0x38630000;       /* addi 3,3,0 */
-             bfd_put_32 (output_bfd, insn2,
+             bfd_put_32 (input_bfd, insn2,
                          contents + rel->r_offset - d_offset);
              /* Zap the reloc on the _tls_get_addr call too.  */
              BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
              rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
-             rel--;
-             continue;
+             goto again;
            }
          break;
        }
@@ -7918,7 +8190,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_REL14_BRTAKEN:
          branch_bit = BRANCH_PREDICT_BIT;
-         /* Fall thru */
+         /* Fall through.  */
 
          /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
@@ -7926,7 +8198,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          {
            bfd_vma insn;
 
-           insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+           insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
            insn &= ~BRANCH_PREDICT_BIT;
            insn |= branch_bit;
 
@@ -7938,11 +8210,122 @@ ppc_elf_relocate_section (bfd *output_bfd,
            if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
              insn ^= BRANCH_PREDICT_BIT;
 
-           bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+           bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
            break;
          }
        }
 
+      if (ELIMINATE_COPY_RELOCS
+         && h != NULL
+         && !h->def_regular
+         && h->protected_def
+         && ppc_elf_hash_entry (h)->has_addr16_ha
+         && ppc_elf_hash_entry (h)->has_addr16_lo
+         && htab->params->pic_fixup > 0)
+       {
+         /* Convert lis;addi or lis;load/store accessing a protected
+            variable defined in a shared library to PIC.  */
+         unsigned int insn;
+
+         if (r_type == R_PPC_ADDR16_HA)
+           {
+             insn = bfd_get_32 (input_bfd,
+                                contents + rel->r_offset - d_offset);
+             if ((insn & (0x3f << 26)) == (15u << 26)
+                 && (insn & (0x1f << 16)) == 0 /* lis */)
+               {
+                 bfd_byte *p;
+                 bfd_vma off;
+                 bfd_vma got_addr;
+
+                 p = (contents + input_section->size
+                      - relax_info->workaround_size
+                      - relax_info->picfixup_size
+                      + picfixup_size);
+                 off = (p - contents) - (rel->r_offset - d_offset);
+                 if (off > 0x1fffffc || (off & 3) != 0)
+                   info->callbacks->einfo
+                     (_("%P: %H: fixup branch overflow\n"),
+                      input_bfd, input_section, rel->r_offset);
+
+                 bfd_put_32 (input_bfd, B | off,
+                             contents + rel->r_offset - d_offset);
+                 got_addr = (htab->elf.sgot->output_section->vma
+                             + htab->elf.sgot->output_offset
+                             + (h->got.offset & ~1));
+                 wrel->r_offset = (p - contents) + d_offset;
+                 wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
+                 wrel->r_addend = got_addr;
+                 insn &= ~0xffff;
+                 insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+                 bfd_put_32 (input_bfd, insn, p);
+
+                 /* Convert lis to lwz, loading address from GOT.  */
+                 insn &= ~0xffff;
+                 insn ^= (32u ^ 15u) << 26;
+                 insn |= (insn & (0x1f << 21)) >> 5;
+                 insn |= got_addr & 0xffff;
+                 bfd_put_32 (input_bfd, insn, p + 4);
+
+                 bfd_put_32 (input_bfd, B | ((-4 - off) & 0x3ffffff), p + 8);
+                 picfixup_size += 12;
+
+                 /* Use one of the spare relocs, so --emit-relocs
+                    output is reasonable.  */
+                 memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
+                 wrel++, rel++;
+                 rel->r_offset = wrel[-1].r_offset + 4;
+                 rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO);
+                 rel->r_addend = wrel[-1].r_addend;
+
+                 /* Continue on as if we had a got reloc, to output
+                    dynamic reloc.  */
+                 r_type = R_PPC_GOT16_LO;
+               }
+             else
+               info->callbacks->einfo
+                 /* xgettext:c-format */
+                 (_("%P: %H: error: %s with unexpected instruction %x\n"),
+                  input_bfd, input_section, rel->r_offset,
+                  "R_PPC_ADDR16_HA", insn);
+           }
+         else if (r_type == R_PPC_ADDR16_LO)
+           {
+             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 */
+                     && (insn & 3) != 1)
+                 || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+                     && ((insn & 3) == 0 || (insn & 3) == 3)))
+               {
+                 /* Arrange to apply the reloc addend, if any.  */
+                 relocation = 0;
+                 unresolved_reloc = FALSE;
+                 rel->r_info = ELF32_R_INFO (0, r_type);
+               }
+             else
+               info->callbacks->einfo
+                 /* xgettext:c-format */
+                 (_("%P: %H: error: %s with unexpected instruction %x\n"),
+                  input_bfd, input_section, rel->r_offset,
+                  "R_PPC_ADDR16_LO", insn);
+           }
+       }
+
       ifunc = NULL;
       if (!htab->is_vxworks)
        {
@@ -7965,28 +8348,49 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
          ent = NULL;
          if (ifunc != NULL
-             && (!info->shared
+             && (!bfd_link_pic (info)
                  || is_branch_reloc (r_type)))
            {
              addend = 0;
-             if (r_type == R_PPC_PLTREL24 && info->shared)
+             if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
                addend = rel->r_addend;
              ent = find_plt_ent (ifunc, got2, addend);
            }
          if (ent != NULL)
            {
+             if (bfd_link_pic (info)
+                 && ent->sec != got2
+                 && htab->plt_type != PLT_NEW
+                 && (!htab->elf.dynamic_sections_created
+                     || h == NULL
+                     || h->dynindx == -1))
+               {
+                 /* Uh oh, we are going to create a pic glink stub
+                    for an ifunc (here for h == NULL and later in
+                    finish_dynamic_symbol for h != NULL), and
+                    apparently are using code compiled with
+                    -mbss-plt.  The difficulty is that -mbss-plt code
+                    gives no indication via a magic PLTREL24 addend
+                    whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or
+                    is pointing into a .got2 section (and how far
+                    into .got2).  */
+                   info->callbacks->einfo
+                     /* xgettext:c-format */
+                     (_("%X%P: %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->iplt->output_section->vma
-                                  + htab->iplt->output_offset
+                 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->reliplt->contents;
-                 loc += (htab->reliplt->reloc_count++
+                 loc = htab->elf.irelplt->contents;
+                 loc += (htab->elf.irelplt->reloc_count++
                          * sizeof (Elf32_External_Rela));
                  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
@@ -7996,7 +8400,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                {
                  unsigned char *p = ((unsigned char *) htab->glink->contents
                                      + ent->glink_offset);
-                 write_glink_stub (ent, htab->iplt, p, info);
+                 write_glink_stub (ent, htab->elf.iplt, p, info);
                  ent->glink_offset |= 1;
                }
 
@@ -8009,8 +8413,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              + htab->glink->output_offset
                              + (ent->glink_offset & ~1));
              else
-               relocation = (htab->plt->output_section->vma
-                             + htab->plt->output_offset
+               relocation = (htab->elf.splt->output_section->vma
+                             + htab->elf.splt->output_offset
                              + ent->plt.offset);
            }
        }
@@ -8024,12 +8428,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
        {
        default:
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: %B: unknown relocation type %d for symbol %s\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
 
        case R_PPC_NONE:
        case R_PPC_TLS:
@@ -8038,7 +8443,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_MRKREF:
        case R_PPC_GNU_VTINHERIT:
        case R_PPC_GNU_VTENTRY:
-         continue;
+         goto copy_reloc;
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
             address in the GOT as relocation value instead of the
@@ -8085,7 +8490,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
            bfd_vma *offp;
            unsigned long indx;
 
-           if (htab->got == NULL)
+           if (htab->elf.sgot == NULL)
              abort ();
 
            indx = 0;
@@ -8097,8 +8502,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              {
                bfd_boolean dyn;
                dyn = htab->elf.dynamic_sections_created;
-               if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-                   || (info->shared
+               if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+                   || (bfd_link_pic (info)
                        && SYMBOL_REFERENCES_LOCAL (info, h)))
                  /* This is actually a static link, or it is a
                     -Bsymbolic link and the symbol is defined
@@ -8166,19 +8571,19 @@ ppc_elf_relocate_section (bfd *output_bfd,
                      }
 
                    /* Generate relocs for the dynamic linker.  */
-                   if ((info->shared || indx != 0)
+                   if ((bfd_link_pic (info) || indx != 0)
                        && (offp == &htab->tlsld_got.offset
                            || h == NULL
                            || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                            || h->root.type != bfd_link_hash_undefweak))
                      {
-                       asection *rsec = htab->relgot;
+                       asection *rsec = htab->elf.srelgot;
                        bfd_byte * loc;
 
                        if (ifunc != NULL)
-                         rsec = htab->reliplt;
-                       outrel.r_offset = (htab->got->output_section->vma
-                                          + htab->got->output_offset
+                         rsec = htab->elf.irelplt;
+                       outrel.r_offset = (htab->elf.sgot->output_section->vma
+                                          + htab->elf.sgot->output_offset
                                           + off);
                        outrel.r_addend = 0;
                        if (tls_ty & (TLS_LD | TLS_GD))
@@ -8210,7 +8615,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          {
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
-                             outrel.r_addend -= htab->elf.tls_sec->vma;
+                             {
+                               if (htab->elf.tls_sec == NULL)
+                                 outrel.r_addend = 0;
+                               else
+                                 outrel.r_addend -= htab->elf.tls_sec->vma;
+                             }
                          }
                        loc = rsec->contents;
                        loc += (rsec->reloc_count++
@@ -8228,19 +8638,24 @@ ppc_elf_relocate_section (bfd *output_bfd,
                          value = 1;
                        else if (tls_ty != 0)
                          {
-                           value -= htab->elf.tls_sec->vma + DTP_OFFSET;
-                           if (tls_ty == (TLS_TLS | TLS_TPREL))
-                             value += DTP_OFFSET - TP_OFFSET;
+                           if (htab->elf.tls_sec == NULL)
+                             value = 0;
+                           else
+                             {
+                               value -= htab->elf.tls_sec->vma + DTP_OFFSET;
+                               if (tls_ty == (TLS_TLS | TLS_TPREL))
+                                 value += DTP_OFFSET - TP_OFFSET;
+                             }
 
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
-                               bfd_put_32 (output_bfd, value,
-                                           htab->got->contents + off + 4);
+                               bfd_put_32 (input_bfd, value,
+                                           htab->elf.sgot->contents + off + 4);
                                value = 1;
                              }
                          }
-                       bfd_put_32 (output_bfd, value,
-                                   htab->got->contents + off);
+                       bfd_put_32 (input_bfd, value,
+                                   htab->elf.sgot->contents + off);
                      }
 
                    off += 4;
@@ -8277,8 +8692,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  }
              }
 
-           relocation = (htab->got->output_section->vma
-                         + htab->got->output_offset
+           /* If here for a picfixup, we're done.  */
+           if (r_type != ELF32_R_TYPE (rel->r_info))
+             goto copy_reloc;
+
+           relocation = (htab->elf.sgot->output_section->vma
+                         + htab->elf.sgot->output_offset
                          + off
                          - SYM_VAL (htab->elf.hgot));
 
@@ -8288,6 +8707,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
               got at entry m+n bears little relation to the entry m.  */
            if (addend != 0)
              info->callbacks->einfo
+               /* xgettext:c-format */
                (_("%P: %H: non-zero addend on %s reloc against `%s'\n"),
                 input_bfd, input_section, rel->r_offset,
                 howto->name,
@@ -8301,14 +8721,28 @@ ppc_elf_relocate_section (bfd *output_bfd,
             at a symbol not in this object.  */
          if (unresolved_reloc)
            {
-             if (! (*info->callbacks->undefined_symbol) (info,
-                                                         h->root.root.string,
-                                                         input_bfd,
-                                                         input_section,
-                                                         rel->r_offset,
-                                                         TRUE))
-               return FALSE;
-             continue;
+             (*info->callbacks->undefined_symbol) (info,
+                                                   h->root.root.string,
+                                                   input_bfd,
+                                                   input_section,
+                                                   rel->r_offset,
+                                                   TRUE);
+             goto copy_reloc;
+           }
+         if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info))
+           {
+             /* @local on an ifunc does not really make sense since
+                the ifunc resolver can take you anywhere.  More
+                seriously, calls to ifuncs must go through a plt call
+                stub, and for pic the plt call stubs uses r30 to
+                access the PLT.  The problem is that a call that is
+                local won't have the +32k reloc addend trick marking
+                -fPIC code, so the linker won't know whether r30 is
+                _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section.  */
+             /* xgettext:c-format */
+             info->callbacks->einfo (_("%X%P: %H: @local call to ifunc %s\n"),
+                                     input_bfd, input_section, rel->r_offset,
+                                     h->root.root.string);
            }
          break;
 
@@ -8316,7 +8750,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_DTPREL16_LO:
        case R_PPC_DTPREL16_HI:
        case R_PPC_DTPREL16_HA:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          break;
 
          /* Relocations that may need to be propagated if this is a shared
@@ -8334,24 +8769,27 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 code using weak externs ought to check that they are
                 defined before using them.  */
              bfd_byte *p = contents + rel->r_offset - d_offset;
-             unsigned int insn = bfd_get_32 (output_bfd, p);
+             unsigned int insn = bfd_get_32 (input_bfd, p);
              insn = _bfd_elf_ppc_at_tprel_transform (insn, 2);
              if (insn != 0)
-               bfd_put_32 (output_bfd, insn, p);
+               bfd_put_32 (input_bfd, insn, p);
              break;
            }
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          /* The TPREL16 relocs shouldn't really be used in shared
             libs as they will result in DT_TEXTREL being set, but
             support them anyway.  */
          goto dodyn;
 
        case R_PPC_TPREL32:
-         addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPREL32:
-         addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+         if (htab->elf.tls_sec != NULL)
+           addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
          goto dodyn;
 
        case R_PPC_DTPMOD32:
@@ -8363,6 +8801,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          break;
 
        case R_PPC_REL32:
@@ -8397,7 +8836,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_ADDR14:
        case R_PPC_ADDR14_BRTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
-         if (h != NULL && !info->shared)
+         if (h != NULL && !bfd_link_pic (info))
            break;
          /* fall through */
 
@@ -8406,7 +8845,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              || is_vxworks_tls)
            break;
 
-         if ((info->shared
+         if ((bfd_link_pic (info)
               && !(h != NULL
                    && ((h->root.type == bfd_link_hash_undefined
                         && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
@@ -8416,11 +8855,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
-                 && !info->shared
+                 && !bfd_link_pic (info)
                  && h != NULL
                  && h->dynindx != -1
                  && !h->non_got_ref
-                 && !h->def_regular))
+                 && !h->def_regular
+                 && !(h->protected_def
+                      && ppc_elf_hash_entry (h)->has_addr16_ha
+                      && ppc_elf_hash_entry (h)->has_addr16_lo
+                      && htab->params->pic_fixup > 0)))
            {
              int skip;
              bfd_byte *loc;
@@ -8437,7 +8880,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 time.  */
              sreloc = elf_section_data (input_section)->sreloc;
              if (ifunc)
-               sreloc = htab->reliplt;
+               sreloc = htab->elf.irelplt;
              if (sreloc == NULL)
                return FALSE;
 
@@ -8486,6 +8929,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                             So we'll segfault when trying to run the
                             indirection function to resolve the reloc.  */
                          info->callbacks->einfo
+                           /* xgettext:c-format */
                            (_("%P: %H: relocation %s for indirect "
                               "function %s unsupported\n"),
                             input_bfd, input_section, rel->r_offset,
@@ -8539,7 +8983,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 
              if (skip == -1)
-               continue;
+               goto copy_reloc;
 
              /* This reloc will be computed at runtime.  We clear the memory
                 so that it contains predictable value.  */
@@ -8563,7 +9007,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
              if (r_type == R_PPC_RELAX_PLTREL24)
                {
-                 if (info->shared)
+                 if (bfd_link_pic (info))
                    got2_addend = addend;
                  addend = 0;
                }
@@ -8573,11 +9017,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
                              + htab->glink->output_offset
                              + ent->glink_offset);
              else
-               relocation = (htab->plt->output_section->vma
-                             + htab->plt->output_offset
+               relocation = (htab->elf.splt->output_section->vma
+                             + htab->elf.splt->output_offset
                              + ent->plt.offset);
            }
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_RELAX:
          {
@@ -8586,15 +9030,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
            size_t insn_offset = rel->r_offset;
            unsigned int insn;
 
-           if (info->shared)
+           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 (output_bfd, stub[0], contents + insn_offset - 12);
-               bfd_put_32 (output_bfd, stub[1], contents + insn_offset - 8);
-               bfd_put_32 (output_bfd, stub[2], contents + insn_offset - 4);
+               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;
              }
@@ -8605,18 +9049,18 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            relocation += addend;
-           if (info->relocatable)
+           if (bfd_link_relocatable (info))
              relocation = 0;
 
            /* First insn is HA, second is LO.  */
            insn = *stub++;
            insn |= ((relocation + 0x8000) >> 16) & 0xffff;
-           bfd_put_32 (output_bfd, insn, contents + insn_offset);
+           bfd_put_32 (input_bfd, insn, contents + insn_offset);
            insn_offset += 4;
 
            insn = *stub++;
            insn |= relocation & 0xffff;
-           bfd_put_32 (output_bfd, insn, contents + insn_offset);
+           bfd_put_32 (input_bfd, insn, contents + insn_offset);
            insn_offset += 4;
            size -= 2;
 
@@ -8624,7 +9068,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
              {
                insn = *stub++;
                --size;
-               bfd_put_32 (output_bfd, insn, contents + insn_offset);
+               bfd_put_32 (input_bfd, insn, contents + insn_offset);
                insn_offset += 4;
              }
 
@@ -8632,12 +9076,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
               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 */
-           rel[0].r_offset += d_offset;
-           memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
-           rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
-           rel[1].r_offset += 4;
-           rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
-           rel++;
+           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);
          }
          continue;
 
@@ -8690,10 +9135,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_PLTREL24:
          if (h != NULL && ifunc == NULL)
            {
-             struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   info->shared ? addend : 0);
+             struct plt_entry *ent;
+
+             ent = find_plt_ent (&h->plt.plist, got2,
+                                 bfd_link_pic (info) ? addend : 0);
              if (ent == NULL
-                 || htab->plt == NULL)
+                 || htab->elf.splt == NULL)
                {
                  /* We didn't make a PLT entry for this symbol.  This
                     happens when statically linking PIC code, or when
@@ -8709,8 +9156,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                  + htab->glink->output_offset
                                  + ent->glink_offset);
                  else
-                   relocation = (htab->plt->output_section->vma
-                                 + htab->plt->output_offset
+                   relocation = (htab->elf.splt->output_section->vma
+                                 + htab->elf.splt->output_offset
                                  + ent->plt.offset);
                }
            }
@@ -8741,6 +9188,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  || strcmp (name, ".sbss") == 0))
              {
                info->callbacks->einfo
+                 /* xgettext:c-format */
                  (_("%P: %B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)\n"),
                   input_bfd,
@@ -8771,6 +9219,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  || strcmp (name, ".sbss2") == 0))
              {
                info->callbacks->einfo
+                 /* xgettext:c-format */
                  (_("%P: %B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)\n"),
                   input_bfd,
@@ -8783,39 +9232,45 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_VLE_LO16A:
          relocation = relocation + addend;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16a_type);
-         continue;
+         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;
 
        case R_PPC_VLE_LO16D:
          relocation = relocation + addend;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16d_type);
-         continue;
+         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;
 
        case R_PPC_VLE_HI16A:
          relocation = (relocation + addend) >> 16;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16a_type);
-         continue;
+         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;
 
        case R_PPC_VLE_HI16D:
          relocation = (relocation + addend) >> 16;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16d_type);
-         continue;
+         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;
 
        case R_PPC_VLE_HA16A:
          relocation = (relocation + addend + 0x8000) >> 16;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16a_type);
-         continue;
+         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;
 
        case R_PPC_VLE_HA16D:
          relocation = (relocation + addend + 0x8000) >> 16;
-         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                              relocation, split16d_type);
-         continue;
+         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;
 
          /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
        case R_PPC_EMB_SDA21:
@@ -8855,6 +9310,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
            else
              {
                info->callbacks->einfo
+                 /* xgettext:c-format */
                  (_("%P: %B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)\n"),
                   input_bfd,
@@ -8864,7 +9320,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
                bfd_set_error (bfd_error_bad_value);
                ret = FALSE;
-               continue;
+               goto copy_reloc;
              }
 
            if (sda != NULL)
@@ -8877,7 +9333,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                addend -= SYM_VAL (sda);
              }
 
-           insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+           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))
@@ -8897,12 +9353,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
                /* And the final 11 bits of the value to bits 21 to 31.  */
                insn |= relocation & 0x7ff;
 
-               bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+               bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
 
                if (r_type == R_PPC_VLE_SDA21
                    && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
                  goto overflow;
-               continue;
+               goto copy_reloc;
              }
            else if (r_type == R_PPC_EMB_SDA21
                     || r_type == R_PPC_VLE_SDA21
@@ -8911,7 +9367,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                /* Fill in register field.  */
                insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
              }
-           bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+           bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
          }
          break;
 
@@ -8948,7 +9404,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
            else
              {
-               (*_bfd_error_handler)
+               _bfd_error_handler
+                 /* xgettext:c-format */
                  (_("%B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)"),
                   input_bfd,
@@ -8958,7 +9415,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
                bfd_set_error (bfd_error_bad_value);
                ret = FALSE;
-               continue;
+               goto copy_reloc;
              }
 
            if (sda != NULL)
@@ -8975,37 +9432,49 @@ ppc_elf_relocate_section (bfd *output_bfd,
                     + addend);
 
            if (r_type == R_PPC_VLE_SDAREL_LO16A)
-             ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
-                                  value, split16a_type);
+             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 (output_bfd, contents + rel->r_offset,
-                                  value, split16d_type);
+             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 (output_bfd, contents + rel->r_offset,
-                                    value, split16a_type);
+               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 (output_bfd, contents + rel->r_offset,
-                                    value, split16d_type);
+               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 (output_bfd, contents + rel->r_offset,
-                                    value, split16a_type);
+               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 (output_bfd, contents + rel->r_offset,
-                                    value, split16d_type);
+               ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+                                    contents + rel->r_offset, value,
+                                    split16d_type,
+                                    htab->params->vle_reloc_fixup);
              }
          }
-         continue;
+         goto copy_reloc;
 
          /* Relocate against the beginning of the section.  */
        case R_PPC_SECTOFF:
@@ -9046,6 +9515,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_RELST_HA:
        case R_PPC_EMB_BIT_FLD:
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: %B: relocation %s is not yet supported for symbol %s\n"),
             input_bfd,
             howto->name,
@@ -9053,7 +9523,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
          bfd_set_error (bfd_error_invalid_operation);
          ret = FALSE;
-         continue;
+         goto copy_reloc;
        }
 
       /* Do any further special processing.  */
@@ -9064,6 +9534,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_ADDR16_HA:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
        case R_PPC_SECTOFF_HA:
        case R_PPC_TPREL16_HA:
        case R_PPC_DTPREL16_HA:
@@ -9075,7 +9546,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
             alone (it will be set to zero elsewhere in the link).  */
          if (sec == NULL)
            break;
-         /* Fall thru */
+         /* Fall through.  */
 
        case R_PPC_PLT16_HA:
        case R_PPC_GOT16_HA:
@@ -9113,7 +9584,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
               that make up part of the insn opcode.  */
            unsigned int insn, mask, lobit;
 
-           insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+           insn = bfd_get_32 (input_bfd,
+                              contents + rel->r_offset - d_offset);
            mask = 0;
            if (is_insn_ds_form (insn))
              mask = 3;
@@ -9121,18 +9593,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
              mask = 15;
            else
              break;
-           lobit = mask & (relocation + addend);
+           relocation += addend;
+           addend = insn & mask;
+           lobit = mask & relocation;
            if (lobit != 0)
              {
-               addend -= lobit;
+               relocation ^= lobit;
                info->callbacks->einfo
+                 /* xgettext:c-format */
                  (_("%P: %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;
              }
-           addend += insn & mask;
          }
          break;
        }
@@ -9155,6 +9629,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                      rel->r_offset) != (bfd_vma) -1)
        {
          info->callbacks->einfo
+           /* xgettext:c-format */
            (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
             input_bfd, input_section, rel->r_offset,
             howto->name,
@@ -9191,48 +9666,82 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
        }
 
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                   rel->r_offset, relocation, addend);
+      if (r_type == R_PPC_REL16DX_HA)
+       {
+         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         if (rel->r_offset + 4 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             unsigned int insn;
+
+             relocation += addend;
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             relocation >>= 16;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~0x1fffc1;
+             insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+             r = bfd_reloc_ok;
+           }
+       }
+      else
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
          if (r == bfd_reloc_overflow)
            {
            overflow:
-             if (warned)
-               continue;
-             if (h != NULL
-                 && h->root.type == bfd_link_hash_undefweak
-                 && howto->pc_relative)
-               {
-                 /* Assume this is a call protected by other code that
-                    detect the symbol is undefined.  If this is the case,
-                    we can safely ignore the overflow.  If not, the
-                    program is hosed anyway, and a little warning isn't
-                    going to help.  */
-
-                 continue;
-               }
-
-             if (! (*info->callbacks->reloc_overflow) (info,
-                                                       (h ? &h->root : NULL),
-                                                       sym_name,
-                                                       howto->name,
-                                                       rel->r_addend,
-                                                       input_bfd,
-                                                       input_section,
-                                                       rel->r_offset))
-               return FALSE;
+             /* On code like "if (foo) foo();" don't report overflow
+                on a branch to zero when foo is undefined.  */
+             if (!warned
+                 && !(h != NULL
+                      && (h->root.type == bfd_link_hash_undefweak
+                          || h->root.type == bfd_link_hash_undefined)
+                      && is_branch_reloc (r_type)))
+               info->callbacks->reloc_overflow
+                 (info, (h ? &h->root : NULL), sym_name, howto->name,
+                  rel->r_addend, input_bfd, input_section, rel->r_offset);
            }
          else
            {
              info->callbacks->einfo
+               /* xgettext:c-format */
                (_("%P: %H: %s reloc against `%s': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
                 howto->name, sym_name, (int) r);
              ret = FALSE;
            }
        }
+    copy_reloc:
+      if (wrel != rel)
+       *wrel = *rel;
+    }
+
+  if (wrel != rel)
+    {
+      Elf_Internal_Shdr *rel_hdr;
+      size_t deleted = rel - wrel;
+
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      if (rel_hdr->sh_size == 0)
+       {
+         /* It is too late to remove an empty reloc section.  Leave
+            one NONE reloc.
+            ??? What is wrong with an empty section???  */
+         rel_hdr->sh_size = rel_hdr->sh_entsize;
+         deleted -= 1;
+         wrel++;
+       }
+      relend = wrel;
+      rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+      rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+      input_section->reloc_count -= deleted;
     }
 
 #ifdef DEBUG
@@ -9251,15 +9760,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
   if (htab->params->ppc476_workaround
       && input_section->sec_info_type == SEC_INFO_TYPE_TARGET
-      && (!info->relocatable
+      && (!bfd_link_relocatable (info)
          || (input_section->output_section->alignment_power
              >= htab->params->pagesize_p2)))
     {
-      struct ppc_elf_relax_info *relax_info;
       bfd_vma start_addr, end_addr, addr;
       bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
 
-      relax_info = elf_section_data (input_section)->sec_info;
       if (relax_info->workaround_size != 0)
        {
          bfd_byte *p;
@@ -9363,13 +9870,13 @@ ppc_elf_relocate_section (bfd *output_bfd,
             prevent the bad prefetch from happening in the first
             place:
             .
-            .  lis 9,new_page@ha        lis 9,new_page@ha      
-            .  addi 9,9,new_page@l      addi 9,9,new_page@l    
-            .  mtctr 9                  mtctr 9                        
-            .  bctr                     bctr                   
+            .  lis 9,new_page@ha        lis 9,new_page@ha
+            .  addi 9,9,new_page@l      addi 9,9,new_page@l
+            .  mtctr 9                  mtctr 9
+            .  bctr                     bctr
             .  nop                      b somewhere_else
-            .  b somewhere_else         nop                    
-            . new_page:                new_page:               
+            .  b somewhere_else         nop
+            . new_page:                new_page:
             .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
          if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
@@ -9390,6 +9897,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
              && rel->r_offset >= offset
              && rel->r_offset < offset + 4)
            {
+             asection *sreloc;
+
              /* If the insn we are patching had a reloc, adjust the
                 reloc r_offset so that the reloc applies to the moved
                 location.  This matters for -r and --emit-relocs.  */
@@ -9402,6 +9911,57 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  relend[-1] = tmp;
                }
              relend[-1].r_offset += patch_off - offset;
+
+             /* Adjust REL16 addends too.  */
+             switch (ELF32_R_TYPE (relend[-1].r_info))
+               {
+               case R_PPC_REL16:
+               case R_PPC_REL16_LO:
+               case R_PPC_REL16_HI:
+               case R_PPC_REL16_HA:
+                 relend[-1].r_addend += patch_off - offset;
+                 break;
+               default:
+                 break;
+               }
+
+             /* If we are building a PIE or shared library with
+                non-PIC objects, perhaps we had a dynamic reloc too?
+                If so, the dynamic reloc must move with the insn.  */
+             sreloc = elf_section_data (input_section)->sreloc;
+             if (sreloc != NULL)
+               {
+                 Elf32_External_Rela *slo, *shi, *srelend;
+                 bfd_vma soffset;
+
+                 slo = (Elf32_External_Rela *) sreloc->contents;
+                 shi = srelend = slo + sreloc->reloc_count;
+                 soffset = (offset + input_section->output_section->vma
+                            + input_section->output_offset);
+                 while (slo < shi)
+                   {
+                     Elf32_External_Rela *srel = slo + (shi - slo) / 2;
+                     bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel,
+                                               &outrel);
+                     if (outrel.r_offset < soffset)
+                       slo = srel + 1;
+                     else if (outrel.r_offset > soffset + 3)
+                       shi = srel;
+                     else
+                       {
+                         if (srel + 1 != srelend)
+                           {
+                             memmove (srel, srel + 1,
+                                      (srelend - (srel + 1)) * sizeof (*srel));
+                             srel = srelend - 1;
+                           }
+                         outrel.r_offset += patch_off - offset;
+                         bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+                                                    (bfd_byte *) srel);
+                         break;
+                       }
+                   }
+               }
            }
          else
            rel = NULL;
@@ -9412,9 +9972,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
              bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
 
              delta += offset - patch_off;
-             if (info->relocatable && rel != NULL)
+             if (bfd_link_relocatable (info) && rel != NULL)
                delta = 0;
-             if (!info->relocatable && rel != NULL)
+             if (!bfd_link_relocatable (info) && rel != NULL)
                {
                  enum elf_ppc_reloc_type r_type;
 
@@ -9540,18 +10100,18 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                got_offset = (reloc_index + 3) * 4;
 
                /* Use the right PLT. */
-               plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
+               plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry
                            : ppc_elf_vxworks_plt_entry;
 
                /* Fill in the .plt on VxWorks.  */
-               if (info->shared)
+               if (bfd_link_pic (info))
                  {
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | PPC_HA (got_offset),
-                               htab->plt->contents + ent->plt.offset + 0);
+                               htab->elf.splt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
                                plt_entry[1] | PPC_LO (got_offset),
-                               htab->plt->contents + ent->plt.offset + 4);
+                               htab->elf.splt->contents + ent->plt.offset + 4);
                  }
                else
                  {
@@ -9559,16 +10119,16 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | PPC_HA (got_loc),
-                               htab->plt->contents + ent->plt.offset + 0);
+                               htab->elf.splt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
                                plt_entry[1] | PPC_LO (got_loc),
-                               htab->plt->contents + ent->plt.offset + 4);
+                               htab->elf.splt->contents + ent->plt.offset + 4);
                  }
 
                bfd_put_32 (output_bfd, plt_entry[2],
-                           htab->plt->contents + ent->plt.offset + 8);
+                           htab->elf.splt->contents + ent->plt.offset + 8);
                bfd_put_32 (output_bfd, plt_entry[3],
-                           htab->plt->contents + ent->plt.offset + 12);
+                           htab->elf.splt->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
@@ -9578,7 +10138,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   prescaled offset.  */
                bfd_put_32 (output_bfd,
                            plt_entry[4] | reloc_index,
-                           htab->plt->contents + ent->plt.offset + 16);
+                           htab->elf.splt->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.
@@ -9588,21 +10148,21 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                bfd_put_32 (output_bfd,
                            (plt_entry[5]
                             | (-(ent->plt.offset + 20) & 0x03fffffc)),
-                           htab->plt->contents + ent->plt.offset + 20);
+                           htab->elf.splt->contents + ent->plt.offset + 20);
                bfd_put_32 (output_bfd, plt_entry[6],
-                           htab->plt->contents + ent->plt.offset + 24);
+                           htab->elf.splt->contents + ent->plt.offset + 24);
                bfd_put_32 (output_bfd, plt_entry[7],
-                           htab->plt->contents + ent->plt.offset + 28);
+                           htab->elf.splt->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->plt->output_section->vma
-                                        + htab->plt->output_offset
+               bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
+                                        + htab->elf.splt->output_offset
                                         + ent->plt.offset + 16),
-                           htab->sgotplt->contents + got_offset);
+                           htab->elf.sgotplt->contents + got_offset);
 
-               if (!info->shared)
+               if (!bfd_link_pic (info))
                  {
                    /* Fill in a couple of entries in .rela.plt.unloaded.  */
                    loc = htab->srelplt2->contents
@@ -9611,8 +10171,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                         * sizeof (Elf32_External_Rela));
 
                    /* Provide the @ha relocation for the first instruction.  */
-                   rela.r_offset = (htab->plt->output_section->vma
-                                    + htab->plt->output_offset
+                   rela.r_offset = (htab->elf.splt->output_section->vma
+                                    + htab->elf.splt->output_offset
                                     + ent->plt.offset + 2);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_HA);
@@ -9621,8 +10181,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                    loc += sizeof (Elf32_External_Rela);
 
                    /* Provide the @l relocation for the second instruction.  */
-                   rela.r_offset = (htab->plt->output_section->vma
-                                    + htab->plt->output_offset
+                   rela.r_offset = (htab->elf.splt->output_section->vma
+                                    + htab->elf.splt->output_offset
                                     + ent->plt.offset + 6);
                    rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
                                                R_PPC_ADDR16_LO);
@@ -9632,8 +10192,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
                    /* Provide a relocation for the GOT entry corresponding to this
                       PLT slot.  Point it at the middle of the .plt entry.  */
-                   rela.r_offset = (htab->sgotplt->output_section->vma
-                                    + htab->sgotplt->output_offset
+                   rela.r_offset = (htab->elf.sgotplt->output_section->vma
+                                    + htab->elf.sgotplt->output_offset
                                     + got_offset);
                    rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
                                                R_PPC_ADDR32);
@@ -9646,17 +10206,17 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                   address of the PLT entry for this function, as specified
                   by the ABI.  Instead, the offset is set to the address of
                   the GOT slot for this function.  See EABI 4.4.4.1.  */
-               rela.r_offset = (htab->sgotplt->output_section->vma
-                                + htab->sgotplt->output_offset
+               rela.r_offset = (htab->elf.sgotplt->output_section->vma
+                                + htab->elf.sgotplt->output_offset
                                 + got_offset);
 
              }
            else
              {
-               asection *splt = htab->plt;
+               asection *splt = htab->elf.splt;
                if (!htab->elf.dynamic_sections_created
                    || h->dynindx == -1)
-                 splt = htab->iplt;
+                 splt = htab->elf.iplt;
 
                rela.r_offset = (splt->output_section->vma
                                 + splt->output_offset
@@ -9695,11 +10255,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
-             loc = (htab->reliplt->contents
-                    + (htab->reliplt->reloc_count++
+             loc = (htab->elf.irelplt->contents
+                    + (htab->elf.irelplt->reloc_count++
                        * sizeof (Elf32_External_Rela)));
            else
-             loc = (htab->relplt->contents
+             loc = (htab->elf.srelplt->contents
                     + reloc_index * sizeof (Elf32_External_Rela));
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
@@ -9724,7 +10284,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                  }
              }
            else if (h->type == STT_GNU_IFUNC
-                    && !info->shared)
+                    && !bfd_link_pic (info))
              {
                /* Set the value of ifunc symbols in a non-pie
                   executable to the glink entry.  This is to avoid
@@ -9747,10 +10307,10 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            || h->dynindx == -1)
          {
            unsigned char *p;
-           asection *splt = htab->plt;
+           asection *splt = htab->elf.splt;
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
-             splt = htab->iplt;
+             splt = htab->elf.iplt;
 
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
 
@@ -9776,7 +10336,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 
            write_glink_stub (ent, splt, p, info);
 
-           if (!info->shared)
+           if (!bfd_link_pic (info))
              /* We only need one non-PIC glink stub.  */
              break;
          }
@@ -9825,7 +10385,7 @@ ppc_elf_reloc_type_class (const struct bfd_link_info *info,
 {
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
-  if (rel_sec == htab->reliplt)
+  if (rel_sec == htab->elf.irelplt)
     return reloc_class_ifunc;
 
   switch (ELF32_R_TYPE (rela->r_info))
@@ -9859,10 +10419,10 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #endif
 
   htab = ppc_elf_hash_table (info);
-  dynobj = elf_hash_table (info)->dynobj;
+  dynobj = htab->elf.dynobj;
   sdyn = bfd_get_linker_section (dynobj, ".dynamic");
   if (htab->is_vxworks)
-    splt = bfd_get_linker_section (dynobj, ".plt");
+    splt = htab->elf.splt;
   else
     splt = NULL;
 
@@ -9874,7 +10434,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
     {
       Elf32_External_Dyn *dyncon, *dynconend;
 
-      BFD_ASSERT (htab->plt != NULL && sdyn != NULL);
+      BFD_ASSERT (htab->elf.splt != NULL && sdyn != NULL);
 
       dyncon = (Elf32_External_Dyn *) sdyn->contents;
       dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
@@ -9889,18 +10449,18 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
            {
            case DT_PLTGOT:
              if (htab->is_vxworks)
-               s = htab->sgotplt;
+               s = htab->elf.sgotplt;
              else
-               s = htab->plt;
+               s = htab->elf.splt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_PLTRELSZ:
-             dyn.d_un.d_val = htab->relplt->size;
+             dyn.d_un.d_val = htab->elf.srelplt->size;
              break;
 
            case DT_JMPREL:
-             s = htab->relplt;
+             s = htab->elf.srelplt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
@@ -9911,8 +10471,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
            case DT_RELASZ:
              if (htab->is_vxworks)
                {
-                 if (htab->relplt)
-                   dyn.d_un.d_ptr -= htab->relplt->size;
+                 if (htab->elf.srelplt)
+                   dyn.d_un.d_ptr -= htab->elf.srelplt->size;
                  break;
                }
              continue;
@@ -9928,10 +10488,10 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
     }
 
-  if (htab->got != NULL)
+  if (htab->elf.sgot != NULL)
     {
-      if (htab->elf.hgot->root.u.def.section == htab->got
-         || htab->elf.hgot->root.u.def.section == htab->sgotplt)
+      if (htab->elf.hgot->root.u.def.section == htab->elf.sgot
+         || htab->elf.hgot->root.u.def.section == htab->elf.sgotplt)
        {
          unsigned char *p = htab->elf.hgot->root.u.def.section->contents;
 
@@ -9956,26 +10516,28 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
       else
        {
+         /* xgettext:c-format */
          info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"),
                                  htab->elf.hgot->root.root.string,
-                                 (htab->sgotplt != NULL
-                                  ? htab->sgotplt->name : htab->got->name));
+                                 (htab->elf.sgotplt != NULL
+                                  ? htab->elf.sgotplt->name
+                                  : htab->elf.sgot->name));
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
        }
 
-      elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
+      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 (splt && splt->size > 0)
     {
       /* Use the right PLT. */
-      const bfd_vma *plt_entry = (info->shared
+      const bfd_vma *plt_entry = (bfd_link_pic (info)
                                  ? ppc_elf_vxworks_pic_plt0_entry
                                  : ppc_elf_vxworks_plt0_entry);
 
-      if (!info->shared)
+      if (!bfd_link_pic (info))
        {
          bfd_vma got_value = SYM_VAL (htab->elf.hgot);
 
@@ -9996,7 +10558,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
       bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
 
-      if (! info->shared)
+      if (! bfd_link_pic (info))
        {
          Elf_Internal_Rela rela;
          bfd_byte *loc;
@@ -10004,8 +10566,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
          loc = htab->srelplt2->contents;
 
          /* Output the @ha relocation for the first instruction.  */
-         rela.r_offset = (htab->plt->output_section->vma
-                          + htab->plt->output_offset
+         rela.r_offset = (htab->elf.splt->output_section->vma
+                          + htab->elf.splt->output_offset
                           + 2);
          rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
          rela.r_addend = 0;
@@ -10013,8 +10575,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
          loc += sizeof (Elf32_External_Rela);
 
          /* Output the @l relocation for the second instruction.  */
-         rela.r_offset = (htab->plt->output_section->vma
-                          + htab->plt->output_offset
+         rela.r_offset = (htab->elf.splt->output_section->vma
+                          + htab->elf.splt->output_offset
                           + 6);
          rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
          rela.r_addend = 0;
@@ -10213,7 +10775,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        }
 
       /* Last comes the PLTresolve stub.  */
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          bfd_vma bcl;
 
@@ -10327,11 +10889,12 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #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
@@ -10386,7 +10949,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_action_discarded           ppc_elf_action_discarded
 #define elf_backend_init_index_section         _bfd_elf_init_1_index_section
 #define elf_backend_lookup_section_flags_hook  ppc_elf_lookup_section_flags
-#define elf_backend_section_processing         ppc_elf_section_processing
 
 #include "elf32-target.h"