gas: detect DCTI couples in sparc
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index 5c26077ad03bf8007c20ad6f1637d35c6f917680..e808cb523f53d12eec082d82862b015ebf78d141 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC-specific support for 32-bit ELF
-   Copyright (C) 1994-2015 Free Software Foundation, Inc.
+   Copyright (C) 1994-2016 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -35,7 +35,6 @@
 #include "elf32-ppc.h"
 #include "elf-vxworks.h"
 #include "dwarf2.h"
-#include "elf-linux-psinfo.h"
 
 typedef enum split16_format_type
 {
@@ -414,7 +413,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -430,7 +429,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_LO",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -446,7 +445,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -462,7 +461,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GOT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -477,8 +476,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         26,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_signed,  /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLTREL24",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -497,7 +496,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_COPY",          /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -513,7 +512,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_GLOB_DAT",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -528,7 +527,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_JMP_SLOT",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -623,7 +622,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT32",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -639,7 +638,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLTREL32",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -655,7 +654,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_LO",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -671,7 +670,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_HI",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -687,7 +686,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_PLT16_HA",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -703,7 +702,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SDAREL16",      /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -718,7 +717,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF",       /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -733,7 +732,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_LO",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -748,7 +747,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_HI",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -763,7 +762,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_SECTOFF_HA",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1239,7 +1238,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR32",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1254,7 +1253,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1269,7 +1268,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_ADDR16_LO", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1284,7 +1283,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16_HI", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1301,7 +1300,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        ppc_elf_addr16_ha_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_NADDR16_HA", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1318,7 +1317,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDAI16",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1335,7 +1334,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA2I16",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1351,7 +1350,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA2REL",   /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1368,7 +1367,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_SDA21",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1392,7 +1391,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_EMB_RELSDA",    /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1426,7 +1425,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         "R_PPC_VLE_REL15",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfe,                  /* dst_mask */
+        0xfffe,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
   /* A relative 24 bit branch.  */
@@ -1452,7 +1451,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_VLE_LO16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1467,8 +1466,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_LO16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_LO16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
@@ -1482,8 +1481,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HI16A",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HI16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f007ff,             /* dst_mask */
@@ -1497,8 +1496,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HI16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HI16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
@@ -1512,8 +1511,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HA16A",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HA16A",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f007ff,             /* dst_mask */
@@ -1527,8 +1526,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_HA16D",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_HA16D",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
@@ -1544,8 +1543,8 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_PPC_VLE_SDA21",             /* name */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDA21",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
@@ -1559,7 +1558,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_VLE_SDA21_LO",  /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1573,9 +1572,9 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_LO16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_LO16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f007ff,             /* dst_mask */
@@ -1588,69 +1587,69 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_LO16D",              /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_LO16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16A,       /* type */
+  HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HI16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HI16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HI16D,       /* type */
+  HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HI16D",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HI16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16A,       /* type */
+  HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HA16A",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HA16A", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f007ff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
-  HOWTO (R_PPC_VLE_SDAREL_HA16D,       /* type */
+  HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_dont,        /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
-        "R_PPC_VLE_SDAREL_HA16D",      /* name */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc_elf_unhandled_reloc, /* special_function */
+        "R_PPC_VLE_SDAREL_HA16D", /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0x1f07ff,              /* dst_mask */
@@ -1663,7 +1662,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        bfd_elf_generic_reloc,  /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_IRELATIVE",     /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1731,6 +1730,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* Like R_PPC_REL16_HA but for split field in addpcis.  */
+  HOWTO (R_PPC_REL16DX_HA,     /* type */
+        16,                    /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc_elf_addr16_ha_reloc, /* special_function */
+        "R_PPC_REL16DX_HA",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x1fffc1,              /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC_GNU_VTINHERIT,  /* type */
         0,                     /* rightshift */
@@ -1769,7 +1783,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
+        ppc_elf_unhandled_reloc, /* special_function */
         "R_PPC_TOC16",         /* name */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
@@ -1804,30 +1818,28 @@ struct elf_external_ppc_linux_prpsinfo32
     char pr_psargs[80];                        /* Initial part of arg list.  */
   };
 
-/* Helper macro to swap (properly handling endianess) things from the
-   `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32'
-   structure.
-
-   Note that FROM should be a pointer, and TO should be the explicit type.  */
-
-#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to)             \
-  do                                                                 \
-    {                                                                \
-      H_PUT_8 (abfd, from->pr_state, &to.pr_state);                  \
-      H_PUT_8 (abfd, from->pr_sname, &to.pr_sname);                  \
-      H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb);                    \
-      H_PUT_8 (abfd, from->pr_nice, &to.pr_nice);                    \
-      H_PUT_32 (abfd, from->pr_flag, to.pr_flag);                    \
-      H_PUT_32 (abfd, from->pr_uid, to.pr_uid);                              \
-      H_PUT_32 (abfd, from->pr_gid, to.pr_gid);                              \
-      H_PUT_32 (abfd, from->pr_pid, to.pr_pid);                              \
-      H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid);                    \
-      H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp);                    \
-      H_PUT_32 (abfd, from->pr_sid, to.pr_sid);                              \
-      strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname));    \
-      strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
-    } while (0)
+/* Helper function to copy an elf_internal_linux_prpsinfo in host
+   endian to an elf_external_ppc_linux_prpsinfo32 in target endian.  */
 
