Add --no-dynamic-linker option to ld, for static PIE use
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 5bfa33b7b5f4d9f37c031fa2e3062b0e319a9bcd..708076d65e8d74515d992c033d92d7cf6764610a 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright (C) 1994-2014 Free Software Foundation, Inc.
+   Copyright (C) 1994-2015 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -50,8 +50,6 @@ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type ppc_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
-static void ppc_elf_vle_split16
-  (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type);
 
 /* Branch prediction bit for branch taken relocs.  */
 #define BRANCH_PREDICT_BIT 0x200000
@@ -149,6 +147,7 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
 #define ADD_3_12_2     0x7c6c1214
 #define ADD_11_0_11    0x7d605a14
 #define B              0x48000000
+#define BA             0x48000002
 #define BCL_20_31      0x429f0005
 #define BCTR           0x4e800420
 #define BEQLR          0x4d820020
@@ -188,11 +187,11 @@ 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_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_NONE",          /* name */
         FALSE,                 /* partial_inplace */
@@ -207,7 +206,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_ADDR32",        /* name */
         FALSE,                 /* partial_inplace */
@@ -223,7 +222,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         26,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_ADDR24",        /* name */
         FALSE,                 /* partial_inplace */
@@ -300,7 +299,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_ADDR14",        /* name */
         FALSE,                 /* partial_inplace */
@@ -317,7 +316,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_ADDR14_BRTAKEN",/* name */
         FALSE,                 /* partial_inplace */
@@ -334,7 +333,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_ADDR14_BRNTAKEN",/* name */
         FALSE,                 /* partial_inplace */
@@ -446,7 +445,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_GOT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
@@ -462,7 +461,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_GOT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
@@ -497,7 +496,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_COPY",          /* name */
         FALSE,                 /* partial_inplace */
@@ -513,7 +512,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_GLOB_DAT",      /* name */
         FALSE,                 /* partial_inplace */
@@ -528,7 +527,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_JMP_SLOT",      /* name */
         FALSE,                 /* partial_inplace */
@@ -545,7 +544,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_RELATIVE",      /* name */
         FALSE,                 /* partial_inplace */
@@ -577,7 +576,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_UADDR32",       /* name */
         FALSE,                 /* partial_inplace */
@@ -607,7 +606,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_REL32",         /* name */
         FALSE,                 /* partial_inplace */
@@ -623,7 +622,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_PLT32",         /* name */
         FALSE,                 /* partial_inplace */
@@ -639,7 +638,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_PLTREL32",      /* name */
         FALSE,                 /* partial_inplace */
@@ -671,7 +670,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_PLT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
@@ -687,7 +686,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_PLT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
@@ -718,7 +717,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_SECTOFF",       /* name */
         FALSE,                 /* partial_inplace */
@@ -748,7 +747,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_SECTOFF_HI",    /* name */
         FALSE,                 /* partial_inplace */
@@ -763,7 +762,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         ppc_elf_addr16_ha_reloc, /* special_function */
         "R_PPC_SECTOFF_HA",    /* name */
         FALSE,                 /* partial_inplace */
@@ -1239,7 +1238,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_NADDR32",   /* name */
         FALSE,                 /* partial_inplace */
@@ -1254,7 +1253,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_NADDR16",   /* name */
         FALSE,                 /* partial_inplace */