+static inline void
+swap_ppc_linux_prpsinfo32_out (bfd *obfd,
+                              const struct elf_internal_linux_prpsinfo *from,
+                              struct elf_external_ppc_linux_prpsinfo32 *to)
+{
+  bfd_put_8 (obfd, from->pr_state, &to->pr_state);
+  bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
+  bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
+  bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
+  bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
+  bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
+  bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
+  bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
+  bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
+  bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
+  bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
+  strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
+  strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
+}
 \f
 /* Initialize the ppc_elf_howto_table, so that linear accesses can be done.  */
 
@@ -1989,6 +2001,7 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
     case BFD_RELOC_LO16_PCREL:         r = R_PPC_REL16_LO;             break;
     case BFD_RELOC_HI16_PCREL:         r = R_PPC_REL16_HI;             break;
     case BFD_RELOC_HI16_S_PCREL:       r = R_PPC_REL16_HA;             break;
+    case BFD_RELOC_PPC_REL16DX_HA:     r = R_PPC_REL16DX_HA;           break;
     case BFD_RELOC_VTABLE_INHERIT:     r = R_PPC_GNU_VTINHERIT;        break;
     case BFD_RELOC_VTABLE_ENTRY:       r = R_PPC_GNU_VTENTRY;          break;
     }
@@ -2058,7 +2071,10 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
                         bfd *output_bfd,
                         char **error_message ATTRIBUTE_UNUSED)
 {
-  bfd_vma relocation;
+  enum elf_ppc_reloc_type r_type;
+  long insn;
+  bfd_size_type octets;
+  bfd_vma value;
 
   if (output_bfd != NULL)
     {
@@ -2066,20 +2082,28 @@ ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
       return bfd_reloc_ok;
     }
 
-  if (bfd_is_com_section (symbol->section))
-    relocation = 0;
-  else
-    relocation = symbol->value;
-
-  relocation += symbol->section->output_section->vma;
-  relocation += symbol->section->output_offset;
-  relocation += reloc_entry->addend;
-  if (reloc_entry->howto->pc_relative)
-    relocation -= reloc_entry->address;
-
-  reloc_entry->addend += (relocation & 0x8000) << 1;
-
-  return bfd_reloc_continue;
+  reloc_entry->addend += 0x8000;
+  r_type = reloc_entry->howto->type;
+  if (r_type != R_PPC_REL16DX_HA)
+    return bfd_reloc_continue;
+
+  value = 0;
+  if (!bfd_is_com_section (symbol->section))
+    value = symbol->value;
+  value += (reloc_entry->addend
+           + symbol->section->output_offset
+           + symbol->section->output_section->vma);
+  value -= (reloc_entry->address
+           + input_section->output_offset
+           + input_section->output_section->vma);
+  value >>= 16;
+
+  octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+  insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+  insn &= ~0x1fffc1;
+  insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+  bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+  return bfd_reloc_ok;
 }
 
 static bfd_reloc_status_type
@@ -2172,13 +2196,94 @@ ppc_elf_mkobject (bfd *abfd)
                                  PPC32_ELF_DATA);
 }
 
+/* When defaulting arch/mach, decode apuinfo to find a better match.  */
+
+bfd_boolean
+_bfd_elf_ppc_set_arch (bfd *abfd)
+{
+  unsigned long mach = 0;
+  asection *s;
+  unsigned char *contents;
+
+  if (abfd->arch_info->bits_per_word == 32
+      && bfd_big_endian (abfd))
+    {
+
+      for (s = abfd->sections; s != NULL; s = s->next)
+       if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0)
+         break;
+      if (s != NULL)
+       mach = bfd_mach_ppc_vle;
+    }
+
+  if (mach == 0)
+    {
+      s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+      if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+       {
+         unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
+         unsigned int i;
+
+         for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4)
+           {
+             unsigned int val = bfd_get_32 (abfd, contents + i);
+             switch (val >> 16)
+               {
+               case PPC_APUINFO_PMR:
+               case PPC_APUINFO_RFMCI:
+                 if (mach == 0)
+                   mach = bfd_mach_ppc_titan;
+                 break;
+
+               case PPC_APUINFO_ISEL:
+               case PPC_APUINFO_CACHELCK:
+                 if (mach == bfd_mach_ppc_titan)
+                   mach = bfd_mach_ppc_e500mc;
+                 break;
+
+               case PPC_APUINFO_SPE:
+               case PPC_APUINFO_EFS:
+               case PPC_APUINFO_BRLOCK:
+                 if (mach != bfd_mach_ppc_vle)
+                   mach = bfd_mach_ppc_e500;
+                 break;
+
+               case PPC_APUINFO_VLE:
+                 mach = bfd_mach_ppc_vle;
+                 break;
+
+               default:
+                 mach = -1ul;
+               }
+           }
+         free (contents);
+       }
+    }
+
+  if (mach != 0 && mach != -1ul)
+    {
+      const bfd_arch_info_type *arch;
+
+      for (arch = abfd->arch_info->next; arch; arch = arch->next)
+       if (arch->mach == mach)
+         {
+           abfd->arch_info = arch;
+           break;
+         }
+    }
+  return TRUE;
+}
+
 /* Fix bad default arch selected for a 32 bit input bfd when the
-   default is 64 bit.  */
+   default is 64 bit.  Also select arch based on apuinfo.  */
 
 static bfd_boolean
 ppc_elf_object_p (bfd *abfd)
 {
-  if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64)
+  if (!abfd->arch_info->the_default)
+    return TRUE;
+
+  if (abfd->arch_info->bits_per_word == 64)
     {
       Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
 
@@ -2189,7 +2294,7 @@ ppc_elf_object_p (bfd *abfd)
          BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
        }
     }
-  return TRUE;
+  return _bfd_elf_ppc_set_arch (abfd);
 }
 
 /* Function to set whether a module needs the -mrelocatable bit set.  */
@@ -2270,14 +2375,15 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 }
 
 char *
-elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz,
-                                     const struct elf_internal_linux_prpsinfo *prpsinfo)
+elfcore_write_ppc_linux_prpsinfo32
+  (bfd *abfd,
+   char *buf,
+   int *bufsiz,
+   const struct elf_internal_linux_prpsinfo *prpsinfo)
 {
   struct elf_external_ppc_linux_prpsinfo32 data;
 
-  memset (&data, 0, sizeof (data));
-  PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
-
+  swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
   return elfcore_write_note (abfd, buf, bufsiz,
                             "CORE", NT_PRPSINFO, &data, sizeof (data));
 }
@@ -2338,18 +2444,6 @@ ppc_elf_lookup_section_flags (char *flag_name)
   return 0;
 }
 
-/* Add the VLE flag if required.  */
-
-bfd_boolean
-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
-{
-  if (bfd_get_mach (abfd) == bfd_mach_ppc_vle
-      && (shdr->sh_flags & SHF_EXECINSTR) != 0)
-    shdr->sh_flags |= SHF_PPC_VLE;
-
-  return TRUE;
-}
-
 /* Return address for Ith PLT stub in section PLT, for relocation REL
    or (bfd_vma) -1 if it should not be included.  */
 