@@ -1449,10 +1448,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   HOWTO (R_PPC_VLE_LO16A,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_LO16A",     /* name */
         FALSE,                 /* partial_inplace */
@@ -1464,10 +1463,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   HOWTO (R_PPC_VLE_LO16D,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_LO16D",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1477,12 +1476,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 split16a format.  */
   HOWTO (R_PPC_VLE_HI16A,      /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_HI16A",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1492,12 +1491,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 split16d format.  */
   HOWTO (R_PPC_VLE_HI16D,      /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_HI16D",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1507,12 +1506,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (High Adjusted) in split16a format.  */
   HOWTO (R_PPC_VLE_HA16A,      /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_HA16A",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1522,12 +1521,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (High Adjusted) in split16d format.  */
   HOWTO (R_PPC_VLE_HA16D,      /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_HA16D",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1535,14 +1534,16 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* This reloc does nothing.  */
-  HOWTO (R_PPC_VLE_SDA21,              /* type */
+  /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
+     instructions.  If the register base is 0 then the linker changes
+     the e_add16i to an e_li instruction.  */
+  HOWTO (R_PPC_VLE_SDA21,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_VLE_SDA21",             /* name */
         FALSE,                 /* partial_inplace */
@@ -1550,29 +1551,29 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* This reloc does nothing.  */
+  /* Like R_PPC_VLE_SDA21 but ignore overflow.  */
   HOWTO (R_PPC_VLE_SDA21_LO,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_VLE_SDA21_LO",  /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
+        0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_LO16A",      /* name */
         FALSE,                 /* partial_inplace */
@@ -1581,14 +1582,13 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE),                /* pcrel_offset */
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16d format.  */
-  /* This reloc does nothing.  */
   HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_LO16D",              /* name */
         FALSE,                 /* partial_inplace */
@@ -1598,12 +1598,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_HI16A,       /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_HI16A",      /* name */
         FALSE,                 /* partial_inplace */
@@ -1613,12 +1613,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
   HOWTO (R_PPC_VLE_SDAREL_HI16D,       /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_HI16D",      /* name */
         FALSE,                 /* partial_inplace */
@@ -1628,12 +1628,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_HA16A,       /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_HA16A",      /* name */
         FALSE,                 /* partial_inplace */
@@ -1643,12 +1643,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
   HOWTO (R_PPC_VLE_SDAREL_HA16D,       /* type */
-        0,                     /* rightshift */
+        16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
+        16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_VLE_SDAREL_HA16D",      /* name */
         FALSE,                 /* partial_inplace */
@@ -1662,7 +1662,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc,  /* special_function */
         "R_PPC_IRELATIVE",     /* name */
         FALSE,                 /* partial_inplace */
@@ -1677,7 +1677,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_REL16",         /* name */
         FALSE,                 /* partial_inplace */
@@ -2019,19 +2019,28 @@ 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)
+    {
+      (*_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));
+                             abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
 
       cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
@@ -2057,9 +2066,6 @@ 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
@@ -2629,7 +2635,7 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
   apuinfo_list_init ();
 
   /* Read in the input sections contents.  */
-  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
+  for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next)
     {
       unsigned long datum;
 
@@ -2919,7 +2925,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 +2955,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 +2969,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 +2988,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 +3080,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 +3135,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))
@@ -3250,7 +3263,7 @@ 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, 4096 };
+  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12, 0 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -3338,6 +3351,36 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Create a special linker section, used for R_PPC_EMB_SDAI16 and
+   R_PPC_EMB_SDA2I16 pointers.  These sections become part of .sdata
+   and .sdata2.  Create _SDA_BASE_ and _SDA2_BASE too.  */
+
+static bfd_boolean
+ppc_elf_create_linker_section (bfd *abfd,
+                              struct bfd_link_info *info,
+                              flagword flags,
+                              elf_linker_section_t *lsect)
+{
+  asection *s;
+
+  flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+           | SEC_LINKER_CREATED);
+
+  s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags);
+  if (s == NULL)
+    return FALSE;
+  lsect->section = s;
+
+  /* Define the sym on the first section of this name.  */
+  s = bfd_get_section_by_name (abfd, lsect->name);
+
+  lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name);
+  if (lsect->sym == NULL)
+    return FALSE;
+  lsect->sym->root.u.def.value = 0x8000;
+  return TRUE;
+}
+
 static bfd_boolean
 ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
 {
@@ -3379,6 +3422,15 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL
       || ! bfd_set_section_alignment (abfd, s, 2))
     return FALSE;
+
+  if (!ppc_elf_create_linker_section (abfd, info, 0,
+                                     &htab->sdata[0]))
+    return FALSE;
+
+  if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
+                                     &htab->sdata[1]))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -3413,7 +3465,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
@@ -3570,7 +3622,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))
     {
@@ -3597,59 +3649,15 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
-  if ((abfd->flags & DYNAMIC) == 0
-      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
-    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+      && (abfd->flags & DYNAMIC) == 0
+      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+    elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
 
   return TRUE;
 }
 \f
-static bfd_boolean
-create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
-{
-  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
-
-  lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
-                                    TRUE, FALSE, TRUE);
-  if (lsect->sym == NULL)
-    return FALSE;
-  if (lsect->sym->root.type == bfd_link_hash_new)
-    lsect->sym->non_elf = 0;
-  lsect->sym->ref_regular = 1;
-  _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
-  return TRUE;
-}
-
-/* Create a special linker section.  */
-
-static bfd_boolean
-ppc_elf_create_linker_section (bfd *abfd,
-                              struct bfd_link_info *info,
-                              flagword flags,
-                              elf_linker_section_t *lsect)
-{
-  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
-  asection *s;
-
-  flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-           | SEC_LINKER_CREATED);
-
-  /* Record the first bfd that needs the special sections.  */
-  if (!htab->elf.dynobj)
-    htab->elf.dynobj = abfd;
-
-  s = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
-                                         lsect->name,
-                                         flags);
-  if (s == NULL
-      || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
-    return FALSE;
-  lsect->section = s;
-
-  return create_sdata_sym (info, lsect);
-}
-
 /* Find a linker generated pointer with a given addend and type.  */
 
 static elf_linker_section_pointers_t *
@@ -3668,10 +3676,10 @@ elf_find_pointer_linker_section
 /* Allocate a pointer to live in a linker created section.  */
 
 static bfd_boolean
-elf_create_pointer_linker_section (bfd *abfd,
-                                  elf_linker_section_t *lsect,
-                                  struct elf_link_hash_entry *h,
-                                  const Elf_Internal_Rela *rel)
+elf_allocate_pointer_linker_section (bfd *abfd,
+                                    elf_linker_section_t *lsect,
+                                    struct elf_link_hash_entry *h,
+                                    const Elf_Internal_Rela *rel)
 {
   elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
   elf_linker_section_pointers_t *linker_section_ptr;
@@ -3739,6 +3747,8 @@ elf_create_pointer_linker_section (bfd *abfd,
   linker_section_ptr->lsect = lsect;
   *ptr_linker_section_ptr = linker_section_ptr;
 
+  if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2))
+    return FALSE;
   linker_section_ptr->offset = lsect->section->size;
   lsect->section->size += 4;
 
@@ -3866,7 +3876,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.
@@ -3963,14 +3973,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))
@@ -4021,7 +4031,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->executable)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
@@ -4060,7 +4070,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;
@@ -4069,17 +4079,14 @@ 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;
            }
-         if (htab->sdata[0].section == NULL
-             && !ppc_elf_create_linker_section (abfd, info, 0,
-                                                &htab->sdata[0]))
-           return FALSE;
-         if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
-                                                 h, rel))
+         htab->sdata[0].sym->ref_regular = 1;
+         if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0],
+                                                   h, rel))
            return FALSE;
          if (h != NULL)
            {
@@ -4090,17 +4097,14 @@ 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;
            }
-         if (htab->sdata[1].section == NULL
-             && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
-                                                &htab->sdata[1]))
-           return FALSE;
-         if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
-                                                 h, rel))
+         htab->sdata[1].sym->ref_regular = 1;
+         if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1],
+                                                   h, rel))
            return FALSE;
          if (h != NULL)
            {
@@ -4109,21 +4113,16 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          break;
 
+       case R_PPC_SDAREL16:
+         htab->sdata[0].sym->ref_regular = 1;
+         /* Fall thru */
+
        case R_PPC_VLE_SDAREL_LO16A:
        case R_PPC_VLE_SDAREL_LO16D:
        case R_PPC_VLE_SDAREL_HI16A:
        case R_PPC_VLE_SDAREL_HI16D:
        case R_PPC_VLE_SDAREL_HA16A:
        case R_PPC_VLE_SDAREL_HA16D:
-       case R_PPC_SDAREL16:
-         if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[0]))
-           return FALSE;
-
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
-
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4143,14 +4142,12 @@ 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;
            }
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
+         htab->sdata[1].sym->ref_regular = 1;
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4162,17 +4159,11 @@ 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;
            }
-         if (htab->sdata[0].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[0]))
-           return FALSE;
-         if (htab->sdata[1].sym == NULL
-             && !create_sdata_sym (info, &htab->sdata[1]))
-           return FALSE;
          if (h != NULL)
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
@@ -4185,7 +4176,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;
@@ -4229,7 +4220,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;
@@ -4295,7 +4286,7 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
-             if (info->shared)
+             if (bfd_link_pic (info))
                {
                  info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
                                          abfd, sec, rel->r_offset,
@@ -4331,7 +4322,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
-         if (!info->executable)
+         if (bfd_link_pic (info))
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
 
@@ -4344,7 +4335,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
@@ -4379,7 +4370,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.  */
@@ -4389,6 +4380,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;
 
@@ -4413,7 +4408,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.  */
@@ -4445,14 +4440,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)))
@@ -4790,20 +4785,19 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 }
 
 static void
-ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
-                 bfd_vma offset, bfd_vma relocation,
-                split16_format_type split16_format)
+ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
+                    bfd_vma value,
+                    split16_format_type split16_format)
 
 {
-  bfd_vma insn, top5, bottom11;
+  unsigned int insn, top5;
 
-  insn = bfd_get_32 (output_bfd, contents + offset);
-  top5 = relocation >> 11;
-  top5 = top5 << (split16_format == split16a_type ? 20 : 16);
-  bottom11 = relocation & 0x7ff;
+  insn = bfd_get_32 (output_bfd, loc);
+  top5 = value & 0xf800;
+  top5 = top5 << (split16_format == split16a_type ? 9 : 5);
   insn |= top5;
-  insn |= bottom11;
-  bfd_put_32 (output_bfd, insn, contents + offset);
+  insn |= value & 0x7ff;
+  bfd_put_32 (output_bfd, insn, loc);
 }
 
 \f
@@ -4824,7 +4818,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
@@ -4852,7 +4846,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
             --secure-plt and we never see REL16 relocs.  */
          if (plt_type == PLT_UNSET)
            plt_type = PLT_OLD;
-         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+         for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
            if (is_ppc_elf (ibfd))
              {
                if (ppc_elf_tdata (ibfd)->has_rel16)
@@ -4940,7 +4934,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)
@@ -4986,7 +4980,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 **)
@@ -4999,7 +4993,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)
@@ -5034,7 +5028,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;
 
@@ -5070,7 +5064,7 @@ 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;
 
        case R_PPC_PLT32:
@@ -5084,7 +5078,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)
@@ -5110,6 +5104,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;
@@ -5207,7 +5204,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);
@@ -5221,7 +5218,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
      notify relocate_section that optimization can be done, and
      adjust got and plt refcounts.  */
   for (pass = 0; pass < 2; ++pass)
-    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
       {
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
@@ -5380,7 +5377,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,
@@ -5530,9 +5527,24 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             will go to this object, or will remain undefined.  */
          h->plt.plist = NULL;
          h->needs_plt = 0;
+         h->pointer_equality_needed = 0;
        }
       else
        {
+         /* Taking a function's address in a read/write section
+            doesn't require us to define the function symbol in the
+            executable on a plt call stub.  A dynamic reloc can
+            be used instead.  */
+         if (h->pointer_equality_needed
+             && h->type != STT_GNU_IFUNC
+             && !htab->is_vxworks
+             && !ppc_elf_hash_entry (h)->has_sda_refs
+             && !readonly_dynrelocs (h))
+           {
+             h->pointer_equality_needed = 0;
+             h->non_got_ref = 0;
+           }
+
          /* After adjust_dynamic_symbol, non_got_ref set in the
             non-shared case means that we have allocated space in
             .dynbss for the symbol and thus dyn_relocs for this
@@ -5542,14 +5554,15 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
             relocations against this symbol to the PLT entry.  Allow
             dynamic relocs if the reference is weak, and the dynamic
             relocs will not cause text relocation.  */
-         if (!h->ref_regular_nonweak
-             && h->non_got_ref
-             && h->type != STT_GNU_IFUNC
-             && !htab->is_vxworks
-             && !ppc_elf_hash_entry (h)->has_sda_refs
-             && !readonly_dynrelocs (h))
+         else if (!h->ref_regular_nonweak
+                  && h->non_got_ref
+                  && h->type != STT_GNU_IFUNC
+                  && !htab->is_vxworks
+                  && !ppc_elf_hash_entry (h)->has_sda_refs
+                  && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
        }
+      h->protected_def = 0;
       return TRUE;
     }
   else
@@ -5576,13 +5589,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.
@@ -5636,7 +5678,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
@@ -5656,7 +5698,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.";
@@ -5687,6 +5729,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;
 }