@@ -2429,10 +2523,7 @@ bfd_boolean
 ppc_elf_modify_segment_map (bfd *abfd,
                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
-  struct elf_segment_map *m, *n;
-  bfd_size_type amt;
-  unsigned int j, k;
-  bfd_boolean sect0_vle, sectj_vle;
+  struct elf_segment_map *m;
 
   /* At this point in the link, output sections have already been sorted by
      LMA and assigned to segments.  All that is left to do is to ensure
@@ -2442,25 +2533,59 @@ ppc_elf_modify_segment_map (bfd *abfd,
 
   for (m = elf_seg_map (abfd); m != NULL; m = m->next)
     {
-      if (m->count == 0)
+      struct elf_segment_map *n;
+      bfd_size_type amt;
+      unsigned int j, k;
+      unsigned int p_flags;
+
+      if (m->p_type != PT_LOAD || m->count == 0)
        continue;
 
-      sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
-      for (j = 1; j < m->count; ++j)
+      for (p_flags = PF_R, j = 0; j != m->count; ++j)
        {
-         sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
+         if ((m->sections[j]->flags & SEC_READONLY) == 0)
+           p_flags |= PF_W;
+         if ((m->sections[j]->flags & SEC_CODE) != 0)
+           {
+             p_flags |= PF_X;
+             if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+               p_flags |= PF_PPC_VLE;
+             break;
+           }
+       }
+      if (j != m->count)
+       while (++j != m->count)
+         {
+           unsigned int p_flags1 = PF_R;
 
-         if (sectj_vle != sect0_vle)
-           break;
-        }
-      if (j >= m->count)
+           if ((m->sections[j]->flags & SEC_READONLY) == 0)
+             p_flags1 |= PF_W;
+           if ((m->sections[j]->flags & SEC_CODE) != 0)
+             {
+               p_flags1 |= PF_X;
+               if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+                 p_flags1 |= PF_PPC_VLE;
+               if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0)
+                 break;
+             }
+           p_flags |= p_flags1;
+         }
+      /* If we're splitting a segment which originally contained rw
+        sections then those sections might now only be in one of the
+        two parts.  So always set p_flags if splitting, even if we
+        are being called for objcopy with p_flags_valid set.  */
+      if (j != m->count || !m->p_flags_valid)
+       {
+         m->p_flags_valid = 1;
+         m->p_flags = p_flags;
+       }
+      if (j == m->count)
        continue;
 
-      /* sections 0..j-1 stay in this (current) segment,
+      /* Sections 0..j-1 stay in this (current) segment,
         the remainder are put in a new segment.
         The scan resumes with the new segment.  */
 
-      /* Fix the new segment.  */
       amt = sizeof (struct elf_segment_map);
       amt += (m->count - j - 1) * sizeof (asection *);
       n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
@@ -2468,20 +2593,13 @@ ppc_elf_modify_segment_map (bfd *abfd,
         return FALSE;
 
       n->p_type = PT_LOAD;
-      n->p_flags = PF_X | PF_R;
-      if (sectj_vle)
-        n->p_flags |= PF_PPC_VLE;
       n->count = m->count - j;
       for (k = 0; k < n->count; ++k)
-        {
-          n->sections[k] = m->sections[j+k];
-          m->sections[j+k] = NULL;
-       }
+       n->sections[k] = m->sections[j + k];
+      m->count = j;
+      m->p_size_valid = 0;
       n->next = m->next;
       m->next = n;
-
-      /* Fix the current segment  */
-      m->count = j;
     }
 
   return TRUE;
@@ -2494,16 +2612,16 @@ ppc_elf_modify_segment_map (bfd *abfd,
 
 static const struct bfd_elf_special_section ppc_elf_special_sections[] =
 {
-  { STRING_COMMA_LEN (".plt"),             0, SHT_NOBITS,   SHF_ALLOC + SHF_EXECINSTR },
-  { STRING_COMMA_LEN (".sbss"),           -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
-  { STRING_COMMA_LEN (".sbss2"),          -2, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".sdata"),          -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
-  { STRING_COMMA_LEN (".sdata2"),         -2, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".tags"),            0, SHT_ORDERED,  SHF_ALLOC },
-  { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE,     0 },
-  { STRING_COMMA_LEN (".PPC.EMB.sbss0"),   0, SHT_PROGBITS, SHF_ALLOC },
-  { STRING_COMMA_LEN (".PPC.EMB.sdata0"),  0, SHT_PROGBITS, SHF_ALLOC },
-  { NULL,                              0,  0, 0,            0 }
+  { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC },
+  { STRING_COMMA_LEN (APUINFO_SECTION_NAME), 0, SHT_NOTE, 0 },
+  { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC },
+  { NULL, 0, 0, 0, 0 }
 };
 
 /* This is what we want for new plt/got.  */
@@ -2612,9 +2730,6 @@ apuinfo_list_finish (void)
   head = NULL;
 }
 
-#define APUINFO_SECTION_NAME   ".PPC.EMB.apuinfo"
-#define APUINFO_LABEL          "APUinfo"
-
 /* Scan the input BFDs and create a linked list of
    the APUinfo values that will need to be emitted.  */
 
@@ -3263,7 +3378,8 @@ static struct bfd_link_hash_table *
 ppc_elf_link_hash_table_create (bfd *abfd)
 {
   struct ppc_elf_link_hash_table *ret;
-  static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12, 0 };
+  static struct ppc_elf_params default_params
+    = { PLT_OLD, 0, 1, 0, 0, 12, 0, 0 };
 
   ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
   if (ret == NULL)
@@ -3309,6 +3425,7 @@ ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params)
 
   if (htab)
     htab->params = params;