@@ -5764,7 +5807,7 @@ 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))
              {
@@ -5782,7 +5825,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;
@@ -5791,7 +5834,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)
                      {
@@ -5830,7 +5873,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)
                          {
@@ -5864,7 +5907,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                        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
@@ -5907,7 +5950,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;
@@ -5950,7 +5999,7 @@ 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))
@@ -5981,7 +6030,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
@@ -6050,7 +6099,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.  */
@@ -6120,7 +6173,7 @@ static const unsigned char glink_eh_frame_cie[] =
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
-ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ppc_elf_size_dynamic_sections (bfd *output_bfd,
                               struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab;
@@ -6138,7 +6191,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   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);
@@ -6154,7 +6207,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
     {
       bfd_signed_vma *local_got;
       bfd_signed_vma *end_local_got;
@@ -6238,7 +6291,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
            else
              {
                *local_got = allocate_got (htab, need);
-               if (info->shared)
+               if (bfd_link_pic (info))
                  {
                    asection *srel = htab->relgot;
                    if ((*lgot_masks & PLT_IFUNC) != 0)
@@ -6273,7 +6326,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                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;
@@ -6297,7 +6350,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   if (htab->tlsld_got.refcount > 0)
     {
       htab->tlsld_got.offset = allocate_got (htab, 8);
-      if (info->shared)
+      if (bfd_link_pic (info))
        htab->relgot->size += sizeof (Elf32_External_Rela);
     }
   else
@@ -6321,17 +6374,22 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       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;
-      if (sda != NULL
-         && !(sda->root.type == bfd_link_hash_defined
-              || sda->root.type == bfd_link_hash_defweak))
-       {
-         sda->root.type = bfd_link_hash_defined;
-         sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
-         sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
-       }
+
+      sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
+      sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
+    }
+  if (info->emitrelocations)
+    {
+      struct elf_link_hash_entry *sda = htab->sdata[0].sym;
+
+      if (sda != NULL && sda->ref_regular)
+       sda->root.u.def.section->flags |= SEC_KEEP;
+      sda = htab->sdata[1].sym;
+      if (sda != NULL && sda->ref_regular)
+       sda->root.u.def.section->flags |= SEC_KEEP;
     }
 
   if (htab->glink != NULL
@@ -6363,6 +6421,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              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);
@@ -6378,6 +6437,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              sh->ref_regular_nonweak = 1;
              sh->forced_local = 1;
              sh->non_elf = 0;
+             sh->root.linker_def = 1;
            }
        }
     }
@@ -6390,7 +6450,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
     {
       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)
@@ -6425,12 +6485,15 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
               || s == htab->sgotplt
               || s == htab->sbss
               || s == htab->dynbss
-              || s == htab->dynsbss
-              || s == htab->sdata[0].section
-              || s == htab->sdata[1].section)
+              || s == htab->dynsbss)
        {
          /* Strip these too.  */
        }
+      else if (s == htab->sdata[0].section
+              || s == htab->sdata[1].section)
+       {
+         strip_section = (s->flags & SEC_KEEP) == 0;
+       }
       else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s),
                             ".rela"))
        {
@@ -6484,7 +6547,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 #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;
@@ -6563,7 +6626,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       /* 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;
@@ -6600,6 +6663,46 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output
+   if it looks like nothing is using them.  */
+
+static void
+maybe_strip_sdasym (bfd *output_bfd, elf_linker_section_t *lsect)
+{
+  struct elf_link_hash_entry *sda = lsect->sym;
+
+  if (sda != NULL && !sda->ref_regular && sda->dynindx == -1)
+    {
+      asection *s;
+
+      s = bfd_get_section_by_name (output_bfd, lsect->name);
+      if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+       {
+         s = bfd_get_section_by_name (output_bfd, lsect->bss_name);
+         if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+           {
+             sda->def_regular = 0;
+             /* This is somewhat magic.  See elf_link_output_extsym.  */
+             sda->ref_dynamic = 1;
+             sda->forced_local = 0;
+           }
+       }
+    }
+}
+
+void
+ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info)
+{
+  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+  if (htab != NULL)
+    {
+      maybe_strip_sdasym (info->output_bfd, &htab->sdata[0]);
+      maybe_strip_sdasym (info->output_bfd, &htab->sdata[1]);
+    }
+}
+
+
 /* Return TRUE if symbol should be hashed in the `.gnu.hash' section.  */
 
 static bfd_boolean
@@ -6641,6 +6744,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
@@ -6654,9 +6758,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.  */
@@ -6669,12 +6773,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;
 
@@ -6690,7 +6794,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);
@@ -6706,7 +6810,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)
        {
@@ -6727,8 +6832,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)
@@ -6747,9 +6853,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;
@@ -6770,6 +6876,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;
            }
@@ -6827,7 +6938,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;
@@ -6835,8 +6946,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)
                {
@@ -6891,6 +7001,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
@@ -6916,7 +7037,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)
@@ -6982,7 +7103,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
@@ -6993,7 +7114,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))
@@ -7008,7 +7129,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;
 
@@ -7023,7 +7144,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;
@@ -7053,11 +7174,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++;
@@ -7107,10 +7228,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);
        }
     }
@@ -7118,7 +7239,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;
@@ -7126,7 +7247,7 @@ ppc_elf_relax_section (bfd *abfd,
       bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
 
       addr = isec->output_section->vma + isec->output_offset;
-      end_addr = addr + trampoff - 1;
+      end_addr = addr + trampoff;
       addr &= -pagesize;
       crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2;
       if (crossings != 0)
@@ -7134,7 +7255,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)
            {
@@ -7147,7 +7268,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
@@ -7174,6 +7303,7 @@ ppc_elf_relax_section (bfd *abfd,
        }
     }
 
+  changes += picfixup_size;
   if (changes != 0)
     {
       /* Append sufficient NOP relocs so we can write out relocation
@@ -7208,10 +7338,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)
@@ -7317,7 +7447,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;
 
@@ -7338,7 +7468,7 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
          p += 4;
          bfd_put_32 (output_bfd, BCTR, p);
          p += 4;
-         bfd_put_32 (output_bfd, NOP, p);
+         bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
          p += 4;
        }
       else
@@ -7527,13 +7657,15 @@ ppc_elf_relocate_section (bfd *output_bfd,
   bfd_boolean ret = TRUE;
   bfd_vma d_offset = (bfd_big_endian (output_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");
@@ -7548,9 +7680,11 @@ 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"));
+  if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+    relax_info = elf_section_data (input_section)->sec_info;
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -7570,6 +7704,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
       bfd_boolean warned;
       unsigned int tls_type, tls_mask, tls_gd;
       struct plt_entry **ifunc;
+      struct reloc_howto_struct alt_howto;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       sym = NULL;
@@ -7611,7 +7746,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
                                           rel, 1, relend, howto, 0, contents);
        }
 
-      if (info->relocatable)
+      if (bfd_link_relocatable (info))
        {
          if (got2 != NULL
              && r_type == R_PPC_PLTREL24
@@ -7713,8 +7848,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 (output_bfd, NOP, contents + rel->r_offset);
                  r_type = R_PPC_NONE;
                }
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -7747,12 +7882,16 @@ 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 (output_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)
                    {
@@ -7767,7 +7906,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.  */
@@ -7902,6 +8042,114 @@ ppc_elf_relocate_section (bfd *output_bfd,
          }
        }
 
+      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 (output_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 (output_bfd, B | off,
+                             contents + rel->r_offset - d_offset);
+                 got_addr = (htab->got->output_section->vma
+                             + htab->got->output_offset
+                             + (h->got.offset & ~1));
+                 rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
+                 rel->r_addend = got_addr;
+                 rel->r_offset = (p - contents) + d_offset;
+                 insn &= ~0xffff;
+                 insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+                 bfd_put_32 (output_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 (output_bfd, insn, p + 4);
+
+                 bfd_put_32 (output_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));
+                 rel++;
+                 rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO);
+                 rel->r_offset += 4;
+
+                 /* Continue on as if we had a got reloc, to output
+                    dynamic reloc.  */
+                 r_type = R_PPC_GOT16_LO;
+               }
+             else
+               info->callbacks->einfo
+                 (_("%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 (output_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
+                 (_("%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)
        {
@@ -7924,11 +8172,11 @@ 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);
            }
@@ -8056,8 +8304,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
@@ -8125,7 +8373,7 @@ 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
@@ -8169,7 +8417,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++
@@ -8187,9 +8440,14 @@ 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))
                              {
@@ -8236,6 +8494,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  }
              }
 
+           /* If here for a picfixup, we're done.  */
+           if (r_type != ELF32_R_TYPE (rel->r_info))
+             continue;
+
            relocation = (htab->got->output_section->vma
                          + htab->got->output_offset
                          + off
@@ -8252,9 +8514,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                 howto->name,
                 sym_name);
          }
-       break;
+         break;
 
-       /* Relocations that need no special processing.  */
+         /* Relocations that need no special processing.  */
        case R_PPC_LOCAL24PC:
          /* It makes no sense to point a local relocation
             at a symbol not in this object.  */
@@ -8275,7 +8537,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
@@ -8299,18 +8562,21 @@ ppc_elf_relocate_section (bfd *output_bfd,
                bfd_put_32 (output_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:
@@ -8356,7 +8622,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 */
 
@@ -8365,7 +8631,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
@@ -8375,11 +8641,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;
@@ -8522,7 +8792,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;
                }
@@ -8545,7 +8815,7 @@ 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
@@ -8564,7 +8834,7 @@ 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.  */
@@ -8650,7 +8920,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (h != NULL && ifunc == NULL)
            {
              struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   info->shared ? addend : 0);
+                                                   bfd_link_pic (info) ? addend : 0);
              if (ent == NULL
                  || htab->plt == NULL)
                {
@@ -8696,10 +8966,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
            addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (! ((CONST_STRNEQ (name, ".sdata")
-                   && (name[6] == 0 || name[6] == '.'))
-                  || (CONST_STRNEQ (name, ".sbss")
-                      && (name[5] == 0 || name[5] == '.'))))
+           if (!(strcmp (name, ".sdata") == 0
+                 || strcmp (name, ".sbss") == 0))
              {
                info->callbacks->einfo
                  (_("%P: %B: the target (%s) of a %s relocation is "
@@ -8728,8 +8996,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
            addend -= SYM_VAL (sda);
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (! (CONST_STRNEQ (name, ".sdata2")
-                  || CONST_STRNEQ (name, ".sbss2")))
+           if (!(strcmp (name, ".sdata2") == 0
+                 || strcmp (name, ".sbss2") == 0))
              {
                info->callbacks->einfo
                  (_("%P: %B: the target (%s) of a %s relocation is "
@@ -8743,45 +9011,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC_VLE_LO16A:
-         relocation = (relocation + addend) & 0xffff;
-         ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16a_type);
+         relocation = relocation + addend;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16a_type);
          continue;
 
        case R_PPC_VLE_LO16D:
-         relocation = (relocation + addend) & 0xffff;
-         ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16d_type);
+         relocation = relocation + addend;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16d_type);
          continue;
 
        case R_PPC_VLE_HI16A:
-         relocation = ((relocation + addend) >> 16) & 0xffff;
-         ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16a_type);
+         relocation = (relocation + addend) >> 16;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16a_type);
          continue;
 
        case R_PPC_VLE_HI16D:
-         relocation = ((relocation + addend) >> 16) & 0xffff;
-         ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16d_type);
+         relocation = (relocation + addend) >> 16;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16d_type);
          continue;
 
        case R_PPC_VLE_HA16A:
-         {
-           bfd_vma value = relocation + addend;
-           value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-           ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                 value, split16a_type);
-         }
+         relocation = (relocation + addend + 0x8000) >> 16;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16a_type);
          continue;
 
        case R_PPC_VLE_HA16D:
-         {
-           bfd_vma value = relocation + addend;
-           value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-           ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                 value, split16d_type);
-         }
+         relocation = (relocation + addend + 0x8000) >> 16;
+         ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                              relocation, split16d_type);
          continue;
 
          /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
@@ -8792,6 +9054,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          {
            const char *name;
            int reg;
+           unsigned int insn;
            struct elf_link_hash_entry *sda = NULL;
 
            if (sec == NULL || sec->output_section == NULL)
@@ -8801,16 +9064,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (((CONST_STRNEQ (name, ".sdata")
-                 && (name[6] == 0 || name[6] == '.'))
-                || (CONST_STRNEQ (name, ".sbss")
-                    && (name[5] == 0 || name[5] == '.'))))
+           if (strcmp (name, ".sdata") == 0
+               || strcmp (name, ".sbss") == 0)
              {
                reg = 13;
                sda = htab->sdata[0].sym;
              }
-           else if (CONST_STRNEQ (name, ".sdata2")
-                    || CONST_STRNEQ (name, ".sbss2"))
+           else if (strcmp (name, ".sdata2") == 0
+                    || strcmp (name, ".sbss2") == 0)
              {
                reg = 2;
                sda = htab->sdata[1].sym;
@@ -8845,32 +9106,41 @@ ppc_elf_relocate_section (bfd *output_bfd,
                addend -= SYM_VAL (sda);
              }
 
+           insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
            if (reg == 0
                && (r_type == R_PPC_VLE_SDA21
                    || r_type == R_PPC_VLE_SDA21_LO))
              {
-               /* Use the split20 format.  */
-               bfd_vma insn, bits12to15, bits21to31;
-               bfd_vma value  = (relocation + rel->r_offset) & 0xffff;
-               /* Propagate sign bit, if necessary.  */
-               insn = (value & 0x8000) ? 0x70107800 : 0x70000000;
-               bits12to15 = value & 0x700;
-               bits21to31 = value & 0x7ff;
-               insn |= bits12to15;
-               insn |= bits21to31;
-               bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+               relocation = relocation + addend;
+               addend = 0;
+
+               /* Force e_li insn, keeping RT from original insn.  */
+               insn &= 0x1f << 21;
+               insn |= 28u << 26;
+
+               /* We have an li20 field, bits 17..20, 11..15, 21..31.  */
+               /* Top 4 bits of value to 17..20.  */
+               insn |= (relocation & 0xf0000) >> 5;
+               /* Next 5 bits of the value to 11..15.  */
+               insn |= (relocation & 0xf800) << 5;
+               /* And the final 11 bits of the value to bits 21 to 31.  */
+               insn |= relocation & 0x7ff;
+
+               bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+
+               if (r_type == R_PPC_VLE_SDA21
+                   && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
+                 goto overflow;
                continue;
              }
            else if (r_type == R_PPC_EMB_SDA21
                     || r_type == R_PPC_VLE_SDA21
                     || r_type == R_PPC_VLE_SDA21_LO)
              {
-               bfd_vma insn;  /* Fill in register field.  */
-
-               insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+               /* 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 (output_bfd, insn, contents + rel->r_offset);
          }
          break;
 
@@ -8893,16 +9163,14 @@ ppc_elf_relocate_section (bfd *output_bfd,
              }
 
            name = bfd_get_section_name (output_bfd, sec->output_section);
-           if (((CONST_STRNEQ (name, ".sdata")
-                 && (name[6] == 0 || name[6] == '.'))
-                || (CONST_STRNEQ (name, ".sbss")
-                    && (name[5] == 0 || name[5] == '.'))))
+           if (strcmp (name, ".sdata") == 0
+               || strcmp (name, ".sbss") == 0)
              {
                //reg = 13;
                sda = htab->sdata[0].sym;
              }
-           else if (CONST_STRNEQ (name, ".sdata2")
-                    || CONST_STRNEQ (name, ".sbss2"))
+           else if (strcmp (name, ".sdata2") == 0
+                    || strcmp (name, ".sbss2") == 0)
              {
                //reg = 2;
                sda = htab->sdata[1].sym;
@@ -8931,46 +9199,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
                  }
              }
 
-          value = sda->root.u.def.section->output_section->vma
-                  + sda->root.u.def.section->output_offset;
-
-          if (r_type == R_PPC_VLE_SDAREL_LO16A)
-             {
-               value = (value + addend) & 0xffff;
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
-             }
-          else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+           value = (sda->root.u.def.section->output_section->vma
+                    + sda->root.u.def.section->output_offset
+                    + addend);
+
+           if (r_type == R_PPC_VLE_SDAREL_LO16A)
+             ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                  value, split16a_type);
+           else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+             ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                  value, split16d_type);
+           else if (r_type == R_PPC_VLE_SDAREL_HI16A)
              {
-               value = (value + addend) & 0xffff;
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
+               value = value >> 16;
+               ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                    value, split16a_type);
              }
-          else if (r_type == R_PPC_VLE_SDAREL_HI16A)
+           else if (r_type == R_PPC_VLE_SDAREL_HI16D)
              {
-               value = ((value + addend) >> 16) & 0xffff;
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
+               value = value >> 16;
+               ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                    value, split16d_type);
              }
-          else if (r_type == R_PPC_VLE_SDAREL_HI16D)
+           else if (r_type == R_PPC_VLE_SDAREL_HA16A)
              {
-               value = ((value + addend) >> 16) & 0xffff;
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
+               value = (value + 0x8000) >> 16;
+               ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                    value, split16a_type);
              }
-          else if (r_type == R_PPC_VLE_SDAREL_HA16A)
+           else if (r_type == R_PPC_VLE_SDAREL_HA16D)
              {
-               value += addend;
-               value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
-             }
-          else if (r_type == R_PPC_VLE_SDAREL_HA16D)
-             {
-               value += addend;
-               value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-               ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
+               value = (value + 0x8000) >> 16;
+               ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+                                    value, split16d_type);
              }
          }
          continue;
@@ -9130,42 +9391,57 @@ ppc_elf_relocate_section (bfd *output_bfd,
          ret = FALSE;
        }
 
-      r = _bfd_final_link_relocate (howto,
-                                   input_bfd,
-                                   input_section,
-                                   contents,
-                                   rel->r_offset,
-                                   relocation,
-                                   addend);
+      /* 16-bit fields in insns mostly have signed values, but a
+        few insns have 16-bit unsigned values.  Really, we should
+        have different reloc types.  */
+      if (howto->complain_on_overflow != complain_overflow_dont
+         && howto->dst_mask == 0xffff
+         && (input_section->flags & SEC_CODE) != 0)
+       {
+         enum complain_overflow complain = complain_overflow_signed;
+
+         if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0)
+           {
+             unsigned int insn;
+
+             insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+             if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+               complain = complain_overflow_bitfield;
+             else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+                      || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+                      || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+               complain = complain_overflow_unsigned;
+           }
+         if (howto->complain_on_overflow != complain)
+           {
+             alt_howto = *howto;
+             alt_howto.complain_on_overflow = complain;
+             howto = &alt_howto;
+           }
+       }
+
+      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)
            {
-             if (warned)
-               continue;
-             if (h != NULL
-                 && h->root.type == bfd_link_hash_undefweak
-                 && howto->pc_relative)
+           overflow:
+             /* 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)))
                {
-                 /* 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;
                }
-
-             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;
            }
          else
            {
@@ -9194,18 +9470,28 @@ 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)
-       memset (contents + input_section->size - relax_info->workaround_size,
-               0, relax_info->workaround_size);
+       {
+         bfd_byte *p;
+         unsigned int n;
+         bfd_byte fill[4];
+
+         bfd_put_32 (input_bfd, BA, fill);
+         p = contents + input_section->size - relax_info->workaround_size;
+         n = relax_info->workaround_size >> 2;
+         while (n--)
+           {
+             memcpy (p, fill, 4);
+             p += 4;
+           }
+       }
 
       /* The idea is: Replace the last instruction on a page with a
         branch to a patch area.  Put the insn there followed by a
@@ -9259,27 +9545,56 @@ ppc_elf_relocate_section (bfd *output_bfd,
          if (is_data)
            continue;
 
-         /* Some instructions can be left alone too.  In this
-            category are most insns that unconditionally change
-            control flow, and isync.  Of these, some *must* be left
-            alone, for example, the "bcl 20, 31, label" used in pic
-            sequences to give the address of the next insn.  twui
-            and twu apparently are not safe.  */
+         /* Some instructions can be left alone too.  Unconditional
+            branches, except for bcctr with BO=0x14 (bctr, bctrl),
+            avoid the icache failure.
+
+            The problem occurs due to prefetch across a page boundary
+            where stale instructions can be fetched from the next
+            page, and the mechanism for flushing these bad
+            instructions fails under certain circumstances.  The
+            unconditional branches:
+            1) Branch: b, bl, ba, bla,
+            2) Branch Conditional: bc, bca, bcl, bcla,
+            3) Branch Conditional to Link Register: bclr, bclrl,
+            where (2) and (3) have BO=0x14 making them unconditional,
+            prevent the bad prefetch because the prefetch itself is
+            affected by these instructions.  This happens even if the
+            instruction is not executed.
+
+            A bctr example:
+            .
+            .  lis 9,new_page@ha
+            .  addi 9,9,new_page@l
+            .  mtctr 9
+            .  bctr
+            .  nop
+            .  nop
+            . new_page:
+            .
+            The bctr is not predicted taken due to ctr not being
+            ready, so prefetch continues on past the bctr into the
+            new page which might have stale instructions.  If they
+            fail to be flushed, then they will be executed after the
+            bctr executes.  Either of the following modifications
+            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
+            .  nop                      b somewhere_else
+            .  b somewhere_else         nop
+            . new_page:                new_page:
+            .  */
          insn = bfd_get_32 (input_bfd, contents + offset);
-         if (insn == 0
-             || (insn & (0x3f << 26)) == (18u << 26)        /* b */
-             || ((insn & (0x3f << 26)) == (16u << 26)       /* bc always */
-                 && (insn & (0x14 << 21)) == (0x14 << 21))
-             || ((insn & (0x3f << 26)) == (19u << 26)       /* blr, bctr */
-                 && (insn & (0x14 << 21)) == (0x14 << 21)
-                 && (insn & (0x1ff << 1)) == (16u << 1))
-             || (insn & (0x3f << 26)) == (17u << 26)        /* sc */
+         if ((insn & (0x3f << 26)) == (18u << 26)          /* b,bl,ba,bla */
+             || ((insn & (0x3f << 26)) == (16u << 26)      /* bc,bcl,bca,bcla*/
+                 && (insn & (0x14 << 21)) == (0x14 << 21)) /*   with BO=0x14 */
              || ((insn & (0x3f << 26)) == (19u << 26)
-                 && ((insn & (0x3ff << 1)) == (38u << 1)    /* rfmci */
-                     || (insn & (0x3ff << 1)) == (50u << 1) /* rfi */
-                     || (insn & (0x3ff << 1)) == (51u << 1) /* rfci */
-                     || (insn & (0x3ff << 1)) == (82u << 1) /* rfsvc */
-                     || (insn & (0x3ff << 1)) == (150u << 1))) /* isync */)
+                 && (insn & (0x3ff << 1)) == (16u << 1)    /* bclr,bclrl */
+                 && (insn & (0x14 << 21)) == (0x14 << 21)))/*   with BO=0x14 */
            continue;
 
          patch_addr = (start_addr + input_section->size
@@ -9292,6 +9607,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.  */
@@ -9304,6 +9621,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;
@@ -9314,9 +9682,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;
 
@@ -9442,11 +9810,11 @@ 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),
@@ -9504,7 +9872,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
                                         + ent->plt.offset + 16),
                            htab->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
@@ -9626,7 +9994,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
@@ -9678,7 +10046,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;
          }