+  params->pagesize_p2 = bfd_log2 (params->pagesize);
 }
 
 /* Create .got and the related sections.  */
@@ -3649,11 +3766,10 @@ ppc_elf_add_symbol_hook (bfd *abfd,
       *valp = sym->st_size;
     }
 
-  if ((ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
-       || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
+  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
       && (abfd->flags & DYNAMIC) == 0
       && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
+    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
 
   return TRUE;
 }
@@ -3845,7 +3961,8 @@ is_branch_reloc (enum elf_ppc_reloc_type r_type)
          || r_type == R_PPC_ADDR24
          || r_type == R_PPC_ADDR14
          || r_type == R_PPC_ADDR14_BRTAKEN
-         || r_type == R_PPC_ADDR14_BRNTAKEN);
+         || r_type == R_PPC_ADDR14_BRNTAKEN
+         || r_type == R_PPC_VLE_REL24);
 }
 
 static void
@@ -3921,6 +4038,7 @@ ppc_elf_check_relocs (bfd *abfd,
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
       int tls_type;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3953,6 +4071,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
       tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      ifunc = NULL;
       if (h == NULL && !htab->is_vxworks)
        {
          Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
@@ -3962,8 +4081,6 @@ ppc_elf_check_relocs (bfd *abfd,
 
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
-             struct plt_entry **ifunc;
-
              /* Set PLT_IFUNC flag for this sym, no GOT entry yet.  */
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
                                             PLT_IFUNC);
@@ -4197,21 +4314,20 @@ ppc_elf_check_relocs (bfd *abfd,
 #ifdef DEBUG
          fprintf (stderr, "Reloc requires a PLT entry\n");
 #endif
-         /* This symbol requires a procedure linkage table entry.  We
-            actually build the entry in finish_dynamic_symbol,
-            because this might be a case of linking PIC code without
-            linking in any dynamic objects, in which case we don't
-            need to generate a procedure linkage table after all.  */
-
+         /* This symbol requires a procedure linkage table entry.  */
          if (h == NULL)
            {
-             /* It does not make sense to have a procedure linkage
-                table entry for a local symbol.  */
-             info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
-                                     abfd, sec, rel->r_offset,
-                                     ppc_elf_howto_table[r_type]->name);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
+             if (ifunc == NULL)
+               {
+                 /* It does not make sense to have a procedure linkage
+                    table entry for a non-ifunc local symbol.  */
+                 info->callbacks->einfo
+                   (_("%P: %H: %s reloc against local symbol\n"),
+                    abfd, sec, rel->r_offset,
+                    ppc_elf_howto_table[r_type]->name);
+                 bfd_set_error (bfd_error_bad_value);
+                 return FALSE;
+               }
            }
          else
            {
@@ -4247,6 +4363,7 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          ppc_elf_tdata (abfd)->has_rel16 = 1;
          break;
 
@@ -4286,14 +4403,6 @@ ppc_elf_check_relocs (bfd *abfd,
            }
          if (h != NULL && h->type == STT_GNU_IFUNC)
            {
-             if (bfd_link_pic (info))
-               {
-                 info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
-                                         abfd, sec, rel->r_offset,
-                                         h->root.root.string);
-                 bfd_set_error (bfd_error_bad_value);
-                 return FALSE;
-               }
              h->needs_plt = 1;
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
@@ -4795,6 +4904,7 @@ ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
   insn = bfd_get_32 (output_bfd, loc);
   top5 = value & 0xf800;
   top5 = top5 << (split16_format == split16a_type ? 9 : 5);
+  insn &= (split16_format == split16a_type ? ~0x1f007ff : ~0x1f07ff);
   insn |= top5;
   insn |= value & 0x7ff;
   bfd_put_32 (output_bfd, insn, loc);
@@ -5138,6 +5248,7 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
                  tga->root.type = bfd_link_hash_indirect;
                  tga->root.u.i.link = &opt->root;
                  ppc_elf_copy_indirect_symbol (info, opt, tga);
+                 opt->forced_local = 0;
                  if (opt->dynindx != -1)
                    {
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
@@ -6397,7 +6508,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
       && htab->elf.dynamic_sections_created)
     {
       htab->glink_pltresolve = htab->glink->size;
-      /* Space for the branch table.  */
+      /* Space for the branch table.  ??? We don't need entries for
+        non-dynamic symbols in this table.  This case can arise with
+        static ifuncs or forced local ifuncs.  */
       htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
       /* Pad out to align the start of PLTresolve.  */
       htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
@@ -7604,7 +7717,9 @@ is_insn_ds_form (unsigned int insn)
 static bfd_boolean
 is_insn_dq_form (unsigned int insn)
 {
-  return (insn & (0x3f << 26)) == 56u << 26; /* lq */
+  return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+         || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+             && (insn & 3) == 1));
 }
 
 /* The RELOCATE_SECTION function is called by the ELF backend linker
@@ -8199,6 +8314,26 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
          if (ent != NULL)
            {
+             if (bfd_link_pic (info)
+                 && ent->sec != got2
+                 && htab->plt_type != PLT_NEW
+                 && (!htab->elf.dynamic_sections_created
+                     || h == NULL
+                     || h->dynindx == -1))
+               {
+                 /* Uh oh, we are going to create a pic glink stub
+                    for an ifunc (here for h == NULL and later in
+                    finish_dynamic_symbol for h != NULL), and
+                    apparently are using code compiled with
+                    -mbss-plt.  The difficulty is that -mbss-plt code
+                    gives no indication via a magic PLTREL24 addend
+                    whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or
+                    is pointing into a .got2 section (and how far
+                    into .got2).  */
+                   info->callbacks->einfo
+                     (_("%X%P: %H: unsupported bss-plt -fPIC ifunc %s\n"),
+                      input_bfd, input_section, rel->r_offset, sym_name);
+               }
              if (h == NULL && (ent->plt.offset & 1) == 0)
                {
                  Elf_Internal_Rela rela;
@@ -8539,15 +8674,28 @@ ppc_elf_relocate_section (bfd *output_bfd,
             at a symbol not in this object.  */
          if (unresolved_reloc)
            {
-             if (! (*info->callbacks->undefined_symbol) (info,
-                                                         h->root.root.string,
-                                                         input_bfd,
-                                                         input_section,
-                                                         rel->r_offset,
-                                                         TRUE))
-               return FALSE;
+             (*info->callbacks->undefined_symbol) (info,
+                                                   h->root.root.string,
+                                                   input_bfd,
+                                                   input_section,
+                                                   rel->r_offset,
+                                                   TRUE);
              goto copy_reloc;
            }
+         if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info))
+           {
+             /* @local on an ifunc does not really make sense since
+                the ifunc resolver can take you anywhere.  More
+                seriously, calls to ifuncs must go through a plt call
+                stub, and for pic the plt call stubs uses r30 to
+                access the PLT.  The problem is that a call that is
+                local won't have the +32k reloc addend trick marking
+                -fPIC code, so the linker won't know whether r30 is
+                _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section.  */
+             info->callbacks->einfo (_("%X%P: %H: @local call to ifunc %s\n"),
+                                     input_bfd, input_section, rel->r_offset,
+                                     h->root.root.string);
+           }
          break;
 
        case R_PPC_DTPREL16:
@@ -8605,6 +8753,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_REL16_LO:
        case R_PPC_REL16_HI:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
          break;
 
        case R_PPC_REL32:
@@ -8937,8 +9086,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_PLTREL24:
          if (h != NULL && ifunc == NULL)
            {
-             struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
-                                                   bfd_link_pic (info) ? addend : 0);
+             struct plt_entry *ent;
+
+             ent = find_plt_ent (&h->plt.plist, got2,
+                                 bfd_link_pic (info) ? addend : 0);
              if (ent == NULL
                  || htab->plt == NULL)
                {
@@ -9311,6 +9462,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC_ADDR16_HA:
        case R_PPC_REL16_HA:
+       case R_PPC_REL16DX_HA:
        case R_PPC_SECTOFF_HA:
        case R_PPC_TPREL16_HA:
        case R_PPC_DTPREL16_HA:
@@ -9369,10 +9521,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
              mask = 15;
            else
              break;
-           lobit = mask & (relocation + addend);
+           relocation += addend;
+           addend = insn & mask;
+           lobit = mask & relocation;
            if (lobit != 0)
              {
-               addend -= lobit;
+               relocation ^= lobit;
                info->callbacks->einfo
                  (_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
                   input_bfd, input_section, rel->r_offset,
@@ -9380,7 +9534,6 @@ ppc_elf_relocate_section (bfd *output_bfd,
                bfd_set_error (bfd_error_bad_value);
                ret = FALSE;
              }
-           addend += insn & mask;
          }
          break;
        }
@@ -9439,8 +9592,30 @@ ppc_elf_relocate_section (bfd *output_bfd,
            }
        }
 
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-                                   rel->r_offset, relocation, addend);
+      if (r_type == R_PPC_REL16DX_HA)
+       {
+         /* Split field reloc isn't handled by _bfd_final_link_relocate.  */
+         if (rel->r_offset + 4 > input_section->size)
+           r = bfd_reloc_outofrange;
+         else
+           {
+             unsigned int insn;
+
+             relocation += addend;
+             relocation -= (rel->r_offset
+                            + input_section->output_offset
+                            + input_section->output_section->vma);
+             relocation >>= 16;
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             insn &= ~0x1fffc1;
+             insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+             bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+             r = bfd_reloc_ok;
+           }
+       }
+      else
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                     rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
        {
@@ -9454,13 +9629,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
                       && (h->root.type == bfd_link_hash_undefweak
                           || h->root.type == bfd_link_hash_undefined)
                       && is_branch_reloc (r_type)))
-               {
-                 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;
-               }
+               info->callbacks->reloc_overflow
+                 (info, (h ? &h->root : NULL), sym_name, howto->name,
+                  rel->r_addend, input_bfd, input_section, rel->r_offset);
            }
          else
            {
@@ -10701,7 +10872,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_action_discarded           ppc_elf_action_discarded
 #define elf_backend_init_index_section         _bfd_elf_init_1_index_section
 #define elf_backend_lookup_section_flags_hook  ppc_elf_lookup_section_flags
-#define elf_backend_section_processing         ppc_elf_section_processing
 
 #include "elf32-target.h"
 
This page took 0.046345 seconds and 4 git commands to generate.