@@ -9873,11 +10241,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   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);
 
@@ -9898,7 +10266,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;
@@ -10066,7 +10434,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       p += htab->glink_pltresolve;
       endp = htab->glink->contents;
       endp += htab->glink->size - GLINK_PLTRESOLVE;
-      while (p < endp - 8 * 4)
+      while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4))
        {
          bfd_put_32 (output_bfd, B + endp - p, p);
          p += 4;
@@ -10081,14 +10449,51 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              + htab->glink->output_section->vma
              + htab->glink->output_offset);
 
+      if (htab->params->ppc476_workaround)
+       {
+         /* Ensure that a call stub at the end of a page doesn't
+            result in prefetch over the end of the page into the
+            glink branch table.  */
+         bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+         bfd_vma page_addr;
+         bfd_vma glink_start = (htab->glink->output_section->vma
+                                + htab->glink->output_offset);
+
+         for (page_addr = res0 & -pagesize;
+              page_addr > glink_start;
+              page_addr -= pagesize)
+           {
+             /* We have a plt call stub that may need fixing.  */
+             bfd_byte *loc;
+             unsigned int insn;
+
+             loc = htab->glink->contents + page_addr - 4 - glink_start;
+             insn = bfd_get_32 (output_bfd, loc);
+             if (insn == BCTR)
+               {
+                 /* By alignment, we know that there must be at least
+                    one other call stub before this one.  */
+                 insn = bfd_get_32 (output_bfd, loc - 16);
+                 if (insn == BCTR)
+                   bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc);
+                 else
+                   bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc);
+               }
+           }
+       }
+
       /* Last comes the PLTresolve stub.  */
-      if (info->shared)
+      if (bfd_link_pic (info))
        {
          bfd_vma bcl;
 
          for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
+             unsigned int insn = pic_plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (pic_plt_resolve);
@@ -10122,7 +10527,11 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
        {
          for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
            {
-             bfd_put_32 (output_bfd, plt_resolve[i], p);
+             unsigned int insn = plt_resolve[i];
+
+             if (htab->params->ppc476_workaround && insn == NOP)
+               insn = BA + 0;
+             bfd_put_32 (output_bfd, insn, p);
              p += 4;
            }
          p -= 4 * ARRAY_SIZE (plt_resolve);
@@ -10179,20 +10588,21 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
   return ret;
 }
 \f
-#define TARGET_LITTLE_SYM      bfd_elf32_powerpcle_vec
+#define TARGET_LITTLE_SYM      powerpc_elf32_le_vec
 #define TARGET_LITTLE_NAME     "elf32-powerpcle"
-#define TARGET_BIG_SYM         bfd_elf32_powerpc_vec
+#define TARGET_BIG_SYM         powerpc_elf32_vec
 #define TARGET_BIG_NAME                "elf32-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
 #define ELF_TARGET_ID          PPC32_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC
 #ifdef __QNXTARGET__
 #define ELF_MAXPAGESIZE                0x1000
+#define ELF_COMMONPAGESIZE     0x1000
 #else
 #define ELF_MAXPAGESIZE                0x10000
+#define ELF_COMMONPAGESIZE     0x10000
 #endif
 #define ELF_MINPAGESIZE                0x1000
-#define ELF_COMMONPAGESIZE     0x1000
 #define elf_info_to_howto      ppc_elf_info_to_howto
 
 #ifdef  EM_CYGNUS_POWERPC
@@ -10257,7 +10667,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #undef  TARGET_LITTLE_NAME
 
 #undef  TARGET_BIG_SYM
-#define TARGET_BIG_SYM  bfd_elf32_powerpc_freebsd_vec
+#define TARGET_BIG_SYM  powerpc_elf32_fbsd_vec
 #undef  TARGET_BIG_NAME
 #define TARGET_BIG_NAME "elf32-powerpc-freebsd"
 
@@ -10275,7 +10685,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #undef TARGET_LITTLE_NAME
 
 #undef TARGET_BIG_SYM
-#define TARGET_BIG_SYM         bfd_elf32_powerpc_vxworks_vec
+#define TARGET_BIG_SYM         powerpc_elf32_vxworks_vec
 #undef TARGET_BIG_NAME
 #define TARGET_BIG_NAME                "elf32-powerpc-vxworks"
 
This page took 0.069741 seconds and 4 git commands to generate.