* reloc.c: Add PPC and PPC64 TLS relocs.
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 8e1935dfb9d1a941dcd3d97c18bfd54e9c66b7d1..26340066482ed79dc038b3cebabc219de08cab0e 100644 (file)
@@ -1,5 +1,5 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
 
@@ -27,18 +27,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
-#include "elf/ppc.h"
+#include "elf/ppc64.h"
 #include "elf64-ppc.h"
 
-#define USE_RELA               /* we want RELA relocations, not REL.  */
-
-
 static void ppc_howto_init
   PARAMS ((void));
 static reloc_howto_type *ppc64_elf_reloc_type_lookup
   PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
 static void ppc64_elf_info_to_howto
-  PARAMS ((bfd *abfd, arelent *cache_ptr, Elf64_Internal_Rela *dst));
+  PARAMS ((bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst));
 static bfd_reloc_status_type ppc64_elf_ha_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type ppc64_elf_brtaken_reloc
@@ -55,14 +52,12 @@ static bfd_reloc_status_type ppc64_elf_toc64_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
 static bfd_reloc_status_type ppc64_elf_unhandled_reloc
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static void ppc64_elf_get_symbol_info
-  PARAMS ((bfd *, asymbol *, symbol_info *));
-static boolean ppc64_elf_set_private_flags
-  PARAMS ((bfd *, flagword));
-static boolean ppc64_elf_merge_private_bfd_data
+static bfd_boolean ppc64_elf_object_p
+  PARAMS ((bfd *));
+static bfd_boolean ppc64_elf_merge_private_bfd_data
   PARAMS ((bfd *, bfd *));
-static boolean ppc64_elf_section_from_shdr
-  PARAMS ((bfd *, Elf64_Internal_Shdr *, const char *));
+static bfd_boolean ppc64_elf_new_section_hook
+  PARAMS ((bfd *, asection *));
 
 
 /* The name of the dynamic interpreter.  This is put in the .interp
@@ -76,7 +71,11 @@ static boolean ppc64_elf_section_from_shdr
 #define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE
 
 /* TOC base pointers offset from start of TOC.  */
-#define TOC_BASE_OFF (0x8000)
+#define TOC_BASE_OFF   0x8000
+
+/* Offset of tp and dtp pointers from start of TLS block.  */
+#define TP_OFFSET      0x7000
+#define DTP_OFFSET     0x8000
 
 /* .plt call stub instructions.  */
 #define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha     */
@@ -125,14 +124,15 @@ static boolean ppc64_elf_section_from_shdr
 /* Since .opd is an array of descriptors and each entry will end up
    with identical R_PPC64_RELATIVE relocs, there is really no need to
    propagate .opd relocs;  The dynamic linker should be taught to
-   relocate .opd without reloc entries.  FIXME: .opd should be trimmed
-   of unused values.  */
+   relocate .opd without reloc entries.  */
 #ifndef NO_OPD_RELOCS
 #define NO_OPD_RELOCS 0
 #endif
 \f
+#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1)
+
 /* Relocation HOWTO's.  */
-static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC_max];
+static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC64_max];
 
 static reloc_howto_type ppc64_elf_howto_raw[] = {
   /* This reloc does nothing.  */
@@ -140,30 +140,30 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
+        complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_NONE",        /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* A standard 32 bit relocation.  */
   HOWTO (R_PPC64_ADDR32,       /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR32",      /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* An absolute 26 bit branch; the lower two bits must be zero.
      FIXME: we don't check that, we just clear them.  */
@@ -171,60 +171,60 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR24",      /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        false),                /* pcrel_offset */
+        0x03fffffc,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* A standard 16 bit relocation.  */
   HOWTO (R_PPC64_ADDR16,       /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16",      /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* A 16 bit relocation without overflow.  */
   HOWTO (R_PPC64_ADDR16_LO,    /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_LO",   /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 of an address.  */
   HOWTO (R_PPC64_ADDR16_HI,    /* type */
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_HI",   /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Bits 16-31 of an address, plus 1 if the contents of the low 16
      bits, treated as a signed number, is negative.  */
@@ -232,15 +232,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HA",   /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* An absolute 16 bit branch; the lower two bits must be zero.
      FIXME: we don't check that, we just clear them.  */
@@ -248,15 +248,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR14",      /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* An absolute 16 bit branch, for which bit 10 should be set to
      indicate that the branch is expected to be taken.  The lower two
@@ -265,15 +265,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRTAKEN",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* An absolute 16 bit branch, for which bit 10 should be set to
      indicate that the branch is not expected to be taken.  The lower
@@ -282,45 +282,45 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_ADDR14_BRNTAKEN",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* A relative 26 bit branch; the lower two bits must be zero.  */
   HOWTO (R_PPC64_REL24,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL24",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0x3fffffc,             /* dst_mask */
-        true),                 /* pcrel_offset */
+        0x03fffffc,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* A relative 16 bit branch; the lower two bits must be zero.  */
   HOWTO (R_PPC64_REL14,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL14",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        true),                 /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is expected to be taken.  The lower two bits must be
@@ -329,15 +329,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_REL14_BRTAKEN", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        true),                 /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* A relative 16 bit branch.  Bit 10 should be set to indicate that
      the branch is not expected to be taken.  The lower two bits must
@@ -346,15 +346,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_brtaken_reloc, /* special_function */
         "R_PPC64_REL14_BRNTAKEN",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xfffc,                /* dst_mask */
-        true),                 /* pcrel_offset */
+        0x0000fffc,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16, but referring to the GOT table entry for the
      symbol.  */
@@ -362,15 +362,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_LO, but referring to the GOT table entry for
      the symbol.  */
@@ -378,15 +378,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_LO",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_HI, but referring to the GOT table entry for
      the symbol.  */
@@ -394,15 +394,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_HI",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_HA, but referring to the GOT table entry for
      the symbol.  */
@@ -410,15 +410,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_HA",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* This is used only by the dynamic linker.  The symbol should exist
      both in the object being run and in some shared library.  The
@@ -427,17 +427,17 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
      run has to have the data at some particular address.  */
   HOWTO (R_PPC64_COPY,         /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
-        32,                    /* bitsize */
-        false,                 /* pc_relative */
+        0,                     /* this one is variable size */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield, /* complain_on_overflow */
-        ppc64_elf_unhandled_reloc,  /* special_function */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_COPY",        /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR64, but used when setting global offset table
      entries.  */
@@ -445,15 +445,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc,  /* special_function */
         "R_PPC64_GLOB_DAT",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* Created by the link editor.  Marks a procedure linkage table
      entry for a symbol.  */
@@ -461,15 +461,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_JMP_SLOT",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Used only by the dynamic linker.  When the object is run, this
      doubleword64 is set to the load address of the object, plus the
@@ -478,76 +478,76 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_RELATIVE",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR32, but may be unaligned.  */
   HOWTO (R_PPC64_UADDR32,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_UADDR32",     /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16, but may be unaligned.  */
   HOWTO (R_PPC64_UADDR16,      /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_UADDR16",     /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 32-bit PC relative.  */
   HOWTO (R_PPC64_REL32,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         /* FIXME: Verify.  Was complain_overflow_bitfield.  */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL32",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        true),                 /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
 
   /* 32-bit relocation to the symbol's procedure linkage table.  */
   HOWTO (R_PPC64_PLT32,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT32",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* 32-bit PC relative relocation to the symbol's procedure linkage table.
      FIXME: R_PPC64_PLTREL32 not supported.  */
@@ -555,15 +555,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_PLTREL32",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        true),                 /* pcrel_offset */
+        0xffffffff,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_LO, but referring to the PLT table entry for
      the symbol.  */
@@ -571,15 +571,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_LO",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_HI, but referring to the PLT table entry for
      the symbol.  */
@@ -587,15 +587,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_HI",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_HA, but referring to the PLT table entry for
      the symbol.  */
@@ -603,91 +603,90 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_HA",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16-bit section relative relocation.  */
   HOWTO (R_PPC64_SECTOFF,      /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF",     /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_SECTOFF, but no overflow warning.  */
   HOWTO (R_PPC64_SECTOFF_LO,   /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_LO",  /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16-bit upper half section relative relocation.  */
   HOWTO (R_PPC64_SECTOFF_HI,   /* type */
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_HI",  /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16-bit upper half adjusted section relative relocation.  */
   HOWTO (R_PPC64_SECTOFF_HA,   /* type */
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_sectoff_ha_reloc, /* special_function */
         "R_PPC64_SECTOFF_HA",  /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
-  /* Like R_PPC64_REL24 without touching the two least significant
-     bits.  Should have been named R_PPC64_REL30!  */
-  HOWTO (R_PPC64_ADDR30,       /* type */
+  /* Like R_PPC64_REL24 without touching the two least significant bits.  */
+  HOWTO (R_PPC64_REL30,                /* type */
         2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         30,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_PPC64_ADDR30",      /* name */
-        false,                 /* partial_inplace */
+        "R_PPC64_REL30",       /* name */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffffffc,            /* dst_mask */
-        true),                 /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
 
   /* Relocs in the 64-bit PowerPC ELF ABI, not in the 32-bit ABI.  */
 
@@ -696,30 +695,30 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR64",      /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* The bits 32-47 of an address.  */
   HOWTO (R_PPC64_ADDR16_HIGHER,        /* type */
         32,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_HIGHER", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* The bits 32-47 of an address, plus 1 if the contents of the low
      16 bits, treated as a signed number, is negative.  */
@@ -727,30 +726,30 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         32,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HIGHERA", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* The bits 48-63 of an address.  */
   HOWTO (R_PPC64_ADDR16_HIGHEST,/* type */
         48,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_HIGHEST", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* The bits 48-63 of an address, plus 1 if the contents of the low
      16 bits, treated as a signed number, is negative.  */
@@ -758,60 +757,60 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         48,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_ha_reloc,    /* special_function */
         "R_PPC64_ADDR16_HIGHESTA", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like ADDR64, but may be unaligned.  */
   HOWTO (R_PPC64_UADDR64,      /* type */
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_UADDR64",     /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* 64-bit relative relocation.  */
   HOWTO (R_PPC64_REL64,                /* type */
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_REL64",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        true),                 /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* 64-bit relocation to the symbol's procedure linkage table.  */
   HOWTO (R_PPC64_PLT64,                /* type */
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT64",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* 64-bit PC relative relocation to the symbol's procedure linkage
      table.  */
@@ -820,15 +819,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        true,                  /* pc_relative */
+        TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTREL64",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        true),                 /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        TRUE),                 /* pcrel_offset */
 
   /* 16 bit TOC-relative relocation.  */
 
@@ -837,15 +836,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16",       /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16 bit TOC-relative relocation without overflow.  */
 
@@ -854,15 +853,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_LO",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16 bit TOC-relative relocation, high 16 bits.  */
 
@@ -871,15 +870,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_HI",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 16 bit TOC-relative relocation, high 16 bits, plus 1 if the
      contents of the low 16 bits, treated as a signed number, is
@@ -890,15 +889,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_toc_ha_reloc, /* special_function */
         "R_PPC64_TOC16_HA",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* 64-bit relocation; insert value of TOC base (.TOC.).  */
 
@@ -907,15 +906,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
         64,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_toc64_reloc, /* special_function */
         "R_PPC64_TOC",         /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0xffffffffffffffff,    /* dst_mask */
-        false),                /* pcrel_offset */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_GOT16, but also informs the link editor that the
      value to relocate may (!) refer to a PLT entry which the link
@@ -930,15 +929,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLTGOT16, but without overflow.  */
   /* FIXME: R_PPC64_PLTGOT16_LO not implemented.  */
@@ -946,15 +945,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_LO", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address.  */
   /* FIXME: R_PPC64_PLTGOT16_HI not implemented.  */
@@ -962,15 +961,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_HI", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address, plus
      1 if the contents of the low 16 bits, treated as a signed number,
@@ -980,150 +979,150 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         16,                    /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_HA", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16, but for instructions with a DS field.  */
   HOWTO (R_PPC64_ADDR16_DS,    /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_DS",   /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_ADDR16_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_ADDR16_LO_DS, /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC64_ADDR16_LO_DS",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_GOT16, but for instructions with a DS field.  */
   HOWTO (R_PPC64_GOT16_DS,     /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_DS",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_GOT16_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_GOT16_LO_DS,  /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_GOT16_LO_DS", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLT16_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_PLT16_LO_DS,  /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLT16_LO_DS", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_SECTOFF, but for instructions with a DS field.  */
   HOWTO (R_PPC64_SECTOFF_DS,   /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_DS",  /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_sectoff_reloc, /* special_function */
         "R_PPC64_SECTOFF_LO_DS",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_TOC16, but for instructions with a DS field.  */
   HOWTO (R_PPC64_TOC16_DS,     /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_DS",    /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_TOC16_LO, but for instructions with a DS field.  */
   HOWTO (R_PPC64_TOC16_LO_DS,  /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_toc_reloc,   /* special_function */
         "R_PPC64_TOC16_LO_DS", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLTGOT16, but for instructions with a DS field.  */
   /* FIXME: R_PPC64_PLTGOT16_DS not implemented.  */
@@ -1131,15 +1130,15 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_DS", /* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
   /* Like R_PPC64_PLTGOT16_LO, but for instructions with a DS field.  */
   /* FIXME: R_PPC64_PLTGOT16_LO not implemented.  */
@@ -1147,236 +1146,926 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        false,                 /* pc_relative */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         ppc64_elf_unhandled_reloc, /* special_function */
         "R_PPC64_PLTGOT16_LO_DS",/* name */
-        false,                 /* partial_inplace */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xfffc,                /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
-  /* GNU extension to record C++ vtable hierarchy.  */
-  HOWTO (R_PPC64_GNU_VTINHERIT,        /* type */
+  /* Marker reloc for TLS.  */
+  HOWTO (R_PPC64_TLS,
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        false,                 /* pc_relative */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_PPC64_GNU_VTINHERIT", /* name */
-        false,                 /* partial_inplace */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TLS",         /* name */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        false),                /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
 
-  /* GNU extension to record C++ vtable member usage.  */
-  HOWTO (R_PPC64_GNU_VTENTRY,  /* type */
+  /* Computes the load module index of the load module that contains the
+     definition of its TLS sym.  */
+  HOWTO (R_PPC64_DTPMOD64,
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
-        0,                     /* bitsize */
-        false,                 /* pc_relative */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
-        NULL,                  /* special_function */
-        "R_PPC64_GNU_VTENTRY", /* name */
-        false,                 /* partial_inplace */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPMOD64",    /* name */
+        FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
-        0,                     /* dst_mask */
-        false),                /* pcrel_offset */
-};
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-\f
-/* Initialize the ppc64_elf_howto_table, so that linear accesses can
-   be done.  */
+  /* Computes a dtv-relative displacement, the difference between the value
+     of sym+add and the base address of the thread-local storage block that
+     contains the definition of sym, minus 0x8000.  */
+  HOWTO (R_PPC64_DTPREL64,
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL64",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-static void
-ppc_howto_init ()
-{
-  unsigned int i, type;
+  /* A 16 bit dtprel reloc.  */
+  HOWTO (R_PPC64_DTPREL16,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  for (i = 0;
-       i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]);
-       i++)
-    {
-      type = ppc64_elf_howto_raw[i].type;
-      BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
-                         / sizeof (ppc64_elf_howto_table[0])));
-      ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i];
-    }
-}
+  /* Like DTPREL16, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_LO,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_LO", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-static reloc_howto_type *
-ppc64_elf_reloc_type_lookup (abfd, code)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     bfd_reloc_code_real_type code;
-{
-  enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
+  /* Like DTPREL16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HI", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
-    /* Initialize howto table if needed.  */
-    ppc_howto_init ();
+  /* Like DTPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  switch ((int) code)
-    {
-    default:
-      return (reloc_howto_type *) NULL;
+  /* Like DTPREL16_HI, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHER,
+        32,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HIGHER", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-    case BFD_RELOC_NONE:                ppc_reloc = R_PPC64_NONE;
-      break;
-    case BFD_RELOC_32:                  ppc_reloc = R_PPC64_ADDR32;
-      break;
-    case BFD_RELOC_PPC_BA26:            ppc_reloc = R_PPC64_ADDR24;
-      break;
-    case BFD_RELOC_16:                  ppc_reloc = R_PPC64_ADDR16;
-      break;
-    case BFD_RELOC_LO16:                ppc_reloc = R_PPC64_ADDR16_LO;
-      break;
-    case BFD_RELOC_HI16:                ppc_reloc = R_PPC64_ADDR16_HI;
-      break;
-    case BFD_RELOC_HI16_S:              ppc_reloc = R_PPC64_ADDR16_HA;
-      break;
-    case BFD_RELOC_PPC_BA16:            ppc_reloc = R_PPC64_ADDR14;
-      break;
-    case BFD_RELOC_PPC_BA16_BRTAKEN:    ppc_reloc = R_PPC64_ADDR14_BRTAKEN;
-      break;
-    case BFD_RELOC_PPC_BA16_BRNTAKEN:   ppc_reloc = R_PPC64_ADDR14_BRNTAKEN;
-      break;
-    case BFD_RELOC_PPC_B26:             ppc_reloc = R_PPC64_REL24;
-      break;
-    case BFD_RELOC_PPC_B16:             ppc_reloc = R_PPC64_REL14;
-      break;
-    case BFD_RELOC_PPC_B16_BRTAKEN:     ppc_reloc = R_PPC64_REL14_BRTAKEN;
-      break;
-    case BFD_RELOC_PPC_B16_BRNTAKEN:    ppc_reloc = R_PPC64_REL14_BRNTAKEN;
-      break;
-    case BFD_RELOC_16_GOTOFF:           ppc_reloc = R_PPC64_GOT16;
-      break;
-    case BFD_RELOC_LO16_GOTOFF:                 ppc_reloc = R_PPC64_GOT16_LO;
-      break;
-    case BFD_RELOC_HI16_GOTOFF:                 ppc_reloc = R_PPC64_GOT16_HI;
-      break;
-    case BFD_RELOC_HI16_S_GOTOFF:       ppc_reloc = R_PPC64_GOT16_HA;
-      break;
-    case BFD_RELOC_PPC_COPY:            ppc_reloc = R_PPC64_COPY;
-      break;
-    case BFD_RELOC_PPC_GLOB_DAT:        ppc_reloc = R_PPC64_GLOB_DAT;
-      break;
-    case BFD_RELOC_32_PCREL:            ppc_reloc = R_PPC64_REL32;
-      break;
-    case BFD_RELOC_32_PLTOFF:           ppc_reloc = R_PPC64_PLT32;
-      break;
-    case BFD_RELOC_32_PLT_PCREL:        ppc_reloc = R_PPC64_PLTREL32;
-      break;
-    case BFD_RELOC_LO16_PLTOFF:                 ppc_reloc = R_PPC64_PLT16_LO;
-      break;
-    case BFD_RELOC_HI16_PLTOFF:                 ppc_reloc = R_PPC64_PLT16_HI;
-      break;
-    case BFD_RELOC_HI16_S_PLTOFF:       ppc_reloc = R_PPC64_PLT16_HA;
-      break;
-    case BFD_RELOC_16_BASEREL:          ppc_reloc = R_PPC64_SECTOFF;
-      break;
-    case BFD_RELOC_LO16_BASEREL:        ppc_reloc = R_PPC64_SECTOFF_LO;
-      break;
-    case BFD_RELOC_HI16_BASEREL:        ppc_reloc = R_PPC64_SECTOFF_HI;
-      break;
-    case BFD_RELOC_HI16_S_BASEREL:      ppc_reloc = R_PPC64_SECTOFF_HA;
-      break;
-    case BFD_RELOC_CTOR:                ppc_reloc = R_PPC64_ADDR64;
-      break;
-    case BFD_RELOC_64:                  ppc_reloc = R_PPC64_ADDR64;
-      break;
-    case BFD_RELOC_PPC64_HIGHER:        ppc_reloc = R_PPC64_ADDR16_HIGHER;
-      break;
-    case BFD_RELOC_PPC64_HIGHER_S:      ppc_reloc = R_PPC64_ADDR16_HIGHERA;
-      break;
-    case BFD_RELOC_PPC64_HIGHEST:       ppc_reloc = R_PPC64_ADDR16_HIGHEST;
-      break;
-    case BFD_RELOC_PPC64_HIGHEST_S:     ppc_reloc = R_PPC64_ADDR16_HIGHESTA;
-      break;
-    case BFD_RELOC_64_PCREL:            ppc_reloc = R_PPC64_REL64;
-      break;
-    case BFD_RELOC_64_PLTOFF:           ppc_reloc = R_PPC64_PLT64;
-      break;
-    case BFD_RELOC_64_PLT_PCREL:        ppc_reloc = R_PPC64_PLTREL64;
-      break;
-    case BFD_RELOC_PPC_TOC16:           ppc_reloc = R_PPC64_TOC16;
-      break;
-    case BFD_RELOC_PPC64_TOC16_LO:      ppc_reloc = R_PPC64_TOC16_LO;
-      break;
-    case BFD_RELOC_PPC64_TOC16_HI:      ppc_reloc = R_PPC64_TOC16_HI;
-      break;
-    case BFD_RELOC_PPC64_TOC16_HA:      ppc_reloc = R_PPC64_TOC16_HA;
-      break;
-    case BFD_RELOC_PPC64_TOC:           ppc_reloc = R_PPC64_TOC;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16:      ppc_reloc = R_PPC64_PLTGOT16;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16_LO:   ppc_reloc = R_PPC64_PLTGOT16_LO;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16_HI:   ppc_reloc = R_PPC64_PLTGOT16_HI;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16_HA:   ppc_reloc = R_PPC64_PLTGOT16_HA;
-      break;
-    case BFD_RELOC_PPC64_ADDR16_DS:      ppc_reloc = R_PPC64_ADDR16_DS;
-      break;
-    case BFD_RELOC_PPC64_ADDR16_LO_DS:   ppc_reloc = R_PPC64_ADDR16_LO_DS;
-      break;
-    case BFD_RELOC_PPC64_GOT16_DS:       ppc_reloc = R_PPC64_GOT16_DS;
-      break;
-    case BFD_RELOC_PPC64_GOT16_LO_DS:    ppc_reloc = R_PPC64_GOT16_LO_DS;
-      break;
-    case BFD_RELOC_PPC64_PLT16_LO_DS:    ppc_reloc = R_PPC64_PLT16_LO_DS;
-      break;
-    case BFD_RELOC_PPC64_SECTOFF_DS:     ppc_reloc = R_PPC64_SECTOFF_DS;
-      break;
-    case BFD_RELOC_PPC64_SECTOFF_LO_DS:  ppc_reloc = R_PPC64_SECTOFF_LO_DS;
-      break;
-    case BFD_RELOC_PPC64_TOC16_DS:       ppc_reloc = R_PPC64_TOC16_DS;
-      break;
-    case BFD_RELOC_PPC64_TOC16_LO_DS:    ppc_reloc = R_PPC64_TOC16_LO_DS;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16_DS:    ppc_reloc = R_PPC64_PLTGOT16_DS;
-      break;
-    case BFD_RELOC_PPC64_PLTGOT16_LO_DS: ppc_reloc = R_PPC64_PLTGOT16_LO_DS;
-      break;
-    case BFD_RELOC_VTABLE_INHERIT:      ppc_reloc = R_PPC64_GNU_VTINHERIT;
-      break;
-    case BFD_RELOC_VTABLE_ENTRY:        ppc_reloc = R_PPC64_GNU_VTENTRY;
-      break;
-    }
+  /* Like DTPREL16_HIGHER, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHERA,
+        32,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HIGHERA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  return ppc64_elf_howto_table[(int) ppc_reloc];
-};
+  /* Like DTPREL16_HIGHER, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHEST,
+        48,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HIGHEST", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-/* Set the howto pointer for a PowerPC ELF reloc.  */
+  /* Like DTPREL16_HIGHEST, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_DTPREL16_HIGHESTA,
+        48,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_HIGHESTA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-static void
-ppc64_elf_info_to_howto (abfd, cache_ptr, dst)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     arelent *cache_ptr;
-     Elf64_Internal_Rela *dst;
-{
-  unsigned int type;
+  /* Like DTPREL16, but for insns with a DS field.  */
+  HOWTO (R_PPC64_DTPREL16_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  /* Initialize howto table if needed.  */
-  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
-    ppc_howto_init ();
+  /* Like DTPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_DTPREL16_LO_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_DTPREL16_LO_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-  type = ELF64_R_TYPE (dst->r_info);
-  BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
-                     / sizeof (ppc64_elf_howto_table[0])));
-  cache_ptr->howto = ppc64_elf_howto_table[type];
-}
+  /* Computes a tp-relative displacement, the difference between the value of
+     sym+add and the value of the thread pointer (r13).  */
+  HOWTO (R_PPC64_TPREL64,
+        0,                     /* rightshift */
+        4,                     /* size (0 = byte, 1 = short, 2 = long) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL64",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-/* Handle the R_PPC_ADDR16_HA and similar relocs.  */
+  /* A 16 bit tprel reloc.  */
+  HOWTO (R_PPC64_TPREL16,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
 
-static bfd_reloc_status_type
-ppc64_elf_ha_reloc (abfd, reloc_entry, symbol, data,
-                   input_section, output_bfd, error_message)
-     bfd *abfd;
+  /* Like TPREL16, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_LO,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_LO",  /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HI",  /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HA",  /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_HI, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHER,
+        32,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HIGHER",      /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_HIGHER, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHERA,
+        32,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HIGHERA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_HIGHER, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHEST,
+        48,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HIGHEST", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_HIGHEST, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_TPREL16_HIGHESTA,
+        48,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_HIGHESTA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16, but for insns with a DS field.  */
+  HOWTO (R_PPC64_TPREL16_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_DS",  /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like TPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_TPREL16_LO_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_TPREL16_LO_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
+     with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
+     to the first entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TLSGD16,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSGD16", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSGD16, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_LO,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSGD16_LO", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSGD16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSGD16_HI", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSGD16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSGD16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSGD16_HA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Allocates two contiguous entries in the GOT to hold a tls_index structure,
+     with values (sym+add)@dtpmod and zero, and computes the offset to the
+     first entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TLSLD16,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSLD16", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSLD16, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_LO,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSLD16_LO", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSLD16_LO, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSLD16_HI", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TLSLD16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TLSLD16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TLSLD16_HA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
+     the offset to the entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_DTPREL16_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_DTPREL16_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_DTPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_LO_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_DTPREL16_LO_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xfffc,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_DTPREL16_LO_DS, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_DTPREL16_HI", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_DTPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_DTPREL16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_DTPREL16_HA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
+     offset to the entry relative to the TOC base (r2).  */
+  HOWTO (R_PPC64_GOT_TPREL16_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TPREL16_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TPREL16_DS, but no overflow.  */
+  HOWTO (R_PPC64_GOT_TPREL16_LO_DS,
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TPREL16_LO_DS", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TPREL16_LO_DS, but next higher group of 16 bits.  */
+  HOWTO (R_PPC64_GOT_TPREL16_HI,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TPREL16_HI", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Like GOT_TPREL16_HI, but adjust for low 16 bits.  */
+  HOWTO (R_PPC64_GOT_TPREL16_HA,
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_GOT_TPREL16_HA", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable hierarchy.  */
+  HOWTO (R_PPC64_GNU_VTINHERIT,        /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_PPC64_GNU_VTINHERIT", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable member usage.  */
+  HOWTO (R_PPC64_GNU_VTENTRY,  /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_PPC64_GNU_VTENTRY", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+};
+
+\f
+/* Initialize the ppc64_elf_howto_table, so that linear accesses can
+   be done.  */
+
+static void
+ppc_howto_init ()
+{
+  unsigned int i, type;
+
+  for (i = 0;
+       i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]);
+       i++)
+    {
+      type = ppc64_elf_howto_raw[i].type;
+      BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
+                         / sizeof (ppc64_elf_howto_table[0])));
+      ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i];
+    }
+}
+
+static reloc_howto_type *
+ppc64_elf_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  enum elf_ppc64_reloc_type r = R_PPC64_NONE;
+
+  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
+    /* Initialize howto table if needed.  */
+    ppc_howto_init ();
+
+  switch ((int) code)
+    {
+    default:
+      return (reloc_howto_type *) NULL;
+
+    case BFD_RELOC_NONE:                       r = R_PPC64_NONE;
+      break;
+    case BFD_RELOC_32:                         r = R_PPC64_ADDR32;
+      break;
+    case BFD_RELOC_PPC_BA26:                   r = R_PPC64_ADDR24;
+      break;
+    case BFD_RELOC_16:                         r = R_PPC64_ADDR16;
+      break;
+    case BFD_RELOC_LO16:                       r = R_PPC64_ADDR16_LO;
+      break;
+    case BFD_RELOC_HI16:                       r = R_PPC64_ADDR16_HI;
+      break;
+    case BFD_RELOC_HI16_S:                     r = R_PPC64_ADDR16_HA;
+      break;
+    case BFD_RELOC_PPC_BA16:                   r = R_PPC64_ADDR14;
+      break;
+    case BFD_RELOC_PPC_BA16_BRTAKEN:           r = R_PPC64_ADDR14_BRTAKEN;
+      break;
+    case BFD_RELOC_PPC_BA16_BRNTAKEN:          r = R_PPC64_ADDR14_BRNTAKEN;
+      break;
+    case BFD_RELOC_PPC_B26:                    r = R_PPC64_REL24;
+      break;
+    case BFD_RELOC_PPC_B16:                    r = R_PPC64_REL14;
+      break;
+    case BFD_RELOC_PPC_B16_BRTAKEN:            r = R_PPC64_REL14_BRTAKEN;
+      break;
+    case BFD_RELOC_PPC_B16_BRNTAKEN:           r = R_PPC64_REL14_BRNTAKEN;
+      break;
+    case BFD_RELOC_16_GOTOFF:                  r = R_PPC64_GOT16;
+      break;
+    case BFD_RELOC_LO16_GOTOFF:                        r = R_PPC64_GOT16_LO;
+      break;
+    case BFD_RELOC_HI16_GOTOFF:                        r = R_PPC64_GOT16_HI;
+      break;
+    case BFD_RELOC_HI16_S_GOTOFF:              r = R_PPC64_GOT16_HA;
+      break;
+    case BFD_RELOC_PPC_COPY:                   r = R_PPC64_COPY;
+      break;
+    case BFD_RELOC_PPC_GLOB_DAT:               r = R_PPC64_GLOB_DAT;
+      break;
+    case BFD_RELOC_32_PCREL:                   r = R_PPC64_REL32;
+      break;
+    case BFD_RELOC_32_PLTOFF:                  r = R_PPC64_PLT32;
+      break;
+    case BFD_RELOC_32_PLT_PCREL:               r = R_PPC64_PLTREL32;
+      break;
+    case BFD_RELOC_LO16_PLTOFF:                        r = R_PPC64_PLT16_LO;
+      break;
+    case BFD_RELOC_HI16_PLTOFF:                        r = R_PPC64_PLT16_HI;
+      break;
+    case BFD_RELOC_HI16_S_PLTOFF:              r = R_PPC64_PLT16_HA;
+      break;
+    case BFD_RELOC_16_BASEREL:                 r = R_PPC64_SECTOFF;
+      break;
+    case BFD_RELOC_LO16_BASEREL:               r = R_PPC64_SECTOFF_LO;
+      break;
+    case BFD_RELOC_HI16_BASEREL:               r = R_PPC64_SECTOFF_HI;
+      break;
+    case BFD_RELOC_HI16_S_BASEREL:             r = R_PPC64_SECTOFF_HA;
+      break;
+    case BFD_RELOC_CTOR:                       r = R_PPC64_ADDR64;
+      break;
+    case BFD_RELOC_64:                         r = R_PPC64_ADDR64;
+      break;
+    case BFD_RELOC_PPC64_HIGHER:               r = R_PPC64_ADDR16_HIGHER;
+      break;
+    case BFD_RELOC_PPC64_HIGHER_S:             r = R_PPC64_ADDR16_HIGHERA;
+      break;
+    case BFD_RELOC_PPC64_HIGHEST:              r = R_PPC64_ADDR16_HIGHEST;
+      break;
+    case BFD_RELOC_PPC64_HIGHEST_S:            r = R_PPC64_ADDR16_HIGHESTA;
+      break;
+    case BFD_RELOC_64_PCREL:                   r = R_PPC64_REL64;
+      break;
+    case BFD_RELOC_64_PLTOFF:                  r = R_PPC64_PLT64;
+      break;
+    case BFD_RELOC_64_PLT_PCREL:               r = R_PPC64_PLTREL64;
+      break;
+    case BFD_RELOC_PPC_TOC16:                  r = R_PPC64_TOC16;
+      break;
+    case BFD_RELOC_PPC64_TOC16_LO:             r = R_PPC64_TOC16_LO;
+      break;
+    case BFD_RELOC_PPC64_TOC16_HI:             r = R_PPC64_TOC16_HI;
+      break;
+    case BFD_RELOC_PPC64_TOC16_HA:             r = R_PPC64_TOC16_HA;
+      break;
+    case BFD_RELOC_PPC64_TOC:                  r = R_PPC64_TOC;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16:             r = R_PPC64_PLTGOT16;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16_LO:          r = R_PPC64_PLTGOT16_LO;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16_HI:          r = R_PPC64_PLTGOT16_HI;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16_HA:          r = R_PPC64_PLTGOT16_HA;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_DS:            r = R_PPC64_ADDR16_DS;
+      break;
+    case BFD_RELOC_PPC64_ADDR16_LO_DS:         r = R_PPC64_ADDR16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_GOT16_DS:             r = R_PPC64_GOT16_DS;
+      break;
+    case BFD_RELOC_PPC64_GOT16_LO_DS:          r = R_PPC64_GOT16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_PLT16_LO_DS:          r = R_PPC64_PLT16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_SECTOFF_DS:           r = R_PPC64_SECTOFF_DS;
+      break;
+    case BFD_RELOC_PPC64_SECTOFF_LO_DS:                r = R_PPC64_SECTOFF_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_TOC16_DS:             r = R_PPC64_TOC16_DS;
+      break;
+    case BFD_RELOC_PPC64_TOC16_LO_DS:          r = R_PPC64_TOC16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16_DS:          r = R_PPC64_PLTGOT16_DS;
+      break;
+    case BFD_RELOC_PPC64_PLTGOT16_LO_DS:       r = R_PPC64_PLTGOT16_LO_DS;
+      break;
+    case BFD_RELOC_PPC_TLS:                    r = R_PPC64_TLS;
+      break;
+    case BFD_RELOC_PPC_DTPMOD:                 r = R_PPC64_DTPMOD64;
+      break;
+    case BFD_RELOC_PPC_TPREL16:                        r = R_PPC64_TPREL16;
+      break;
+    case BFD_RELOC_PPC_TPREL16_LO:             r = R_PPC64_TPREL16_LO;
+      break;
+    case BFD_RELOC_PPC_TPREL16_HI:             r = R_PPC64_TPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_TPREL16_HA:             r = R_PPC64_TPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_TPREL:                  r = R_PPC64_TPREL64;
+      break;
+    case BFD_RELOC_PPC_DTPREL16:               r = R_PPC64_DTPREL16;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_LO:            r = R_PPC64_DTPREL16_LO;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_HI:            r = R_PPC64_DTPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_DTPREL16_HA:            r = R_PPC64_DTPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_DTPREL:                 r = R_PPC64_DTPREL64;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16:            r = R_PPC64_GOT_TLSGD16;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_LO:         r = R_PPC64_GOT_TLSGD16_LO;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_HI:         r = R_PPC64_GOT_TLSGD16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSGD16_HA:         r = R_PPC64_GOT_TLSGD16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16:            r = R_PPC64_GOT_TLSLD16;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_LO:         r = R_PPC64_GOT_TLSLD16_LO;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_HI:         r = R_PPC64_GOT_TLSLD16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TLSLD16_HA:         r = R_PPC64_GOT_TLSLD16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16:            r = R_PPC64_GOT_TPREL16_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_LO:         r = R_PPC64_GOT_TPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_HI:         r = R_PPC64_GOT_TPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_TPREL16_HA:         r = R_PPC64_GOT_TPREL16_HA;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16:           r = R_PPC64_GOT_DTPREL16_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_LO:                r = R_PPC64_GOT_DTPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_HI:                r = R_PPC64_GOT_DTPREL16_HI;
+      break;
+    case BFD_RELOC_PPC_GOT_DTPREL16_HA:                r = R_PPC64_GOT_DTPREL16_HA;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_DS:           r = R_PPC64_TPREL16_DS;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_LO_DS:                r = R_PPC64_TPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHER:       r = R_PPC64_TPREL16_HIGHER;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHERA:      r = R_PPC64_TPREL16_HIGHERA;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHEST:      r = R_PPC64_TPREL16_HIGHEST;
+      break;
+    case BFD_RELOC_PPC64_TPREL16_HIGHESTA:     r = R_PPC64_TPREL16_HIGHESTA;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_DS:          r = R_PPC64_DTPREL16_DS;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_LO_DS:       r = R_PPC64_DTPREL16_LO_DS;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHER:      r = R_PPC64_DTPREL16_HIGHER;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHERA:     r = R_PPC64_DTPREL16_HIGHERA;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHEST:     r = R_PPC64_DTPREL16_HIGHEST;
+      break;
+    case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:    r = R_PPC64_DTPREL16_HIGHESTA;
+      break;
+    case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
+      break;
+    case BFD_RELOC_VTABLE_ENTRY:               r = R_PPC64_GNU_VTENTRY;
+      break;
+    }
+
+  return ppc64_elf_howto_table[(int) r];
+};
+
+/* Set the howto pointer for a PowerPC ELF reloc.  */
+
+static void
+ppc64_elf_info_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *cache_ptr;
+     Elf_Internal_Rela *dst;
+{
+  unsigned int type;
+
+  /* Initialize howto table if needed.  */
+  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
+    ppc_howto_init ();
+
+  type = ELF64_R_TYPE (dst->r_info);
+  BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
+                     / sizeof (ppc64_elf_howto_table[0])));
+  cache_ptr->howto = ppc64_elf_howto_table[type];
+}
+
+/* Handle the R_PPC64_ADDR16_HA and similar relocs.  */
+
+static bfd_reloc_status_type
+ppc64_elf_ha_reloc (abfd, reloc_entry, symbol, data,
+                   input_section, output_bfd, error_message)
+     bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol;
      PTR data;
@@ -1410,10 +2099,10 @@ ppc64_elf_brtaken_reloc (abfd, reloc_entry, symbol, data,
      char **error_message;
 {
   long insn;
-  enum elf_ppc_reloc_type r_type;
+  enum elf_ppc64_reloc_type r_type;
   bfd_size_type octets;
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
-  boolean is_power4 = false;
+  bfd_boolean is_power4 = FALSE;
 
   /* If this is a relocatable link (output_bfd test tells us), just
      call the generic function.  Any adjustment will be done at final
@@ -1425,7 +2114,7 @@ ppc64_elf_brtaken_reloc (abfd, reloc_entry, symbol, data,
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
   insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
   insn &= ~(0x01 << 21);
-  r_type = (enum elf_ppc_reloc_type) reloc_entry->howto->type;
+  r_type = (enum elf_ppc64_reloc_type) reloc_entry->howto->type;
   if (r_type == R_PPC64_ADDR14_BRTAKEN
       || r_type == R_PPC64_REL14_BRTAKEN)
     insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
@@ -1633,50 +2322,38 @@ ppc64_elf_unhandled_reloc (abfd, reloc_entry, symbol, data,
   return bfd_reloc_dangerous;
 }
 
-/* Return symbol info as per usual for ELF targets, except that
-   symbols in .opd are given 'd' or 'D' for type.  */
+/* Fix bad default arch selected for a 64 bit input bfd when the
+   default is 32 bit.  */
 
-static void
-ppc64_elf_get_symbol_info (abfd, symbol, ret)
+static bfd_boolean
+ppc64_elf_object_p (abfd)
      bfd *abfd;
-     asymbol *symbol;
-     symbol_info *ret;
 {
-  _bfd_elf_get_symbol_info (abfd, symbol, ret);
-  if (ret->type == '?'
-      && (symbol->flags & (BSF_GLOBAL | BSF_LOCAL)) != 0
-      && strcmp (symbol->section->name, ".opd") == 0)
-    ret->type = (symbol->flags & BSF_GLOBAL) != 0 ? 'D' : 'd';
-}
-
-/* Function to set whether a module needs the -mrelocatable bit set.  */
-
-static boolean
-ppc64_elf_set_private_flags (abfd, flags)
-     bfd *abfd;
-     flagword flags;
-{
-  BFD_ASSERT (!elf_flags_init (abfd)
-             || elf_elfheader (abfd)->e_flags == flags);
+  if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32)
+    {
+      Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
 
-  elf_elfheader (abfd)->e_flags = flags;
-  elf_flags_init (abfd) = true;
-  return true;
+      if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+       {
+         /* Relies on arch after 32 bit default being 64 bit default.  */
+         abfd->arch_info = abfd->arch_info->next;
+         BFD_ASSERT (abfd->arch_info->bits_per_word == 64);
+       }
+    }
+  return TRUE;
 }
 
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
-static boolean
+
+static bfd_boolean
 ppc64_elf_merge_private_bfd_data (ibfd, obfd)
      bfd *ibfd;
      bfd *obfd;
 {
-  flagword old_flags;
-  flagword new_flags;
-  boolean error;
-
   /* Check if we have the same endianess.  */
   if (ibfd->xvec->byteorder != obfd->xvec->byteorder
+      && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
       && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
     {
       const char *msg;
@@ -1689,110 +2366,47 @@ ppc64_elf_merge_private_bfd_data (ibfd, obfd)
       (*_bfd_error_handler) (msg, bfd_archive_filename (ibfd));
 
       bfd_set_error (bfd_error_wrong_format);
-      return false;
+      return FALSE;
     }
 
-  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
-      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return true;
-
-  new_flags = elf_elfheader (ibfd)->e_flags;
-  old_flags = elf_elfheader (obfd)->e_flags;
-  if (!elf_flags_init (obfd))
-    {
-      /* First call, no flags set.  */
-      elf_flags_init (obfd) = true;
-      elf_elfheader (obfd)->e_flags = new_flags;
-    }
-
-  else if (new_flags == old_flags)
-    /* Compatible flags are ok.  */
-    ;
-
-  else
-    {
-      /* Incompatible flags.  Warn about -mrelocatable mismatch.
-        Allow -mrelocatable-lib to be linked with either.  */
-      error = false;
-      if ((new_flags & EF_PPC_RELOCATABLE) != 0
-         && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
-       {
-         error = true;
-         (*_bfd_error_handler)
-           (_("%s: compiled with -mrelocatable and linked with modules compiled normally"),
-            bfd_archive_filename (ibfd));
-       }
-      else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
-              && (old_flags & EF_PPC_RELOCATABLE) != 0)
-       {
-         error = true;
-         (*_bfd_error_handler)
-           (_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
-            bfd_archive_filename (ibfd));
-       }
-
-      /* The output is -mrelocatable-lib iff both the input files are.  */
-      if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
-       elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
-
-      /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
-         but each input file is either -mrelocatable or -mrelocatable-lib.  */
-      if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
-         && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
-         && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
-       elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
-
-      /* Do not warn about eabi vs. V.4 mismatch, just or in the bit
-        if any module uses it.  */
-      elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
-
-      new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
-      old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
-
-      /* Warn about any other mismatches.  */
-      if (new_flags != old_flags)
-       {
-         error = true;
-         (*_bfd_error_handler)
-           (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-            bfd_archive_filename (ibfd), (long) new_flags, (long) old_flags);
-       }
-
-      if (error)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         return false;
-       }
-    }
-
-  return true;
+  return TRUE;
 }
 
-/* Handle a PowerPC specific section when reading an object file.  This
-   is called when elfcode.h finds a section with an unknown type.  */
-
-static boolean
-ppc64_elf_section_from_shdr (abfd, hdr, name)
-     bfd *abfd;
-     Elf64_Internal_Shdr *hdr;
-     const char *name;
+struct _ppc64_elf_section_data
 {
-  asection *newsect;
-  flagword flags;
+  struct bfd_elf_section_data elf;
+
+  /* An array with one entry for each opd function descriptor.  */
+  union
+  {
+    /* Points to the function code section for local opd entries.  */
+    asection **func_sec;
+    /* After editing .opd, adjust references to opd local syms.  */
+    long *adjust;
+  } opd;
+
+  /* An array for toc sections, indexed by offset/8.
+     Specifies the relocation symbol index used at a given toc offset.  */
+  unsigned *t_symndx;
+};
 
-  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
-    return false;
+#define ppc64_elf_section_data(sec) \
+  ((struct _ppc64_elf_section_data *) elf_section_data (sec))
 
-  newsect = hdr->bfd_section;
-  flags = bfd_get_section_flags (abfd, newsect);
-  if (hdr->sh_flags & SHF_EXCLUDE)
-    flags |= SEC_EXCLUDE;
+static bfd_boolean
+ppc64_elf_new_section_hook (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  struct _ppc64_elf_section_data *sdata;
+  bfd_size_type amt = sizeof (*sdata);
 
-  if (hdr->sh_type == SHT_ORDERED)
-    flags |= SEC_SORT_ENTRIES;
+  sdata = (struct _ppc64_elf_section_data *) bfd_zalloc (abfd, amt);
+  if (sdata == NULL)
+    return FALSE;
+  sec->used_by_bfd = (PTR) sdata;
 
-  bfd_set_section_flags (abfd, newsect, flags);
-  return true;
+  return _bfd_elf_new_section_hook (abfd, sec);
 }
 \f
 /* The following functions are specific to the ELF linker, while
@@ -1835,7 +2449,7 @@ ppc64_elf_section_from_shdr (abfd, hdr, name)
    .
    .   .foo_stub:
    .           addis   12,2,Lfoo@toc@ha        # in practice, the call stub
-   .           addi    12,12,Lfoo@toc@l        # is slightly optimised, but
+   .           addi    12,12,Lfoo@toc@l        # is slightly optimized, but
    .           std     2,40(1)                 # this is the general idea
    .           ld      11,0(12)
    .           ld      2,8(12)
@@ -1873,23 +2487,54 @@ struct ppc_dyn_relocs
 {
   struct ppc_dyn_relocs *next;
 
-  /* The input section of the reloc.  */
-  asection *sec;
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  bfd_size_type count;
+
+  /* Number of pc-relative relocs copied for the input section.  */
+  bfd_size_type pc_count;
+};
+
+/* Track GOT entries needed for a given symbol.  We might need more
+   than one got entry per symbol.  */
+struct got_entry
+{
+  struct got_entry *next;
+
+  bfd_vma addend;
+
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } got;
+
+  char tls_type;
+};
+
+/* The same for PLT.  */
+struct plt_entry
+{
+  struct plt_entry *next;
 
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
+  bfd_vma addend;
 
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } plt;
 };
 
 /* Of those relocs that might be copied as dynamic relocs, this macro
-   selects between relative and absolute types.  */
+   selects those that must be copied when linking a shared library.  */
 
-#define IS_ABSOLUTE_RELOC(RTYPE)               \
+#define MUST_BE_DYN_RELOC(RTYPE)               \
   ((RTYPE) != R_PPC64_REL32                    \
    && (RTYPE) != R_PPC64_REL64                 \
-   && (RTYPE) != R_PPC64_ADDR30)
+   && (RTYPE) != R_PPC64_REL30)
 
 /* Section name for stubs is the associated section name plus this
    string.  */
@@ -1904,19 +2549,19 @@ struct ppc_dyn_relocs
    ppc_stub_plt_branch:
    Similar to the above, but a 24 bit branch in the stub section won't
    reach its destination.
-   .   addis   %r12,%r2,xxx@ha
-   .   ld      %r11,xxx@l(%r12)
+   .   addis   %r12,%r2,xxx@toc@ha
+   .   ld      %r11,xxx@toc@l(%r12)
    .   mtctr   %r11
    .   bctr
 
    ppc_stub_plt_call:
    Used to call a function in a shared library.
-   .   addis   %r12,%r2,xxx@ha
+   .   addis   %r12,%r2,xxx@toc@ha
    .   std     %r2,40(%r1)
-   .   ld      %r11,xxx+0@l(%r12)
-   .   ld      %r2,xxx+8@l(%r12)
+   .   ld      %r11,xxx+0@toc@l(%r12)
+   .   ld      %r2,xxx+8@toc@l(%r12)
    .   mtctr   %r11
-   .   ld      %r11,xxx+16@l(%r12)
+   .   ld      %r11,xxx+16@toc@l(%r12)
    .   bctr
 */
 
@@ -1948,6 +2593,9 @@ struct ppc_stub_hash_entry {
   /* The symbol table entry, if any, that this was derived from.  */
   struct ppc_link_hash_entry *h;
 
+  /* And the reloc addend that this was derived from.  */
+  bfd_vma addend;
+
   /* Where this stub is being called from, or, in the case of combined
      stub sections, the first input section in the group.  */
   asection *id_sec;
@@ -1982,6 +2630,17 @@ struct ppc_link_hash_entry
   /* Flag function code and descriptor symbols.  */
   unsigned int is_func:1;
   unsigned int is_func_descriptor:1;
+  unsigned int is_entry:1;
+
+  /* Contexts in which symbol is used in the GOT (or TOC).
+     Linker optimization will result in various transformations.  */
+#define TLS_TLS                1       /* Any TLS reloc.  */
+#define TLS_GD_LD      2       /* GD or LD reloc requiring 2 got slots. */
+#define TLS_LD         4       /* LD reloc. */
+#define TLS_TPREL      8       /* TPREL reloc, => IE. */
+#define TLS_DTPREL     16      /* DTPREL reloc, => LD. */
+#define TLS_EXPLICIT   32      /* Marks TOC section relocs. */
+  char tls_type;
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -2013,10 +2672,8 @@ struct ppc_link_hash_table
   } *stub_group;
 
   /* Assorted information used by ppc64_elf_size_stubs.  */
-  unsigned int bfd_count;
   int top_index;
   asection **input_list;
-  Elf_Internal_Sym **all_local_syms;
 
   /* Short-cuts to get to dynamic linker sections.  */
   asection *sgot;
@@ -2030,6 +2687,18 @@ struct ppc_link_hash_table
   asection *sbrlt;
   asection *srelbrlt;
 
+  /* Short-cut to first output tls section.  */
+  asection *tls_sec;
+
+  /* Shortcut to .__tls_get_addr.  */
+  struct elf_link_hash_entry *tls_get_addr;
+
+  /* TLS local dynamic got entry handling.  */
+  union {
+    bfd_signed_vma refcount;
+    bfd_vma offset;
+  } tlsld_got;
+
   /* Set on error.  */
   unsigned int stub_error;
 
@@ -2065,62 +2734,68 @@ static struct ppc_stub_hash_entry *ppc_get_stub_entry
           const Elf_Internal_Rela *, struct ppc_link_hash_table *));
 static struct ppc_stub_hash_entry *ppc_add_stub
   PARAMS ((const char *, asection *, struct ppc_link_hash_table *));
-static boolean create_linkage_sections
+static bfd_boolean create_linkage_sections
   PARAMS ((bfd *, struct bfd_link_info *));
-static boolean create_got_section
+static bfd_boolean create_got_section
   PARAMS ((bfd *, struct bfd_link_info *));
-static boolean ppc64_elf_create_dynamic_sections
+static bfd_boolean ppc64_elf_create_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static void ppc64_elf_copy_indirect_symbol
-  PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *));
-static boolean ppc64_elf_check_relocs
+  PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
+          struct elf_link_hash_entry *));
+static bfd_boolean update_local_sym_info
+  PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned long, bfd_vma, int));
+static bfd_boolean update_plt_info
+  PARAMS ((bfd *, struct ppc_link_hash_entry *, bfd_vma));
+static bfd_boolean ppc64_elf_check_relocs
   PARAMS ((bfd *, struct bfd_link_info *, asection *,
           const Elf_Internal_Rela *));
 static asection * ppc64_elf_gc_mark_hook
-  PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Rela *rel,
-          struct elf_link_hash_entry *h, Elf_Internal_Sym *sym));
-static boolean ppc64_elf_gc_sweep_hook
-  PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec,
-          const Elf_Internal_Rela *relocs));
-static boolean func_desc_adjust
+  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static bfd_boolean ppc64_elf_gc_sweep_hook
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static bfd_boolean func_desc_adjust
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean ppc64_elf_func_desc_adjust
+static bfd_boolean ppc64_elf_func_desc_adjust
   PARAMS ((bfd *, struct bfd_link_info *));
-static boolean ppc64_elf_adjust_dynamic_symbol
+static bfd_boolean ppc64_elf_adjust_dynamic_symbol
   PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
 static void ppc64_elf_hide_symbol
-  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, boolean));
-static boolean allocate_dynrelocs
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
+static bfd_boolean get_sym_h
+  PARAMS ((struct elf_link_hash_entry **, Elf_Internal_Sym **, asection **,
+          char **, Elf_Internal_Sym **, unsigned long, bfd *));
+static bfd_boolean get_tls_type
+  PARAMS ((char **, Elf_Internal_Sym **, const Elf_Internal_Rela *, bfd *));
+static bfd_boolean allocate_dynrelocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean readonly_dynrelocs
+static bfd_boolean readonly_dynrelocs
   PARAMS ((struct elf_link_hash_entry *, PTR));
 static enum elf_reloc_type_class ppc64_elf_reloc_type_class
   PARAMS ((const Elf_Internal_Rela *));
-static boolean ppc64_elf_size_dynamic_sections
+static bfd_boolean ppc64_elf_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
-static INLINE enum ppc_stub_type ppc_type_of_stub
+static enum ppc_stub_type ppc_type_of_stub
   PARAMS ((asection *, const Elf_Internal_Rela *,
           struct ppc_link_hash_entry **, bfd_vma));
 static bfd_byte *build_plt_stub
   PARAMS ((bfd *, bfd_byte *, int, int));
-static boolean ppc_build_one_stub
+static bfd_boolean ppc_build_one_stub
   PARAMS ((struct bfd_hash_entry *, PTR));
-static boolean ppc_size_one_stub
+static bfd_boolean ppc_size_one_stub
   PARAMS ((struct bfd_hash_entry *, PTR));
 static void group_sections
-  PARAMS ((struct ppc_link_hash_table *, bfd_size_type, boolean));
-static boolean get_local_syms
-  PARAMS ((bfd *, struct ppc_link_hash_table *));
-static boolean ppc64_elf_fake_sections
-  PARAMS ((bfd *, Elf64_Internal_Shdr *, asection *));
-static boolean ppc64_elf_relocate_section
+  PARAMS ((struct ppc_link_hash_table *, bfd_size_type, bfd_boolean));
+static bfd_boolean ppc64_elf_relocate_section
   PARAMS ((bfd *, struct bfd_link_info *info, bfd *, asection *, bfd_byte *,
           Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms,
           asection **));
-static boolean ppc64_elf_finish_dynamic_symbol
+static bfd_boolean ppc64_elf_finish_dynamic_symbol
   PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
           Elf_Internal_Sym *));
-static boolean ppc64_elf_finish_dynamic_sections
+static bfd_boolean ppc64_elf_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
 /* Get the ppc64 ELF linker hash table from a link_info structure.  */
@@ -2233,6 +2908,8 @@ link_hash_newfunc (entry, table, string)
       eh->oh = NULL;
       eh->is_func = 0;
       eh->is_func_descriptor = 0;
+      eh->is_entry = 0;
+      eh->tls_type = 0;
     }
 
   return entry;
@@ -2279,11 +2956,15 @@ ppc64_elf_link_hash_table_create (abfd)
   htab->sfpr = NULL;
   htab->sbrlt = NULL;
   htab->srelbrlt = NULL;
+  htab->tls_sec = NULL;
+  htab->tlsld_got.refcount = 0;
   htab->stub_error = 0;
   htab->has_14bit_branch = 0;
   htab->have_undefweak = 0;
   htab->stub_iteration = 0;
   htab->sym_sec.abfd = NULL;
+  htab->elf.init_refcount.glist = NULL;
+  htab->elf.init_offset.glist = NULL;
 
   return &htab->elf.root;
 }
@@ -2378,241 +3059,1001 @@ ppc_get_stub_entry (input_section, sym_sec, hash, rel, htab)
     {
       char *stub_name;
 
-      stub_name = ppc_stub_name (id_sec, sym_sec, h, rel);
-      if (stub_name == NULL)
-       return NULL;
+      stub_name = ppc_stub_name (id_sec, sym_sec, h, rel);
+      if (stub_name == NULL)
+       return NULL;
+
+      stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table,
+                                        stub_name, FALSE, FALSE);
+      if (h != NULL)
+       h->stub_cache = stub_entry;
+
+      free (stub_name);
+    }
+
+  return stub_entry;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+
+static struct ppc_stub_hash_entry *
+ppc_add_stub (stub_name, section, htab)
+     const char *stub_name;
+     asection *section;
+     struct ppc_link_hash_table *htab;
+{
+  asection *link_sec;
+  asection *stub_sec;
+  struct ppc_stub_hash_entry *stub_entry;
+
+  link_sec = htab->stub_group[section->id].link_sec;
+  stub_sec = htab->stub_group[section->id].stub_sec;
+  if (stub_sec == NULL)
+    {
+      stub_sec = htab->stub_group[link_sec->id].stub_sec;
+      if (stub_sec == NULL)
+       {
+         size_t namelen;
+         bfd_size_type len;
+         char *s_name;
+
+         namelen = strlen (link_sec->name);
+         len = namelen + sizeof (STUB_SUFFIX);
+         s_name = bfd_alloc (htab->stub_bfd, len);
+         if (s_name == NULL)
+           return NULL;
+
+         memcpy (s_name, link_sec->name, namelen);
+         memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+         stub_sec = (*htab->add_stub_section) (s_name, link_sec);
+         if (stub_sec == NULL)
+           return NULL;
+         htab->stub_group[link_sec->id].stub_sec = stub_sec;
+       }
+      htab->stub_group[section->id].stub_sec = stub_sec;
+    }
+
+  /* Enter this entry into the linker stub hash table.  */
+  stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name,
+                                    TRUE, FALSE);
+  if (stub_entry == NULL)
+    {
+      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
+                            bfd_archive_filename (section->owner),
+                            stub_name);
+      return NULL;
+    }
+
+  stub_entry->stub_sec = stub_sec;
+  stub_entry->stub_offset = 0;
+  stub_entry->id_sec = link_sec;
+  return stub_entry;
+}
+
+/* Create sections for linker generated code.  */
+
+static bfd_boolean
+create_linkage_sections (dynobj, info)
+     bfd *dynobj;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+  flagword flags;
+
+  htab = ppc_hash_table (info);
+
+  /* Create .sfpr for code to save and restore fp regs.  */
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->sfpr = bfd_make_section_anyway (dynobj, ".sfpr");
+  if (htab->sfpr == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sfpr, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+    return FALSE;
+
+  /* Create .glink for lazy dynamic linking support.  */
+  htab->sglink = bfd_make_section_anyway (dynobj, ".glink");
+  if (htab->sglink == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sglink, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sglink, 2))
+    return FALSE;
+
+  /* Create .branch_lt for plt_branch stubs.  */
+  flags = (SEC_ALLOC | SEC_LOAD
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->sbrlt = bfd_make_section_anyway (dynobj, ".branch_lt");
+  if (htab->sbrlt == NULL
+      || ! bfd_set_section_flags (dynobj, htab->sbrlt, flags)
+      || ! bfd_set_section_alignment (dynobj, htab->sbrlt, 3))
+    return FALSE;
+
+  if (info->shared)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->srelbrlt = bfd_make_section_anyway (dynobj, ".rela.branch_lt");
+      if (!htab->srelbrlt
+         || ! bfd_set_section_flags (dynobj, htab->srelbrlt, flags)
+         || ! bfd_set_section_alignment (dynobj, htab->srelbrlt, 3))
+       return FALSE;
+    }
+  return TRUE;
+}
+
+/* Create .got and .rela.got sections in DYNOBJ, and set up
+   shortcuts to them in our hash table.  */
+
+static bfd_boolean
+create_got_section (dynobj, info)
+     bfd *dynobj;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+
+  if (! _bfd_elf_create_got_section (dynobj, info))
+    return FALSE;
+
+  htab = ppc_hash_table (info);
+  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
+  if (!htab->sgot)
+    abort ();
+
+  htab->srelgot = bfd_make_section (dynobj, ".rela.got");
+  if (!htab->srelgot
+      || ! bfd_set_section_flags (dynobj, htab->srelgot,
+                                 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                                  | SEC_IN_MEMORY | SEC_LINKER_CREATED
+                                  | SEC_READONLY))
+      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3))
+    return FALSE;
+  return TRUE;
+}
+
+/* Create the dynamic sections, and set up shortcuts.  */
+
+static bfd_boolean
+ppc64_elf_create_dynamic_sections (dynobj, info)
+     bfd *dynobj;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+
+  htab = ppc_hash_table (info);
+  if (!htab->sgot && !create_got_section (dynobj, info))
+    return FALSE;
+
+  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
+    return FALSE;
+
+  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
+  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+  if (!info->shared)
+    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+
+  if (!htab->splt || !htab->srelplt || !htab->sdynbss
+      || (!info->shared && !htab->srelbss))
+    abort ();
+
+  return TRUE;
+}
+
+/* Copy the extra info we tack onto an elf_link_hash_entry.  */
+
+static void
+ppc64_elf_copy_indirect_symbol (bed, dir, ind)
+     struct elf_backend_data *bed ATTRIBUTE_UNUSED;
+     struct elf_link_hash_entry *dir, *ind;
+{
+  struct ppc_link_hash_entry *edir, *eind;
+
+  edir = (struct ppc_link_hash_entry *) dir;
+  eind = (struct ppc_link_hash_entry *) ind;
+
+  /* Copy over any dynamic relocs we may have on the indirect sym.  */
+  if (eind->dyn_relocs != NULL)
+    {
+      if (edir->dyn_relocs != NULL)
+       {
+         struct ppc_dyn_relocs **pp;
+         struct ppc_dyn_relocs *p;
+
+         if (eind->elf.root.type == bfd_link_hash_indirect)
+           abort ();
+
+         /* Add reloc counts against the weak sym to the strong sym
+            list.  Merge any entries against the same section.  */
+         for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+           {
+             struct ppc_dyn_relocs *q;
+
+             for (q = edir->dyn_relocs; q != NULL; q = q->next)
+               if (q->sec == p->sec)
+                 {
+                   q->pc_count += p->pc_count;
+                   q->count += p->count;
+                   *pp = p->next;
+                   break;
+                 }
+             if (q == NULL)
+               pp = &p->next;
+           }
+         *pp = edir->dyn_relocs;
+       }
+
+      edir->dyn_relocs = eind->dyn_relocs;
+      eind->dyn_relocs = NULL;
+    }
+
+  /* Do the same for got entries.  */
+  if (eind->elf.got.glist != NULL)
+    {
+      if (edir->elf.got.glist != NULL)
+       {
+         struct got_entry **entp;
+         struct got_entry *ent;
+
+         for (entp = &eind->elf.got.glist; (ent = *entp) != NULL; )
+           {
+             struct got_entry *dent;
+
+             for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next)
+               if (dent->addend == ent->addend
+                   && dent->tls_type == ent->tls_type)
+                 {
+                   dent->got.refcount += ent->got.refcount;
+                   *entp = ent->next;
+                   break;
+                 }
+             if (dent == NULL)
+               entp = &ent->next;
+           }
+         *entp = edir->elf.got.glist;
+       }
+
+      edir->elf.got.glist = eind->elf.got.glist;
+      eind->elf.got.glist = NULL;
+    }
+
+  /* And plt entries.  */
+  if (eind->elf.plt.plist != NULL)
+    {
+      if (edir->elf.plt.plist != NULL)
+       {
+         struct plt_entry **entp;
+         struct plt_entry *ent;
+
+         for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; )
+           {
+             struct plt_entry *dent;
+
+             for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next)
+               if (dent->addend == ent->addend)
+                 {
+                   dent->plt.refcount += ent->plt.refcount;
+                   *entp = ent->next;
+                   break;
+                 }
+             if (dent == NULL)
+               entp = &ent->next;
+           }
+         *entp = edir->elf.plt.plist;
+       }
+
+      edir->elf.plt.plist = eind->elf.plt.plist;
+      eind->elf.plt.plist = NULL;
+    }
+
+  edir->is_func |= eind->is_func;
+  edir->is_func_descriptor |= eind->is_func_descriptor;
+  edir->is_entry |= eind->is_entry;
+
+  /* Copy down any references that we may have already seen to the
+     symbol which just became indirect.  */
+  edir->elf.elf_link_hash_flags |=
+    (eind->elf.elf_link_hash_flags
+     & (ELF_LINK_HASH_REF_DYNAMIC
+       | ELF_LINK_HASH_REF_REGULAR
+       | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+       | ELF_LINK_NON_GOT_REF));
+
+  if (eind->elf.root.type != bfd_link_hash_indirect)
+    return;
+
+  if (edir->elf.dynindx == -1)
+    {
+      edir->elf.dynindx = eind->elf.dynindx;
+      edir->elf.dynstr_index = eind->elf.dynstr_index;
+      eind->elf.dynindx = -1;
+      eind->elf.dynstr_index = 0;
+    }
+  else
+    BFD_ASSERT (eind->elf.dynindx == -1);
+}
+
+/* Set a flag, used by ppc64_elf_gc_mark_hook, on the entry symbol and
+   symbols undefined on the command-line.  */
+
+bfd_boolean
+ppc64_elf_mark_entry_syms (info)
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+  struct bfd_sym_chain *sym;
+
+  htab = ppc_hash_table (info);
+  for (sym = info->gc_sym_list; sym; sym = sym->next)
+    {
+      struct elf_link_hash_entry *h;
 
-      stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table,
-                                        stub_name, false, false);
+      h = elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
       if (h != NULL)
-       h->stub_cache = stub_entry;
-
-      free (stub_name);
+       ((struct ppc_link_hash_entry *) h)->is_entry = 1;
     }
-
-  return stub_entry;
+  return TRUE;
 }
 
-/* Add a new stub entry to the stub hash.  Not all fields of the new
-   stub entry are initialised.  */
-
-static struct ppc_stub_hash_entry *
-ppc_add_stub (stub_name, section, htab)
-     const char *stub_name;
-     asection *section;
-     struct ppc_link_hash_table *htab;
+static bfd_boolean
+update_local_sym_info (abfd, symtab_hdr, r_symndx, r_addend, tls_type)
+     bfd *abfd;
+     Elf_Internal_Shdr *symtab_hdr;
+     unsigned long r_symndx;
+     bfd_vma r_addend;
+     int tls_type;
 {
-  asection *link_sec;
-  asection *stub_sec;
-  struct ppc_stub_hash_entry *stub_entry;
+  struct got_entry **local_got_ents = elf_local_got_ents (abfd);
+  char *local_got_tls_types;
 
-  link_sec = htab->stub_group[section->id].link_sec;
-  stub_sec = htab->stub_group[section->id].stub_sec;
-  if (stub_sec == NULL)
+  if (local_got_ents == NULL)
     {
-      stub_sec = htab->stub_group[link_sec->id].stub_sec;
-      if (stub_sec == NULL)
-       {
-         bfd_size_type len;
-         char *s_name;
+      bfd_size_type size = symtab_hdr->sh_info;
 
-         len = strlen (link_sec->name) + sizeof (STUB_SUFFIX);
-         s_name = bfd_alloc (htab->stub_bfd, len);
-         if (s_name == NULL)
-           return NULL;
+      size *= sizeof (*local_got_ents) + sizeof (char);
+      local_got_ents = (struct got_entry **) bfd_zalloc (abfd, size);
+      if (local_got_ents == NULL)
+       return FALSE;
+      elf_local_got_ents (abfd) = local_got_ents;
+    }
 
-         strcpy (s_name, link_sec->name);
-         strcpy (s_name + len - sizeof (STUB_SUFFIX), STUB_SUFFIX);
-         stub_sec = (*htab->add_stub_section) (s_name, link_sec);
-         if (stub_sec == NULL)
-           return NULL;
-         htab->stub_group[link_sec->id].stub_sec = stub_sec;
+  if ((tls_type & TLS_EXPLICIT) == 0)
+    {
+      struct got_entry *ent;
+
+      for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
+       if (ent->addend == r_addend && ent->tls_type == tls_type)
+         break;
+      if (ent == NULL)
+       {
+         bfd_size_type amt = sizeof (*ent);
+         ent = (struct got_entry *) bfd_alloc (abfd, amt);
+         if (ent == NULL)
+           return FALSE;
+         ent->next = local_got_ents[r_symndx];
+         ent->addend = r_addend;
+         ent->tls_type = tls_type;
+         ent->got.refcount = 0;
+         local_got_ents[r_symndx] = ent;
        }
-      htab->stub_group[section->id].stub_sec = stub_sec;
+      ent->got.refcount += 1;
     }
 
-  /* Enter this entry into the linker stub hash table.  */
-  stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name,
-                                    true, false);
-  if (stub_entry == NULL)
+  local_got_tls_types = (char *) (local_got_ents + symtab_hdr->sh_info);
+  local_got_tls_types[r_symndx] |= tls_type;
+  return TRUE;
+}
+
+static bfd_boolean
+update_plt_info (abfd, eh, addend)
+     bfd *abfd;
+     struct ppc_link_hash_entry *eh;
+     bfd_vma addend;
+{
+  struct plt_entry *ent;
+
+  for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next)
+    if (ent->addend == addend)
+      break;
+  if (ent == NULL)
     {
-      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
-                            bfd_archive_filename (section->owner),
-                            stub_name);
-      return NULL;
+      bfd_size_type amt = sizeof (*ent);
+      ent = (struct plt_entry *) bfd_alloc (abfd, amt);
+      if (ent == NULL)
+       return FALSE;
+      ent->next = eh->elf.plt.plist;
+      ent->addend = addend;
+      ent->plt.refcount = 0;
+      eh->elf.plt.plist = ent;
     }
-
-  stub_entry->stub_sec = stub_sec;
-  stub_entry->stub_offset = 0;
-  stub_entry->id_sec = link_sec;
-  return stub_entry;
+  ent->plt.refcount += 1;
+  eh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+  eh->is_func = 1;
+  return TRUE;
 }
 
-/* Create sections for linker generated code.  */
+/* Look through the relocs for a section during the first phase, and
+   calculate needed space in the global offset table, procedure
+   linkage table, and dynamic reloc sections.  */
 
-static boolean
-create_linkage_sections (dynobj, info)
-     bfd *dynobj;
+static bfd_boolean
+ppc64_elf_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
      struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
 {
   struct ppc_link_hash_table *htab;
-  flagword flags;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  asection *sreloc;
+  asection **opd_sym_map;
+
+  if (info->relocateable)
+    return TRUE;
 
   htab = ppc_hash_table (info);
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
-  /* Create .sfpr for code to save and restore fp regs.  */
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sfpr = bfd_make_section_anyway (dynobj, ".sfpr");
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = (sym_hashes
+                   + symtab_hdr->sh_size / sizeof (Elf64_External_Sym)
+                   - symtab_hdr->sh_info);
+
+  sreloc = NULL;
+  opd_sym_map = NULL;
+  if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
+    {
+      /* Garbage collection needs some extra help with .opd sections.
+        We don't want to necessarily keep everything referenced by
+        relocs in .opd, as that would keep all functions.  Instead,
+        if we reference an .opd symbol (a function descriptor), we
+        want to keep the function code symbol's section.  This is
+        easy for global symbols, but for local syms we need to keep
+        information about the associated function section.  Later, if
+        edit_opd deletes entries, we'll use this array to adjust
+        local syms in .opd.  */
+      union opd_info {
+       asection *func_section;
+       long entry_adjust;
+      };
+      bfd_size_type amt;
+
+      amt = sec->_raw_size * sizeof (union opd_info) / 24;
+      opd_sym_map = (asection **) bfd_zalloc (abfd, amt);
+      if (opd_sym_map == NULL)
+       return FALSE;
+      ppc64_elf_section_data (sec)->opd.func_sec = opd_sym_map;
+    }
+
+  if (htab->elf.dynobj == NULL)
+    htab->elf.dynobj = abfd;
   if (htab->sfpr == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sfpr, flags)
-      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
-    return false;
+      && !create_linkage_sections (htab->elf.dynobj, info))
+    return FALSE;
 
-  /* Create .glink for lazy dynamic linking support.  */
-  htab->sglink = bfd_make_section_anyway (dynobj, ".glink");
-  if (htab->sglink == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sglink, flags)
-      || ! bfd_set_section_alignment (dynobj, htab->sglink, 2))
-    return false;
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+      enum elf_ppc64_reloc_type r_type;
+      int tls_type = 0;
+
+      r_symndx = ELF64_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
+      switch (r_type)
+       {
+       case R_PPC64_GOT_TLSLD16:
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSLD16_HI:
+       case R_PPC64_GOT_TLSLD16_HA:
+         htab->tlsld_got.refcount += 1;
+         tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+         goto dogottls;
+
+       case R_PPC64_GOT_TLSGD16:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TLSGD16_HI:
+       case R_PPC64_GOT_TLSGD16_HA:
+         tls_type = TLS_TLS | TLS_GD_LD;
+         goto dogottls;
+
+       case R_PPC64_GOT_TPREL16_DS:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_TPREL16_HI:
+       case R_PPC64_GOT_TPREL16_HA:
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         tls_type = TLS_TLS | TLS_TPREL;
+         goto dogottls;
+
+       case R_PPC64_GOT_DTPREL16_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_HI:
+       case R_PPC64_GOT_DTPREL16_HA:
+         tls_type = TLS_TLS | TLS_DTPREL;
+       dogottls:
+         sec->has_tls_reloc = 1;
+         /* Fall thru */
+
+       case R_PPC64_GOT16:
+       case R_PPC64_GOT16_DS:
+       case R_PPC64_GOT16_HA:
+       case R_PPC64_GOT16_HI:
+       case R_PPC64_GOT16_LO:
+       case R_PPC64_GOT16_LO_DS:
+         /* This symbol requires a global offset table entry.  */
+         if (htab->sgot == NULL
+             && !create_got_section (htab->elf.dynobj, info))
+           return FALSE;
+
+         if (h != NULL)
+           {
+             struct ppc_link_hash_entry *eh;
+             struct got_entry *ent;
+
+             eh = (struct ppc_link_hash_entry *) h;
+             for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next)
+               if (ent->addend == rel->r_addend
+                   && ent->tls_type == tls_type)
+                 break;
+             if (ent == NULL)
+               {
+                 bfd_size_type amt = sizeof (*ent);
+                 ent = (struct got_entry *) bfd_alloc (abfd, amt);
+                 if (ent == NULL)
+                   return FALSE;
+                 ent->next = eh->elf.got.glist;
+                 ent->addend = rel->r_addend;
+                 ent->tls_type = tls_type;
+                 ent->got.refcount = 0;
+                 eh->elf.got.glist = ent;
+               }
+             ent->got.refcount += 1;
+             eh->tls_type |= tls_type;
+           }
+         else
+           /* This is a global offset table entry for a local symbol.  */
+           if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                       rel->r_addend, tls_type))
+             return FALSE;
+         break;
+
+       case R_PPC64_PLT16_HA:
+       case R_PPC64_PLT16_HI:
+       case R_PPC64_PLT16_LO:
+       case R_PPC64_PLT32:
+       case R_PPC64_PLT64:
+         /* This symbol requires a procedure linkage table entry.  We
+            actually build the entry in adjust_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.  */
+         if (h == NULL)
+           {
+             /* It does not make sense to have a procedure linkage
+                table entry for a local symbol.  */
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+         else
+           if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
+                                 rel->r_addend))
+             return FALSE;
+         break;
+
+         /* The following relocations don't need to propagate the
+            relocation if linking a shared object since they are
+            section relative.  */
+       case R_PPC64_SECTOFF:
+       case R_PPC64_SECTOFF_LO:
+       case R_PPC64_SECTOFF_HI:
+       case R_PPC64_SECTOFF_HA:
+       case R_PPC64_SECTOFF_DS:
+       case R_PPC64_SECTOFF_LO_DS:
+       case R_PPC64_TOC16:
+       case R_PPC64_TOC16_LO:
+       case R_PPC64_TOC16_HI:
+       case R_PPC64_TOC16_HA:
+       case R_PPC64_TOC16_DS:
+       case R_PPC64_TOC16_LO_DS:
+       case R_PPC64_DTPREL16:
+       case R_PPC64_DTPREL16_LO:
+       case R_PPC64_DTPREL16_HI:
+       case R_PPC64_DTPREL16_HA:
+       case R_PPC64_DTPREL16_DS:
+       case R_PPC64_DTPREL16_LO_DS:
+       case R_PPC64_DTPREL16_HIGHER:
+       case R_PPC64_DTPREL16_HIGHERA:
+       case R_PPC64_DTPREL16_HIGHEST:
+       case R_PPC64_DTPREL16_HIGHESTA:
+         break;
+
+         /* This relocation describes the C++ object vtable hierarchy.
+            Reconstruct it for later use during GC.  */
+       case R_PPC64_GNU_VTINHERIT:
+         if (!_bfd_elf64_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return FALSE;
+         break;
+
+         /* This relocation describes which C++ vtable entries are actually
+            used.  Record for later use during GC.  */
+       case R_PPC64_GNU_VTENTRY:
+         if (!_bfd_elf64_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return FALSE;
+         break;
+
+       case R_PPC64_REL14:
+       case R_PPC64_REL14_BRTAKEN:
+       case R_PPC64_REL14_BRNTAKEN:
+         htab->has_14bit_branch = 1;
+         /* Fall through.  */
+
+       case R_PPC64_REL24:
+         if (h != NULL
+             && h->root.root.string[0] == '.'
+             && h->root.root.string[1] != 0)
+           {
+             /* We may need a .plt entry if the function this reloc
+                refers to is in a shared lib.  */
+             if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
+                                   rel->r_addend))
+               return FALSE;
+             if (h == htab->tls_get_addr)
+               sec->has_tls_reloc = 1;
+             else if (strcmp (h->root.root.string, ".__tls_get_addr") == 0)
+               {
+                 htab->tls_get_addr = h;
+                 sec->has_tls_reloc = 1;
+               }
+           }
+         break;
+
+       case R_PPC64_TPREL64:
+         tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         goto dotlstoc;
+
+       case R_PPC64_DTPMOD64:
+         if (rel + 1 < rel_end
+             && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
+             && rel[1].r_offset == rel->r_offset + 8)
+           tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD;
+         else
+           tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD_LD | TLS_LD;
+         goto dotlstoc;
+
+       case R_PPC64_DTPREL64:
+         tls_type = TLS_EXPLICIT | TLS_TLS | TLS_DTPREL;
+         if (rel != relocs
+             && rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64)
+             && rel[-1].r_offset == rel->r_offset - 8)
+           /* This is the second reloc of a dtpmod, dtprel pair.
+              Don't mark with TLS_DTPREL.  */
+           goto dodyn;
+
+       dotlstoc:
+         sec->has_tls_reloc = 1;
+         if (h != NULL)
+           {
+             struct ppc_link_hash_entry *eh;
+             eh = (struct ppc_link_hash_entry *) h;
+             eh->tls_type |= tls_type;
+           }
+         else
+           if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                       rel->r_addend, tls_type))
+             return FALSE;
+
+         if (ppc64_elf_section_data (sec)->t_symndx == NULL)
+           {
+             bfd_size_type amt = sec->_raw_size * sizeof (unsigned) / 8;
+             ppc64_elf_section_data (sec)->t_symndx
+               = (unsigned *) bfd_zalloc (abfd, amt);
+             if (ppc64_elf_section_data (sec)->t_symndx == NULL)
+               return FALSE;
+           }
+         BFD_ASSERT (rel->r_offset % 8 == 0);
+         ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8] = r_symndx;
+         goto dodyn;
+
+       case R_PPC64_TPREL16:
+       case R_PPC64_TPREL16_LO:
+       case R_PPC64_TPREL16_HI:
+       case R_PPC64_TPREL16_HA:
+       case R_PPC64_TPREL16_DS:
+       case R_PPC64_TPREL16_LO_DS:
+       case R_PPC64_TPREL16_HIGHER:
+       case R_PPC64_TPREL16_HIGHERA:
+       case R_PPC64_TPREL16_HIGHEST:
+       case R_PPC64_TPREL16_HIGHESTA:
+         if (info->shared)
+           {
+             info->flags |= DF_STATIC_TLS;
+             goto dodyn;
+           }
+         break;
+
+       case R_PPC64_ADDR64:
+         if (opd_sym_map != NULL
+             && h != NULL
+             && h->root.root.string[0] == '.'
+             && h->root.root.string[1] != 0)
+           {
+             struct elf_link_hash_entry *fdh;
+
+             fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
+                                         FALSE, FALSE, FALSE);
+             if (fdh != NULL)
+               {
+                 ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
+                 ((struct ppc_link_hash_entry *) fdh)->oh = h;
+                 ((struct ppc_link_hash_entry *) h)->is_func = 1;
+                 ((struct ppc_link_hash_entry *) h)->oh = fdh;
+               }
+           }
+         if (opd_sym_map != NULL
+             && h == NULL
+             && rel + 1 < rel_end
+             && ((enum elf_ppc64_reloc_type) ELF64_R_TYPE ((rel + 1)->r_info)
+                 == R_PPC64_TOC))
+           {
+             asection *s;
+
+             s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
+                                            r_symndx);
+             if (s == NULL)
+               return FALSE;
+             else if (s != sec)
+               opd_sym_map[rel->r_offset / 24] = s;
+           }
+         /* Fall through.  */
+
+       case R_PPC64_REL30:
+       case R_PPC64_REL32:
+       case R_PPC64_REL64:
+       case R_PPC64_ADDR14:
+       case R_PPC64_ADDR14_BRNTAKEN:
+       case R_PPC64_ADDR14_BRTAKEN:
+       case R_PPC64_ADDR16:
+       case R_PPC64_ADDR16_DS:
+       case R_PPC64_ADDR16_HA:
+       case R_PPC64_ADDR16_HI:
+       case R_PPC64_ADDR16_HIGHER:
+       case R_PPC64_ADDR16_HIGHERA:
+       case R_PPC64_ADDR16_HIGHEST:
+       case R_PPC64_ADDR16_HIGHESTA:
+       case R_PPC64_ADDR16_LO:
+       case R_PPC64_ADDR16_LO_DS:
+       case R_PPC64_ADDR24:
+       case R_PPC64_ADDR32:
+       case R_PPC64_UADDR16:
+       case R_PPC64_UADDR32:
+       case R_PPC64_UADDR64:
+       case R_PPC64_TOC:
+         /* Don't propagate .opd relocs.  */
+         if (NO_OPD_RELOCS && opd_sym_map != NULL)
+           break;
 
-  /* Create .branch_lt for plt_branch stubs.  */
-  flags = (SEC_ALLOC | SEC_LOAD
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sbrlt = bfd_make_section_anyway (dynobj, ".branch_lt");
-  if (htab->sbrlt == NULL
-      || ! bfd_set_section_flags (dynobj, htab->sbrlt, flags)
-      || ! bfd_set_section_alignment (dynobj, htab->sbrlt, 3))
-    return false;
+         /* If we are creating a shared library, and this is a reloc
+            against a global symbol, or a non PC relative reloc
+            against a local symbol, then we need to copy the reloc
+            into the shared library.  However, if we are linking with
+            -Bsymbolic, we do not need to copy a reloc against a
+            global symbol which is defined in an object we are
+            including in the link (i.e., DEF_REGULAR is set).  At
+            this point we have not seen all the input files, so it is
+            possible that DEF_REGULAR is not set now but will be set
+            later (it is never cleared).  In case of a weak definition,
+            DEF_REGULAR may be cleared later by a strong definition in
+            a shared library.  We account for that possibility below by
+            storing information in the relocs_copied field of the hash
+            table entry.  A similar situation occurs when creating
+            shared libraries and symbol visibility changes render the
+            symbol local.
 
-  if (info->shared)
-    {
-      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
-              | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      htab->srelbrlt = bfd_make_section (dynobj, ".rela.branch_lt");
-      if (!htab->srelbrlt
-         || ! bfd_set_section_flags (dynobj, htab->srelbrlt, flags)
-         || ! bfd_set_section_alignment (dynobj, htab->srelbrlt, 3))
-       return false;
-    }
-  return true;
-}
+            If on the other hand, we are creating an executable, we
+            may need to keep relocations for symbols satisfied by a
+            dynamic library if we manage to avoid copy relocs for the
+            symbol.  */
+       dodyn:
+         if ((info->shared
+              && (sec->flags & SEC_ALLOC) != 0
+              && (MUST_BE_DYN_RELOC (r_type)
+                  || (h != NULL
+                      && (! info->symbolic
+                          || h->root.type == bfd_link_hash_defweak
+                          || (h->elf_link_hash_flags
+                              & ELF_LINK_HASH_DEF_REGULAR) == 0))))
+             || (!info->shared
+                 && (sec->flags & SEC_ALLOC) != 0
+                 && h != NULL
+                 && (h->root.type == bfd_link_hash_defweak
+                     || (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+           {
+             struct ppc_dyn_relocs *p;
+             struct ppc_dyn_relocs **head;
 
-/* Create .got and .rela.got sections in DYNOBJ, and set up
-   shortcuts to them in our hash table.  */
+             /* We must copy these reloc types into the output file.
+                Create a reloc section in dynobj and make room for
+                this reloc.  */
+             if (sreloc == NULL)
+               {
+                 const char *name;
+                 bfd *dynobj;
 
-static boolean
-create_got_section (dynobj, info)
-     bfd *dynobj;
-     struct bfd_link_info *info;
-{
-  struct ppc_link_hash_table *htab;
+                 name = (bfd_elf_string_from_elf_section
+                         (abfd,
+                          elf_elfheader (abfd)->e_shstrndx,
+                          elf_section_data (sec)->rel_hdr.sh_name));
+                 if (name == NULL)
+                   return FALSE;
 
-  if (! _bfd_elf_create_got_section (dynobj, info))
-    return false;
+                 if (strncmp (name, ".rela", 5) != 0
+                     || strcmp (bfd_get_section_name (abfd, sec),
+                                name + 5) != 0)
+                   {
+                     (*_bfd_error_handler)
+                       (_("%s: bad relocation section name `%s\'"),
+                        bfd_archive_filename (abfd), name);
+                     bfd_set_error (bfd_error_bad_value);
+                   }
 
-  htab = ppc_hash_table (info);
-  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
-  if (!htab->sgot)
-    abort ();
+                 dynobj = htab->elf.dynobj;
+                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 if (sreloc == NULL)
+                   {
+                     flagword flags;
 
-  htab->srelgot = bfd_make_section (dynobj, ".rela.got");
-  if (!htab->srelgot
-      || ! bfd_set_section_flags (dynobj, htab->srelgot,
-                                 (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                  | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                                  | SEC_READONLY))
-      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3))
-    return false;
-  return true;
-}
+                     sreloc = bfd_make_section (dynobj, name);
+                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
+                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+                     if ((sec->flags & SEC_ALLOC) != 0)
+                       flags |= SEC_ALLOC | SEC_LOAD;
+                     if (sreloc == NULL
+                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
+                         || ! bfd_set_section_alignment (dynobj, sreloc, 3))
+                       return FALSE;
+                   }
+                 elf_section_data (sec)->sreloc = sreloc;
+               }
 
-/* Create the dynamic sections, and set up shortcuts.  */
+             /* If this is a global symbol, we count the number of
+                relocations we need for this symbol.  */
+             if (h != NULL)
+               {
+                 head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+               }
+             else
+               {
+                 /* Track dynamic relocs needed for local syms too.
+                    We really need local syms available to do this
+                    easily.  Oh well.  */
 
-static boolean
-ppc64_elf_create_dynamic_sections (dynobj, info)
-     bfd *dynobj;
-     struct bfd_link_info *info;
-{
-  struct ppc_link_hash_table *htab;
+                 asection *s;
+                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
+                                                sec, r_symndx);
+                 if (s == NULL)
+                   return FALSE;
 
-  htab = ppc_hash_table (info);
-  if (!htab->sgot && !create_got_section (dynobj, info))
-    return false;
+                 head = ((struct ppc_dyn_relocs **)
+                         &elf_section_data (s)->local_dynrel);
+               }
 
-  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
-    return false;
+             p = *head;
+             if (p == NULL || p->sec != sec)
+               {
+                 p = ((struct ppc_dyn_relocs *)
+                      bfd_alloc (htab->elf.dynobj,
+                                 (bfd_size_type) sizeof *p));
+                 if (p == NULL)
+                   return FALSE;
+                 p->next = *head;
+                 *head = p;
+                 p->sec = sec;
+                 p->count = 0;
+                 p->pc_count = 0;
+               }
 
-  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
-  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
-  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
-  if (!info->shared)
-    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+             p->count += 1;
+             if (!MUST_BE_DYN_RELOC (r_type))
+               p->pc_count += 1;
+           }
+         break;
 
-  if (!htab->splt || !htab->srelplt || !htab->sdynbss
-      || (!info->shared && !htab->srelbss))
-    abort ();
+       default:
+         break;
+       }
+    }
 
-  return true;
+  return TRUE;
 }
 
-/* Copy the extra info we tack onto an elf_link_hash_entry.  */
+/* Return the section that should be marked against GC for a given
+   relocation.  */
 
-static void
-ppc64_elf_copy_indirect_symbol (dir, ind)
-     struct elf_link_hash_entry *dir, *ind;
+static asection *
+ppc64_elf_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
 {
-  struct ppc_link_hash_entry *edir, *eind;
+  asection *rsec = NULL;
 
-  edir = (struct ppc_link_hash_entry *) dir;
-  eind = (struct ppc_link_hash_entry *) ind;
-
-  if (eind->dyn_relocs != NULL)
+  if (h != NULL)
     {
-      if (edir->dyn_relocs != NULL)
-       {
-         struct ppc_dyn_relocs **pp;
-         struct ppc_dyn_relocs *p;
+      enum elf_ppc64_reloc_type r_type;
+      struct ppc_link_hash_entry *fdh;
 
-         if (ind->root.type == bfd_link_hash_indirect)
-           abort ();
+      r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
+      switch (r_type)
+       {
+       case R_PPC64_GNU_VTINHERIT:
+       case R_PPC64_GNU_VTENTRY:
+         break;
 
-         /* Add reloc counts against the weak sym to the strong sym
-            list.  Merge any entries against the same section.  */
-         for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
+       default:
+         switch (h->root.type)
            {
-             struct ppc_dyn_relocs *q;
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             fdh = (struct ppc_link_hash_entry *) h;
+
+             /* Function descriptor syms cause the associated
+                function code sym section to be marked.  */
+             if (fdh->is_func_descriptor)
+               rsec = fdh->oh->root.u.def.section;
+
+             /* Function entry syms return NULL if they are in .opd
+                and are not ._start (or others undefined on the ld
+                command line).  Thus we avoid marking all function
+                sections, as all functions are referenced in .opd.  */
+             else if ((fdh->oh != NULL
+                       && ((struct ppc_link_hash_entry *) fdh->oh)->is_entry)
+                      || ppc64_elf_section_data (sec)->opd.func_sec == NULL)
+               rsec = h->root.u.def.section;
+             break;
 
-             for (q = edir->dyn_relocs; q != NULL; q = q->next)
-               if (q->sec == p->sec)
-                 {
-                   q->pc_count += p->pc_count;
-                   q->count += p->count;
-                   *pp = p->next;
-                   break;
-                 }
-             if (q == NULL)
-               pp = &p->next;
+           case bfd_link_hash_common:
+             rsec = h->root.u.c.p->section;
+             break;
+
+           default:
+             break;
            }
-         *pp = edir->dyn_relocs;
        }
-
-      edir->dyn_relocs = eind->dyn_relocs;
-      eind->dyn_relocs = NULL;
+    }
+  else
+    {
+      asection **opd_sym_section;
+
+      rsec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+      opd_sym_section = ppc64_elf_section_data (rsec)->opd.func_sec;
+      if (opd_sym_section != NULL)
+       rsec = opd_sym_section[sym->st_value / 24];
+      else if (ppc64_elf_section_data (sec)->opd.func_sec != NULL)
+       rsec = NULL;
     }
 
-  edir->is_func |= eind->is_func;
-  edir->is_func_descriptor |= eind->is_func_descriptor;
-
-  _bfd_elf_link_hash_copy_indirect (dir, ind);
+  return rsec;
 }
 
-/* Look through the relocs for a section during the first phase, and
-   calculate needed space in the global offset table, procedure
-   linkage table, and dynamic reloc sections.  */
+/* Update the .got, .plt. and dynamic reloc reference counts for the
+   section being removed.  */
 
-static boolean
-ppc64_elf_check_relocs (abfd, info, sec, relocs)
+static bfd_boolean
+ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs)
      bfd *abfd;
      struct bfd_link_info *info;
      asection *sec;
@@ -2620,86 +4061,85 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
 {
   struct ppc_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
-  const Elf_Internal_Rela *rel;
-  const Elf_Internal_Rela *rel_end;
-  asection *sreloc;
-  boolean is_opd;
-
-  if (info->relocateable)
-    return true;
-
-  htab = ppc_hash_table (info);
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-
-  sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = (sym_hashes
-                   + symtab_hdr->sh_size / sizeof (Elf64_External_Sym));
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
-
-  sreloc = NULL;
-  is_opd = strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0;
+  struct elf_link_hash_entry **sym_hashes;
+  struct got_entry **local_got_ents;
+  const Elf_Internal_Rela *rel, *relend;
 
-  if (htab->elf.dynobj == NULL)
-    htab->elf.dynobj = abfd;
-  if (htab->sfpr == NULL
-      && !create_linkage_sections (htab->elf.dynobj, info))
-    return false;
+  elf_section_data (sec)->local_dynrel = NULL;
 
-  rel_end = relocs + sec->reloc_count;
-  for (rel = relocs; rel < rel_end; rel++)
+  htab = ppc_hash_table (info);
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_ents = elf_local_got_ents (abfd);
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
     {
       unsigned long r_symndx;
+      enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h;
-      enum elf_ppc_reloc_type r_type;
+      char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-       h = NULL;
-      else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-
-      r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
+      r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
       switch (r_type)
        {
-         /* GOT16 relocations */
+       case R_PPC64_GOT_TLSLD16:
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSLD16_HI:
+       case R_PPC64_GOT_TLSLD16_HA:
+         htab->tlsld_got.refcount -= 1;
+         tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+         goto dogot;
+
+       case R_PPC64_GOT_TLSGD16:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TLSGD16_HI:
+       case R_PPC64_GOT_TLSGD16_HA:
+         tls_type = TLS_TLS | TLS_GD_LD;
+         goto dogot;
+
+       case R_PPC64_GOT_TPREL16_DS:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_TPREL16_HI:
+       case R_PPC64_GOT_TPREL16_HA:
+         tls_type = TLS_TLS | TLS_TPREL;
+         goto dogot;
+
+       case R_PPC64_GOT_DTPREL16_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_HI:
+       case R_PPC64_GOT_DTPREL16_HA:
+         tls_type = TLS_TLS | TLS_DTPREL;
+         goto dogot;
+
        case R_PPC64_GOT16:
        case R_PPC64_GOT16_DS:
        case R_PPC64_GOT16_HA:
        case R_PPC64_GOT16_HI:
        case R_PPC64_GOT16_LO:
        case R_PPC64_GOT16_LO_DS:
+       dogot:
+         {
+           struct got_entry *ent;
 
-         /* This symbol requires a global offset table entry.  */
-         if (htab->sgot == NULL
-             && !create_got_section (htab->elf.dynobj, info))
-           return false;
-
-         if (h != NULL)
-           {
-             h->got.refcount += 1;
-           }
-         else
-           {
-             bfd_signed_vma *local_got_refcounts;
+           if (r_symndx >= symtab_hdr->sh_info)
+             {
+               h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+               ent = h->got.glist;
+             }
+           else
+             ent = local_got_ents[r_symndx];
 
-             /* This is a global offset table entry for a local symbol.  */
-             local_got_refcounts = elf_local_got_refcounts (abfd);
-             if (local_got_refcounts == NULL)
-               {
-                 bfd_size_type size;
-
-                 size = symtab_hdr->sh_info;
-                 size *= sizeof (bfd_signed_vma);
-                 local_got_refcounts = ((bfd_signed_vma *)
-                                        bfd_zalloc (abfd, size));
-                 if (local_got_refcounts == NULL)
-                   return false;
-                 elf_local_got_refcounts (abfd) = local_got_refcounts;
-               }
-             local_got_refcounts[r_symndx] += 1;
-           }
+           for (; ent != NULL; ent = ent->next)
+             if (ent->addend == rel->r_addend
+                 && ent->tls_type == tls_type)
+               break;
+           if (ent == NULL)
+             abort ();
+           if (ent->got.refcount > 0)
+             ent->got.refcount -= 1;
+         }
          break;
 
        case R_PPC64_PLT16_HA:
@@ -2707,96 +4147,52 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
        case R_PPC64_PLT16_LO:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
-         /* This symbol requires a procedure linkage table entry.  We
-             actually build the entry in adjust_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.  */
-         if (h == NULL)
-           {
-             /* It does not make sense to have a procedure linkage
-                 table entry for a local symbol.  */
-             bfd_set_error (bfd_error_bad_value);
-             return false;
-           }
-
-         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-         h->plt.refcount += 1;
-         ((struct ppc_link_hash_entry *) h)->is_func = 1;
-         break;
-
-         /* The following relocations don't need to propagate the
-            relocation if linking a shared object since they are
-            section relative.  */
-       case R_PPC64_SECTOFF:
-       case R_PPC64_SECTOFF_LO:
-       case R_PPC64_SECTOFF_HI:
-       case R_PPC64_SECTOFF_HA:
-       case R_PPC64_SECTOFF_DS:
-       case R_PPC64_SECTOFF_LO_DS:
-       case R_PPC64_TOC16:
-       case R_PPC64_TOC16_LO:
-       case R_PPC64_TOC16_HI:
-       case R_PPC64_TOC16_HA:
-       case R_PPC64_TOC16_DS:
-       case R_PPC64_TOC16_LO_DS:
-         break;
-
-         /* This relocation describes the C++ object vtable hierarchy.
-            Reconstruct it for later use during GC.  */
-       case R_PPC64_GNU_VTINHERIT:
-         if (!_bfd_elf64_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return false;
-         break;
-
-         /* This relocation describes which C++ vtable entries are actually
-            used.  Record for later use during GC.  */
-       case R_PPC64_GNU_VTENTRY:
-         if (!_bfd_elf64_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return false;
-         break;
-
        case R_PPC64_REL14:
-       case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
-         htab->has_14bit_branch = 1;
-         /* Fall through.  */
-
+       case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
-         if (h != NULL
-             && h->root.root.string[0] == '.'
-             && h->root.root.string[1] != 0)
+         if (r_symndx >= symtab_hdr->sh_info)
            {
-             /* We may need a .plt entry if the function this reloc
-                refers to is in a shared lib.  */
-             h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
-             h->plt.refcount += 1;
-             ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             struct plt_entry *ent;
+
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->addend == rel->r_addend)
+                 break;
+             if (ent == NULL)
+               abort ();
+             if (ent->plt.refcount > 0)
+               ent->plt.refcount -= 1;
            }
          break;
 
-       case R_PPC64_ADDR64:
-         if (is_opd
-             && h != NULL
-             && h->root.root.string[0] == '.'
-             && h->root.root.string[1] != 0)
+       case R_PPC64_REL30:
+       case R_PPC64_REL32:
+       case R_PPC64_REL64:
+         if (r_symndx >= symtab_hdr->sh_info)
            {
-             struct elf_link_hash_entry *fdh;
+             struct ppc_link_hash_entry *eh;
+             struct ppc_dyn_relocs **pp;
+             struct ppc_dyn_relocs *p;
 
-             fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                         false, false, false);
-             if (fdh != NULL)
-               {
-                 ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-                 ((struct ppc_link_hash_entry *) fdh)->oh = h;
-                 ((struct ppc_link_hash_entry *) h)->is_func = 1;
-                 ((struct ppc_link_hash_entry *) h)->oh = fdh;
-               }
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             eh = (struct ppc_link_hash_entry *) h;
+
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+               if (p->sec == sec)
+                 {
+                   p->pc_count -= 1;
+                   p->count -= 1;
+                   if (p->count == 0)
+                     *pp = p->next;
+                   break;
+                 }
            }
-         /* Fall through.  */
+         break;
 
-       case R_PPC64_REL64:
-       case R_PPC64_REL32:
+       case R_PPC64_DTPMOD64:
+       case R_PPC64_DTPREL64:
+       case R_PPC64_TPREL64:
        case R_PPC64_ADDR14:
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_ADDR14_BRTAKEN:
@@ -2811,760 +4207,1226 @@ ppc64_elf_check_relocs (abfd, info, sec, relocs)
        case R_PPC64_ADDR16_LO:
        case R_PPC64_ADDR16_LO_DS:
        case R_PPC64_ADDR24:
-       case R_PPC64_ADDR30:
        case R_PPC64_ADDR32:
+       case R_PPC64_ADDR64:
        case R_PPC64_UADDR16:
        case R_PPC64_UADDR32:
        case R_PPC64_UADDR64:
        case R_PPC64_TOC:
-         /* Don't propagate .opd relocs.  */
-         if (NO_OPD_RELOCS && is_opd)
-           break;
+         if (r_symndx >= symtab_hdr->sh_info)
+           {
+             struct ppc_link_hash_entry *eh;
+             struct ppc_dyn_relocs **pp;
+             struct ppc_dyn_relocs *p;
+
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             eh = (struct ppc_link_hash_entry *) h;
+
+             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+               if (p->sec == sec)
+                 {
+                   p->count -= 1;
+                   if (p->count == 0)
+                     *pp = p->next;
+                   break;
+                 }
+           }
+         break;
+
+       default:
+         break;
+       }
+    }
+  return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to transfer dynamic linking
+   information on function code symbol entries to their corresponding
+   function descriptor symbol entries.  */
+static bfd_boolean
+func_desc_adjust (h, inf)
+     struct elf_link_hash_entry *h;
+     PTR inf;
+{
+  struct bfd_link_info *info;
+  struct ppc_link_hash_table *htab;
+  struct plt_entry *ent;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_warning)
+    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+  info = (struct bfd_link_info *) inf;
+  htab = ppc_hash_table (info);
+
+  /* If this is a function code symbol, transfer dynamic linking
+     information to the function descriptor symbol.  */
+  if (!((struct ppc_link_hash_entry *) h)->is_func)
+    return TRUE;
+
+  if (h->root.type == bfd_link_hash_undefweak
+      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+    htab->have_undefweak = TRUE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.refcount > 0)
+      break;
+  if (ent != NULL
+      && h->root.root.string[0] == '.'
+      && h->root.root.string[1] != '\0')
+    {
+      struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh;
+      bfd_boolean force_local;
+
+      /* Find the corresponding function descriptor symbol.  Create it
+        as undefined if necessary.  */
+
+      if (fdh == NULL)
+       fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
+                                   FALSE, FALSE, TRUE);
+
+      if (fdh == NULL
+         && info->shared
+         && (h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak))
+       {
+         bfd *abfd;
+         asymbol *newsym;
+         struct bfd_link_hash_entry *bh;
+
+         abfd = h->root.u.undef.abfd;
+         newsym = bfd_make_empty_symbol (abfd);
+         newsym->name = h->root.root.string + 1;
+         newsym->section = bfd_und_section_ptr;
+         newsym->value = 0;
+         newsym->flags = BSF_OBJECT;
+         if (h->root.type == bfd_link_hash_undefweak)
+           newsym->flags |= BSF_WEAK;
+
+         bh = &fdh->root;
+         if ( !(_bfd_generic_link_add_one_symbol
+                (info, abfd, newsym->name, newsym->flags,
+                 newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
+           {
+             return FALSE;
+           }
+         fdh = (struct elf_link_hash_entry *) bh;
+         fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+       }
+
+      if (fdh != NULL
+         && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+         && (info->shared
+             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+       {
+         if (fdh->dynindx == -1)
+           if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
+             return FALSE;
+         fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
+                                      & (ELF_LINK_HASH_REF_REGULAR
+                                         | ELF_LINK_HASH_REF_DYNAMIC
+                                         | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+                                         | ELF_LINK_NON_GOT_REF));
+         if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+           {
+             fdh->plt.plist = h->plt.plist;
+             fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+           }
+         ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
+         ((struct ppc_link_hash_entry *) fdh)->oh = h;
+         ((struct ppc_link_hash_entry *) h)->oh = fdh;
+       }
+
+      /* Now that the info is on the function descriptor, clear the
+        function code sym info.  Any function code syms for which we
+        don't have a definition in a regular file, we force local.
+        This prevents a shared library from exporting syms that have
+        been imported from another library.  Function code syms that
+        are really in the library we must leave global to prevent the
+        linker dragging in a definition from a static library.  */
+      force_local = (info->shared
+                    && ((h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0
+                        || fdh == NULL
+                        || (fdh->elf_link_hash_flags
+                            & ELF_LINK_HASH_DEF_REGULAR) == 0
+                        || (fdh->elf_link_hash_flags
+                            & ELF_LINK_FORCED_LOCAL) != 0));
+      _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+    }
+
+  return TRUE;
+}
+
+#define MIN_SAVE_FPR 14
+#define MAX_SAVE_FPR 31
 
-         /* If we are creating a shared library, and this is a reloc
-            against a global symbol, or a non PC relative reloc
-            against a local symbol, then we need to copy the reloc
-            into the shared library.  However, if we are linking with
-            -Bsymbolic, we do not need to copy a reloc against a
-            global symbol which is defined in an object we are
-            including in the link (i.e., DEF_REGULAR is set).  At
-            this point we have not seen all the input files, so it is
-            possible that DEF_REGULAR is not set now but will be set
-            later (it is never cleared).  In case of a weak definition,
-            DEF_REGULAR may be cleared later by a strong definition in
-            a shared library.  We account for that possibility below by
-            storing information in the relocs_copied field of the hash
-            table entry.  A similar situation occurs when creating
-            shared libraries and symbol visibility changes render the
-            symbol local.
+/* Called near the start of bfd_elf_size_dynamic_sections.  We use
+   this hook to a) provide some gcc support functions, and b) transfer
+   dynamic linking information gathered so far on function code symbol
+   entries, to their corresponding function descriptor symbol entries.  */
+static bfd_boolean
+ppc64_elf_func_desc_adjust (obfd, info)
+     bfd *obfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+{
+  struct ppc_link_hash_table *htab;
+  unsigned int lowest_savef = MAX_SAVE_FPR + 2;
+  unsigned int lowest_restf = MAX_SAVE_FPR + 2;
+  unsigned int i;
+  struct elf_link_hash_entry *h;
+  bfd_byte *p;
+  char sym[10];
 
-            If on the other hand, we are creating an executable, we
-            may need to keep relocations for symbols satisfied by a
-            dynamic library if we manage to avoid copy relocs for the
-            symbol.  */
-         if ((info->shared
-              && (sec->flags & SEC_ALLOC) != 0
-              && (IS_ABSOLUTE_RELOC (r_type)
-                  || (h != NULL
-                      && (! info->symbolic
-                          || h->root.type == bfd_link_hash_defweak
-                          || (h->elf_link_hash_flags
-                              & ELF_LINK_HASH_DEF_REGULAR) == 0))))
-             || (!info->shared
-                 && (sec->flags & SEC_ALLOC) != 0
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak
-                     || (h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
-           {
-             struct ppc_dyn_relocs *p;
-             struct ppc_dyn_relocs **head;
+  htab = ppc_hash_table (info);
 
-             /* We must copy these reloc types into the output file.
-                Create a reloc section in dynobj and make room for
-                this reloc.  */
-             if (sreloc == NULL)
-               {
-                 const char *name;
-                 bfd *dynobj;
+  if (htab->sfpr == NULL)
+    /* We don't have any relocs.  */
+    return TRUE;
 
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return false;
+  /* First provide any missing ._savef* and ._restf* functions.  */
+  memcpy (sym, "._savef14", 10);
+  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+    {
+      sym[7] = i / 10 + '0';
+      sym[8] = i % 10 + '0';
+      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+      if (h != NULL
+         && h->root.type == bfd_link_hash_undefined)
+       {
+         if (lowest_savef > i)
+           lowest_savef = i;
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = htab->sfpr;
+         h->root.u.def.value = (i - lowest_savef) * 4;
+         h->type = STT_FUNC;
+         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+         _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
+       }
+    }
 
-                 if (strncmp (name, ".rela", 5) != 0
-                     || strcmp (bfd_get_section_name (abfd, sec),
-                                name + 5) != 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%s: bad relocation section name `%s\'"),
-                        bfd_archive_filename (abfd), name);
-                     bfd_set_error (bfd_error_bad_value);
-                   }
+  memcpy (sym, "._restf14", 10);
+  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+    {
+      sym[7] = i / 10 + '0';
+      sym[8] = i % 10 + '0';
+      h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+      if (h != NULL
+         && h->root.type == bfd_link_hash_undefined)
+       {
+         if (lowest_restf > i)
+           lowest_restf = i;
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = htab->sfpr;
+         h->root.u.def.value = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
+                                + (i - lowest_restf) * 4);
+         h->type = STT_FUNC;
+         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+         _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
+       }
+    }
 
-                 dynobj = htab->elf.dynobj;
-                 sreloc = bfd_get_section_by_name (dynobj, name);
-                 if (sreloc == NULL)
-                   {
-                     flagword flags;
+  elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
 
-                     sreloc = bfd_make_section (dynobj, name);
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-                     if ((sec->flags & SEC_ALLOC) != 0)
-                       flags |= SEC_ALLOC | SEC_LOAD;
-                     if (sreloc == NULL
-                         || ! bfd_set_section_flags (dynobj, sreloc, flags)
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 3))
-                       return false;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
-               }
+  htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
+                          + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
 
-             /* If this is a global symbol, we count the number of
-                relocations we need for this symbol.  */
-             if (h != NULL)
-               {
-                 head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
-               }
-             else
-               {
-                 /* Track dynamic relocs needed for local syms too.
-                    We really need local syms available to do this
-                    easily.  Oh well.  */
+  if (htab->sfpr->_raw_size == 0)
+    {
+      if (!htab->have_undefweak)
+       {
+         _bfd_strip_section_from_output (info, htab->sfpr);
+         return TRUE;
+       }
 
-                 asection *s;
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
-                   return false;
+      htab->sfpr->_raw_size = 4;
+    }
 
-                 head = ((struct ppc_dyn_relocs **)
-                         &elf_section_data (s)->local_dynrel);
-               }
+  p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
+  if (p == NULL)
+    return FALSE;
+  htab->sfpr->contents = p;
 
-             p = *head;
-             if (p == NULL || p->sec != sec)
-               {
-                 p = ((struct ppc_dyn_relocs *)
-                      bfd_alloc (htab->elf.dynobj,
-                                 (bfd_size_type) sizeof *p));
-                 if (p == NULL)
-                   return false;
-                 p->next = *head;
-                 *head = p;
-                 p->sec = sec;
-                 p->count = 0;
-                 p->pc_count = 0;
-               }
+  for (i = lowest_savef; i <= MAX_SAVE_FPR; i++)
+    {
+      unsigned int fpr = i << 21;
+      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
+      bfd_put_32 (htab->elf.dynobj, STFD_FR0_0R1 + fpr + stackoff, p);
+      p += 4;
+    }
+  if (lowest_savef <= MAX_SAVE_FPR)
+    {
+      bfd_put_32 (htab->elf.dynobj, BLR, p);
+      p += 4;
+    }
 
-             p->count += 1;
-             if (!IS_ABSOLUTE_RELOC (r_type))
-               p->pc_count += 1;
-           }
-         break;
+  for (i = lowest_restf; i <= MAX_SAVE_FPR; i++)
+    {
+      unsigned int fpr = i << 21;
+      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
+      bfd_put_32 (htab->elf.dynobj, LFD_FR0_0R1 + fpr + stackoff, p);
+      p += 4;
+    }
+  if (lowest_restf <= MAX_SAVE_FPR
+      || htab->sfpr->_raw_size == 4)
+    {
+      bfd_put_32 (htab->elf.dynobj, BLR, p);
+    }
 
-       default:
+  return TRUE;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+
+static bfd_boolean
+ppc64_elf_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  struct ppc_link_hash_table *htab;
+  struct ppc_link_hash_entry * eh;
+  struct ppc_dyn_relocs *p;
+  asection *s;
+  unsigned int power_of_two;
+
+  htab = ppc_hash_table (info);
+
+  /* Deal with function syms.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      /* Clear procedure linkage table information for any symbol that
+        won't need a .plt entry.  */
+      struct plt_entry *ent;
+      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+       if (ent->plt.refcount > 0)
          break;
+      if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
+         || ent == NULL
+         || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
+         || (! info->shared
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+             && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
+       {
+         h->plt.plist = NULL;
+         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
        }
+      return TRUE;
+    }
+  else
+    h->plt.plist = NULL;
+
+  /* If this is a weak symbol, and there is a real definition, the
+     processor independent code will have arranged for us to see the
+     real definition first, and we can just use the same value.  */
+  if (h->weakdef != NULL)
+    {
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+                 || h->weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->weakdef->root.u.def.section;
+      h->root.u.def.value = h->weakdef->root.u.def.value;
+      return TRUE;
     }
 
-  return true;
-}
+  /* This is a reference to a symbol defined by a dynamic object which
+     is not a function.  */
+
+  /* If we are creating a shared library, we must presume that the
+     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 there are no references to this symbol that do not use the
+     GOT, we don't need to generate a copy reloc.  */
+  if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
+    return TRUE;
 
-/* Return the section that should be marked against GC for a given
-   relocation.  */
+  eh = (struct ppc_link_hash_entry *) h;
+  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+    {
+      s = p->sec->output_section;
+      if (s != NULL && (s->flags & SEC_READONLY) != 0)
+       break;
+    }
 
-static asection *
-ppc64_elf_gc_mark_hook (abfd, info, rel, h, sym)
-     bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     Elf_Internal_Rela *rel;
-     struct elf_link_hash_entry *h;
-     Elf_Internal_Sym *sym;
-{
-  if (h != NULL)
+  /* 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.  */
+  if (p == NULL)
     {
-      enum elf_ppc_reloc_type r_type;
+      h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+      return TRUE;
+    }
 
-      r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
-      switch (r_type)
-       {
-       case R_PPC64_GNU_VTINHERIT:
-       case R_PPC64_GNU_VTENTRY:
-         break;
+  /* We must allocate the symbol in our .dynbss section, which will
+     become part of the .bss section of the executable.  There will be
+     an entry for this symbol in the .dynsym section.  The dynamic
+     object will contain position independent code, so all references
+     from the dynamic object to this symbol will go through the global
+     offset table.  The dynamic linker will use the .dynsym entry to
+     determine the address it must put in the global offset table, so
+     both the dynamic object and the regular object will refer to the
+     same memory location for the variable.  */
 
-       default:
-         switch (h->root.type)
-           {
-           case bfd_link_hash_defined:
-           case bfd_link_hash_defweak:
-             return h->root.u.def.section;
+  /* We must generate a R_PPC64_COPY reloc to tell the dynamic linker
+     to copy the initial value out of the dynamic object and into the
+     runtime process image.  We need to remember the offset into the
+     .rela.bss section we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+    {
+      htab->srelbss->_raw_size += sizeof (Elf64_External_Rela);
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+    }
 
-           case bfd_link_hash_common:
-             return h->root.u.c.p->section;
+  /* We need to figure out the alignment required for this symbol.  I
+     have no idea how ELF linkers handle this.  */
+  power_of_two = bfd_log2 (h->size);
+  if (power_of_two > 4)
+    power_of_two = 4;
 
-           default:
-             break;
-           }
-       }
-    }
-  else
+  /* Apply the required alignment.  */
+  s = htab->sdynbss;
+  s->_raw_size = BFD_ALIGN (s->_raw_size, (bfd_size_type) (1 << power_of_two));
+  if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
     {
-      return bfd_section_from_elf_index (abfd, sym->st_shndx);
+      if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
+       return FALSE;
     }
 
-  return NULL;
-}
-
-/* Update the .got, .plt. and dynamic reloc reference counts for the
-   section being removed.  */
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->_raw_size;
 
-static boolean
-ppc64_elf_gc_sweep_hook (abfd, info, sec, relocs)
-     bfd *abfd;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     asection *sec;
-     const Elf_Internal_Rela *relocs;
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
+  /* Increment the section size to make room for the symbol.  */
+  s->_raw_size += h->size;
 
-  elf_section_data (sec)->local_dynrel = NULL;
+  return TRUE;
+}
 
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+/* If given a function descriptor symbol, hide both the function code
+   sym and the descriptor.  */
+static void
+ppc64_elf_hide_symbol (info, h, force_local)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     bfd_boolean force_local;
+{
+  _bfd_elf_link_hash_hide_symbol (info, h, force_local);
 
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
+  if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
     {
-      unsigned long r_symndx;
-      enum elf_ppc_reloc_type r_type;
-      struct elf_link_hash_entry *h;
+      struct elf_link_hash_entry *fh = ((struct ppc_link_hash_entry *) h)->oh;
 
-      r_symndx = ELF64_R_SYM (rel->r_info);
-      r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
-      switch (r_type)
+      if (fh == NULL)
        {
-       case R_PPC64_GOT16:
-       case R_PPC64_GOT16_DS:
-       case R_PPC64_GOT16_HA:
-       case R_PPC64_GOT16_HI:
-       case R_PPC64_GOT16_LO:
-       case R_PPC64_GOT16_LO_DS:
-         if (r_symndx >= symtab_hdr->sh_info)
-           {
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             if (h->got.refcount > 0)
-               h->got.refcount--;
-           }
-         else
-           {
-             if (local_got_refcounts[r_symndx] > 0)
-               local_got_refcounts[r_symndx]--;
-           }
-         break;
+         const char *p, *q;
+         struct ppc_link_hash_table *htab;
+         char save;
 
-       case R_PPC64_PLT16_HA:
-       case R_PPC64_PLT16_HI:
-       case R_PPC64_PLT16_LO:
-       case R_PPC64_PLT32:
-       case R_PPC64_PLT64:
-         if (r_symndx >= symtab_hdr->sh_info)
-           {
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             if (h->plt.refcount > 0)
-               h->plt.refcount--;
-           }
-         break;
+         /* We aren't supposed to use alloca in BFD because on
+            systems which do not have alloca the version in libiberty
+            calls xmalloc, which might cause the program to crash
+            when it runs out of memory.  This function doesn't have a
+            return status, so there's no way to gracefully return an
+            error.  So cheat.  We know that string[-1] can be safely
+            dereferenced;  It's either a string in an ELF string
+            table, or allocated in an objalloc structure.  */
 
-       case R_PPC64_REL14:
-       case R_PPC64_REL14_BRNTAKEN:
-       case R_PPC64_REL14_BRTAKEN:
-       case R_PPC64_REL24:
-         if (r_symndx >= symtab_hdr->sh_info)
-           {
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             if (h->plt.refcount > 0)
-               h->plt.refcount--;
-           }
-         break;
+         p = h->root.root.string - 1;
+         save = *p;
+         *(char *) p = '.';
+         htab = ppc_hash_table (info);
+         fh = elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
+         *(char *) p = save;
 
-       case R_PPC64_REL32:
-       case R_PPC64_REL64:
-         if (r_symndx >= symtab_hdr->sh_info)
+         /* Unfortunately, if it so happens that the string we were
+            looking for was allocated immediately before this string,
+            then we overwrote the string terminator.  That's the only
+            reason the lookup should fail.  */
+         if (fh == NULL)
            {
-             struct ppc_link_hash_entry *eh;
-             struct ppc_dyn_relocs **pp;
-             struct ppc_dyn_relocs *p;
-
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             eh = (struct ppc_link_hash_entry *) h;
-
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-               if (p->sec == sec)
-                 {
-                   p->pc_count -= 1;
-                   p->count -= 1;
-                   if (p->count == 0)
-                     *pp = p->next;
-                   break;
-                 }
+             q = h->root.root.string + strlen (h->root.root.string);
+             while (q >= h->root.root.string && *q == *p)
+               --q, --p;
+             if (q < h->root.root.string && *p == '.')
+               fh = elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
            }
-         break;
-
-       case R_PPC64_ADDR14:
-       case R_PPC64_ADDR14_BRNTAKEN:
-       case R_PPC64_ADDR14_BRTAKEN:
-       case R_PPC64_ADDR16:
-       case R_PPC64_ADDR16_DS:
-       case R_PPC64_ADDR16_HA:
-       case R_PPC64_ADDR16_HI:
-       case R_PPC64_ADDR16_HIGHER:
-       case R_PPC64_ADDR16_HIGHERA:
-       case R_PPC64_ADDR16_HIGHEST:
-       case R_PPC64_ADDR16_HIGHESTA:
-       case R_PPC64_ADDR16_LO:
-       case R_PPC64_ADDR16_LO_DS:
-       case R_PPC64_ADDR24:
-       case R_PPC64_ADDR30:
-       case R_PPC64_ADDR32:
-       case R_PPC64_ADDR64:
-       case R_PPC64_UADDR16:
-       case R_PPC64_UADDR32:
-       case R_PPC64_UADDR64:
-       case R_PPC64_TOC:
-         if (r_symndx >= symtab_hdr->sh_info)
+         if (fh != NULL)
            {
-             struct ppc_link_hash_entry *eh;
-             struct ppc_dyn_relocs **pp;
-             struct ppc_dyn_relocs *p;
-
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             eh = (struct ppc_link_hash_entry *) h;
-
-             for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
-               if (p->sec == sec)
-                 {
-                   p->count -= 1;
-                   if (p->count == 0)
-                     *pp = p->next;
-                   break;
-                 }
+             ((struct ppc_link_hash_entry *) h)->oh = fh;
+             ((struct ppc_link_hash_entry *) fh)->oh = h;
            }
-         break;
-
-       default:
-         break;
        }
+      if (fh != NULL)
+       _bfd_elf_link_hash_hide_symbol (info, fh, force_local);
     }
-  return true;
 }
 
-/* Called via elf_link_hash_traverse to transfer dynamic linking
-   information on function code symbol entries to their corresponding
-   function descriptor symbol entries.  */
-static boolean
-func_desc_adjust (h, inf)
-     struct elf_link_hash_entry *h;
-     PTR inf;
+static bfd_boolean
+get_sym_h (hp, symp, symsecp, tlstypep, locsymsp, r_symndx, ibfd)
+     struct elf_link_hash_entry **hp;
+     Elf_Internal_Sym **symp;
+     asection **symsecp;
+     char **tlstypep;
+     Elf_Internal_Sym **locsymsp;
+     unsigned long r_symndx;
+     bfd *ibfd;
 {
-  struct bfd_link_info *info;
-  struct ppc_link_hash_table *htab;
+  Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
 
-  if (h->root.type == bfd_link_hash_indirect)
-    return true;
+  if (r_symndx >= symtab_hdr->sh_info)
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+            || h->root.type == bfd_link_hash_warning)
+       h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  info = (struct bfd_link_info *) inf;
-  htab = ppc_hash_table (info);
+      if (hp != NULL)
+       *hp = h;
 
-  /* If this is a function code symbol, transfer dynamic linking
-     information to the function descriptor symbol.  */
-  if (!((struct ppc_link_hash_entry *) h)->is_func)
-    return true;
+      if (symp != NULL)
+       *symp = NULL;
+
+      if (symsecp != NULL)
+       {
+         asection *symsec = NULL;
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+           symsec = h->root.u.def.section;
+         *symsecp = symsec;
+       }
 
-  if (h->root.type == bfd_link_hash_undefweak
-      && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
-    htab->have_undefweak = true;
+      if (tlstypep != NULL)
+       {
+         struct ppc_link_hash_entry *eh;
 
-  if (h->plt.refcount > 0
-      && h->root.root.string[0] == '.'
-      && h->root.root.string[1] != '\0')
+         eh = (struct ppc_link_hash_entry *) h;
+         *tlstypep = &eh->tls_type;
+       }
+    }
+  else
     {
-      struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh;
-      boolean force_local;
-
-      /* Find the corresponding function descriptor symbol.  Create it
-        as undefined if necessary.  */
-
-      if (fdh == NULL)
-       fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
-                                   false, false, true);
+      Elf_Internal_Sym *sym;
+      Elf_Internal_Sym *locsyms = *locsymsp;
 
-      if (fdh == NULL
-         && info->shared
-         && (h->root.type == bfd_link_hash_undefined
-             || h->root.type == bfd_link_hash_undefweak))
+      if (locsyms == NULL)
        {
-         bfd *abfd;
-         asymbol *newsym;
+         locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
+         if (locsyms == NULL)
+           locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr,
+                                           symtab_hdr->sh_info,
+                                           0, NULL, NULL, NULL);
+         if (locsyms == NULL)
+           return FALSE;
+         *locsymsp = locsyms;
+       }
+      sym = locsyms + r_symndx;
 
-         abfd = h->root.u.undef.abfd;
-         newsym = bfd_make_empty_symbol (abfd);
-         newsym->name = h->root.root.string + 1;
-         newsym->section = bfd_und_section_ptr;
-         newsym->value = 0;
-         newsym->flags = BSF_OBJECT;
-         if (h->root.type == bfd_link_hash_undefweak)
-           newsym->flags |= BSF_WEAK;
+      if (hp != NULL)
+       *hp = NULL;
 
-         if ( !(_bfd_generic_link_add_one_symbol
-                (info, abfd, newsym->name, newsym->flags,
-                 newsym->section, newsym->value, NULL, false, false,
-                 (struct bfd_link_hash_entry **) &fdh)))
-           {
-             return false;
-           }
-         fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+      if (symp != NULL)
+       *symp = sym;
+
+      if (symsecp != NULL)
+       {
+         asection *symsec = NULL;
+         if ((sym->st_shndx != SHN_UNDEF
+              && sym->st_shndx < SHN_LORESERVE)
+             || sym->st_shndx > SHN_HIRESERVE)
+           symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
+         *symsecp = symsec;
        }
 
-      if (fdh != NULL
-         && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
-         && (info->shared
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
-             || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0))
+      if (tlstypep != NULL)
        {
-         if (fdh->dynindx == -1)
-           if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
-             return false;
-         fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
-                                      & (ELF_LINK_HASH_REF_REGULAR
-                                         | ELF_LINK_HASH_REF_DYNAMIC
-                                         | ELF_LINK_HASH_REF_REGULAR_NONWEAK
-                                         | ELF_LINK_NON_GOT_REF));
-         if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+         struct got_entry **lgot_ents;
+         char *tlstype;
+
+         tlstype = NULL;
+         lgot_ents = elf_local_got_ents (ibfd);
+         if (lgot_ents != NULL)
            {
-             fdh->plt.refcount = h->plt.refcount;
-             fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+             char *lgot_types = (char *) (lgot_ents + symtab_hdr->sh_info);
+             tlstype = &lgot_types[r_symndx];
            }
-         ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
-         ((struct ppc_link_hash_entry *) fdh)->oh = h;
-         ((struct ppc_link_hash_entry *) h)->oh = fdh;
+         *tlstypep = tlstype;
        }
-
-      /* Now that the info is on the function descriptor, clear the
-        function code sym info.  Any function code syms for which we
-        don't have a definition in a regular file, we force local.
-        This prevents a shared library from exporting syms that have
-        been imported from another library.  Function code syms that
-        are really in the library we must leave global to prevent the
-        linker dragging in a definition from a static library.  */
-      force_local = (info->shared
-                    && ((h->elf_link_hash_flags
-                         & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || fdh == NULL
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_HASH_DEF_REGULAR) == 0
-                        || (fdh->elf_link_hash_flags
-                            & ELF_LINK_FORCED_LOCAL) != 0));
-      _bfd_elf_link_hash_hide_symbol (info, h, force_local);
     }
-
-  return true;
+  return TRUE;
 }
 
-#define MIN_SAVE_FPR 14
-#define MAX_SAVE_FPR 31
-
-/* Called near the start of bfd_elf_size_dynamic_sections.  We use
-   this hook to a) provide some gcc support functions, and b) transfer
-   dynamic linking information gathered so far on function code symbol
-   entries, to their corresponding function descriptor symbol entries.  */
-static boolean
-ppc64_elf_func_desc_adjust (obfd, info)
-     bfd *obfd ATTRIBUTE_UNUSED;
-     struct bfd_link_info *info;
+static bfd_boolean
+get_tls_type (tls_type, locsymsp, rel, ibfd)
+     char **tls_type;
+     Elf_Internal_Sym **locsymsp;
+     const Elf_Internal_Rela *rel;
+     bfd *ibfd;
 {
-  struct ppc_link_hash_table *htab;
-  unsigned int lowest_savef = MAX_SAVE_FPR + 2;
-  unsigned int lowest_restf = MAX_SAVE_FPR + 2;
-  unsigned int i;
+  unsigned long r_symndx;
   struct elf_link_hash_entry *h;
-  bfd_byte *p;
-  char sym[10];
+  Elf_Internal_Sym *sym;
+  asection *sec;
+  bfd_vma off;
 
-  htab = ppc_hash_table (info);
+  r_symndx = ELF64_R_SYM (rel->r_info);
+  if (!get_sym_h (&h, &sym, &sec, tls_type, locsymsp, r_symndx, ibfd))
+    return FALSE;
 
-  if (htab->sfpr == NULL)
-    /* We don't have any relocs.  */
-    return true;
+  if ((*tls_type != NULL && **tls_type != 0)
+      || sec == NULL
+      || ppc64_elf_section_data (sec)->t_symndx == NULL)
+    return TRUE;
 
-  /* First provide any missing ._savef* and ._restf* functions.  */
-  memcpy (sym, "._savef14", 10);
-  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+  /* Look inside a TOC section too.  */
+  if (h != NULL)
     {
-      sym[7] = i / 10 + '0';
-      sym[8] = i % 10 + '0';
-      h = elf_link_hash_lookup (&htab->elf, sym, false, false, true);
-      if (h != NULL
-         && h->root.type == bfd_link_hash_undefined)
-       {
-         if (lowest_savef > i)
-           lowest_savef = i;
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = htab->sfpr;
-         h->root.u.def.value = (i - lowest_savef) * 4;
-         h->type = STT_FUNC;
-         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-         _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
-       }
+      BFD_ASSERT (h->root.type == bfd_link_hash_defined);
+      off = h->root.u.def.value;
     }
+  else
+    off = sym->st_value;
+  off += rel->r_addend;
+  BFD_ASSERT (off % 8 == 0);
+  r_symndx = ppc64_elf_section_data (sec)->t_symndx[off / 8];
+  return get_sym_h (&h, &sym, NULL, tls_type, locsymsp, r_symndx, ibfd);
+}
 
-  memcpy (sym, "._restf14", 10);
-  for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
+bfd_boolean
+ppc64_elf_edit_opd (obfd, info)
+     bfd *obfd;
+     struct bfd_link_info *info;
+{
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
-      sym[7] = i / 10 + '0';
-      sym[8] = i % 10 + '0';
-      h = elf_link_hash_lookup (&htab->elf, sym, false, false, true);
-      if (h != NULL
-         && h->root.type == bfd_link_hash_undefined)
+      asection *sec;
+      Elf_Internal_Rela *relstart, *rel, *relend;
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      struct elf_link_hash_entry **sym_hashes;
+      bfd_vma offset;
+      bfd_size_type amt;
+      long *adjust;
+      bfd_boolean need_edit;
+
+      sec = bfd_get_section_by_name (ibfd, ".opd");
+      if (sec == NULL)
+       continue;
+
+      amt = sec->_raw_size * sizeof (long) / 24;
+      adjust = ppc64_elf_section_data (sec)->opd.adjust;
+      if (adjust == NULL)
        {
-         if (lowest_restf > i)
-           lowest_restf = i;
-         h->root.type = bfd_link_hash_defined;
-         h->root.u.def.section = htab->sfpr;
-         h->root.u.def.value = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
-                                + (i - lowest_restf) * 4);
-         h->type = STT_FUNC;
-         h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
-         _bfd_elf_link_hash_hide_symbol (info, h, info->shared);
+         /* Must be a ld -r link.  ie. check_relocs hasn't been
+            called.  */
+         adjust = (long *) bfd_zalloc (obfd, amt);
+         ppc64_elf_section_data (sec)->opd.adjust = adjust;
        }
-    }
+      memset (adjust, 0, (size_t) amt);
 
-  elf_link_hash_traverse (&htab->elf, func_desc_adjust, (PTR) info);
+      if (sec->output_section == bfd_abs_section_ptr)
+       continue;
 
-  htab->sfpr->_raw_size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
-                          + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
+      /* Look through the section relocs.  */
+      if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0)
+       continue;
 
-  if (htab->sfpr->_raw_size == 0)
-    {
-      if (!htab->have_undefweak)
+      local_syms = NULL;
+      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+      sym_hashes = elf_sym_hashes (ibfd);
+
+      /* Read the relocations.  */
+      relstart = _bfd_elf64_link_read_relocs (ibfd, sec, (PTR) NULL,
+                                             (Elf_Internal_Rela *) NULL,
+                                             info->keep_memory);
+      if (relstart == NULL)
+       return FALSE;
+
+      /* First run through the relocs to check they are sane, and to
+        determine whether we need to edit this opd section.  */
+      need_edit = FALSE;
+      offset = 0;
+      relend = relstart + sec->reloc_count;
+      for (rel = relstart; rel < relend; rel++)
        {
-         _bfd_strip_section_from_output (info, htab->sfpr);
-         return true;
-       }
+         enum elf_ppc64_reloc_type r_type;
+         unsigned long r_symndx;
+         asection *sym_sec;
+         struct elf_link_hash_entry *h;
+         Elf_Internal_Sym *sym;
+
+         /* .opd contains a regular array of 24 byte entries.  We're
+            only interested in the reloc pointing to a function entry
+            point.  */
+         r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
+         if (r_type == R_PPC64_TOC)
+           continue;
 
-      htab->sfpr->_raw_size = 4;
-    }
+         if (r_type != R_PPC64_ADDR64)
+           {
+             (*_bfd_error_handler)
+               (_("%s: unexpected reloc type %u in .opd section"),
+                bfd_archive_filename (ibfd), r_type);
+             need_edit = FALSE;
+             break;
+           }
 
-  p = (bfd_byte *) bfd_alloc (htab->elf.dynobj, htab->sfpr->_raw_size);
-  if (p == NULL)
-    return false;
-  htab->sfpr->contents = p;
+         if (rel + 1 >= relend)
+           continue;
+         r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE ((rel + 1)->r_info);
+         if (r_type != R_PPC64_TOC)
+           continue;
 
-  for (i = lowest_savef; i <= MAX_SAVE_FPR; i++)
-    {
-      unsigned int fpr = i << 21;
-      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
-      bfd_put_32 (htab->elf.dynobj, STFD_FR0_0R1 + fpr + stackoff, p);
-      p += 4;
-    }
-  if (lowest_savef <= MAX_SAVE_FPR)
-    {
-      bfd_put_32 (htab->elf.dynobj, BLR, p);
-      p += 4;
-    }
+         if (rel->r_offset != offset)
+           {
+             /* If someone messes with .opd alignment then after a
+                "ld -r" we might have padding in the middle of .opd.
+                Also, there's nothing to prevent someone putting
+                something silly in .opd with the assembler.  No .opd
+                optimization for them!  */
+             (*_bfd_error_handler)
+               (_("%s: .opd is not a regular array of opd entries"),
+                bfd_archive_filename (ibfd));
+             need_edit = FALSE;
+             break;
+           }
 
-  for (i = lowest_restf; i <= MAX_SAVE_FPR; i++)
-    {
-      unsigned int fpr = i << 21;
-      unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
-      bfd_put_32 (htab->elf.dynobj, LFD_FR0_0R1 + fpr + stackoff, p);
-      p += 4;
-    }
-  if (lowest_restf <= MAX_SAVE_FPR
-      || htab->sfpr->_raw_size == 4)
-    {
-      bfd_put_32 (htab->elf.dynobj, BLR, p);
-    }
+         r_symndx = ELF64_R_SYM (rel->r_info);
+         if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                         r_symndx, ibfd))
+           goto error_free_rel;
 
-  return true;
-}
+         if (sym_sec == NULL || sym_sec->owner == NULL)
+           {
+             const char *sym_name;
+             if (h != NULL)
+               sym_name = h->root.root.string;
+             else
+               sym_name = bfd_elf_local_sym_name (ibfd, sym);
 
-/* Adjust a symbol defined by a dynamic object and referenced by a
-   regular object.  The current definition is in some section of the
-   dynamic object, but we're not including those sections.  We have to
-   change the definition to something the rest of the link can
-   understand.  */
+             (*_bfd_error_handler)
+               (_("%s: undefined sym `%s' in .opd section"),
+                bfd_archive_filename (ibfd),
+                sym_name);
+             need_edit = FALSE;
+             break;
+           }
 
-static boolean
-ppc64_elf_adjust_dynamic_symbol (info, h)
-     struct bfd_link_info *info;
-     struct elf_link_hash_entry *h;
-{
-  struct ppc_link_hash_table *htab;
-  struct ppc_link_hash_entry * eh;
-  struct ppc_dyn_relocs *p;
-  asection *s;
-  unsigned int power_of_two;
+         /* opd entries are always for functions defined in the
+            current input bfd.  If the symbol isn't defined in the
+            input bfd, then we won't be using the function in this
+            bfd;  It must be defined in a linkonce section in another
+            bfd, or is weak.  It's also possible that we are
+            discarding the function due to a linker script /DISCARD/,
+            which we test for via the output_section.  */
+         if (sym_sec->owner != ibfd
+             || sym_sec->output_section == bfd_abs_section_ptr)
+           need_edit = TRUE;
+
+         offset += 24;
+       }
 
-  htab = ppc_hash_table (info);
+      if (need_edit)
+       {
+         Elf_Internal_Rela *write_rel;
+         bfd_byte *rptr, *wptr;
+         bfd_boolean skip;
+
+         /* This seems a waste of time as input .opd sections are all
+            zeros as generated by gcc, but I suppose there's no reason
+            this will always be so.  We might start putting something in
+            the third word of .opd entries.  */
+         if ((sec->flags & SEC_IN_MEMORY) == 0)
+           {
+             bfd_byte *loc = bfd_alloc (ibfd, sec->_raw_size);
+             if (loc == NULL
+                 || !bfd_get_section_contents (ibfd, sec, loc, (bfd_vma) 0,
+                                               sec->_raw_size))
+               {
+                 if (local_syms != NULL
+                     && symtab_hdr->contents != (unsigned char *) local_syms)
+                   free (local_syms);
+               error_free_rel:
+                 if (elf_section_data (sec)->relocs != relstart)
+                   free (relstart);
+                 return FALSE;
+               }
+             sec->contents = loc;
+             sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS);
+           }
 
-  /* Deal with function syms.  */
-  if (h->type == STT_FUNC
-      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
-    {
-      /* Clear procedure linkage table information for any symbol that
-        won't need a .plt entry.  */
-      if (!((struct ppc_link_hash_entry *) h)->is_func_descriptor
-         || h->plt.refcount <= 0
-         || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0
-         || (! info->shared
-             && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
-             && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0))
+         elf_section_data (sec)->relocs = relstart;
+
+         wptr = sec->contents;
+         rptr = sec->contents;
+         write_rel = relstart;
+         skip = FALSE;
+         offset = 0;
+         for (rel = relstart; rel < relend; rel++)
+           {
+             if (rel->r_offset == offset)
+               {
+                 unsigned long r_symndx;
+                 asection *sym_sec;
+                 struct elf_link_hash_entry *h;
+                 Elf_Internal_Sym *sym;
+
+                 r_symndx = ELF64_R_SYM (rel->r_info);
+                 get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                            r_symndx, ibfd);
+
+                 skip = (sym_sec->owner != ibfd
+                         || sym_sec->output_section == bfd_abs_section_ptr);
+                 if (skip)
+                   {
+                     if (h != NULL && sym_sec->owner == ibfd)
+                       {
+                         /* Arrange for the function descriptor sym
+                            to be dropped.  */
+                         struct ppc_link_hash_entry *fdh;
+                         struct ppc_link_hash_entry *fh;
+
+                         fh = (struct ppc_link_hash_entry *) h;
+                         fdh = (struct ppc_link_hash_entry *) fh->oh;
+                         if (fdh == NULL)
+                           {
+                             const char *fd_name;
+                             struct ppc_link_hash_table *htab;
+
+                             fd_name = h->root.root.string + 1;
+                             htab = ppc_hash_table (info);
+                             fdh = (struct ppc_link_hash_entry *)
+                               elf_link_hash_lookup (&htab->elf, fd_name,
+                                                     FALSE, FALSE, FALSE);
+                             fdh->is_func_descriptor = 1;
+                             fdh->oh = &fh->elf;
+                             fh->is_func = 1;
+                             fh->oh = &fdh->elf;
+                           }
+
+                         fdh->elf.root.u.def.value = 0;
+                         fdh->elf.root.u.def.section = sym_sec;
+                       }
+                   }
+                 else
+                   {
+                     /* We'll be keeping this opd entry.  */
+
+                     if (h != NULL)
+                       {
+                         /* Redefine the function descriptor symbol
+                            to this location in the opd section.
+                            We've checked above that opd relocs are
+                            ordered.  */
+                         struct ppc_link_hash_entry *fdh;
+                         struct ppc_link_hash_entry *fh;
+
+                         fh = (struct ppc_link_hash_entry *) h;
+                         fdh = (struct ppc_link_hash_entry *) fh->oh;
+                         if (fdh == NULL)
+                           {
+                             const char *fd_name;
+                             struct ppc_link_hash_table *htab;
+
+                             fd_name = h->root.root.string + 1;
+                             htab = ppc_hash_table (info);
+                             fdh = (struct ppc_link_hash_entry *)
+                               elf_link_hash_lookup (&htab->elf, fd_name,
+                                                     FALSE, FALSE, FALSE);
+                             fdh->is_func_descriptor = 1;
+                             fdh->oh = &fh->elf;
+                             fh->is_func = 1;
+                             fh->oh = &fdh->elf;
+                           }
+
+                         fdh->elf.root.u.def.value = wptr - sec->contents;
+                       }
+                     else
+                       {
+                         /* Local syms are a bit tricky.  We could
+                            tweak them as they can be cached, but
+                            we'd need to look through the local syms
+                            for the function descriptor sym which we
+                            don't have at the moment.  So keep an
+                            array of adjustments.  */
+                         adjust[rel->r_offset / 24] = wptr - rptr;
+                       }
+
+                     if (wptr != rptr)
+                       memcpy (wptr, rptr, 24);
+                     wptr += 24;
+                   }
+                 rptr += 24;
+                 offset += 24;
+               }
+
+             /* We need to adjust any reloc offsets to point to the
+                new opd entries.  While we're at it, we may as well
+                remove redundant relocs.  */
+             if (!skip)
+               {
+                 rel->r_offset += wptr - rptr;
+                 if (write_rel != rel)
+                   memcpy (write_rel, rel, sizeof (*rel));
+                 ++write_rel;
+               }
+           }
+
+         sec->_cooked_size = wptr - sec->contents;
+         sec->reloc_count = write_rel - relstart;
+         /* Fudge the size too, as this is used later in
+            elf_bfd_final_link if we are emitting relocs.  */
+         elf_section_data (sec)->rel_hdr.sh_size
+           = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
+         BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
+       }
+      else if (elf_section_data (sec)->relocs != relstart)
+       free (relstart);
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
        {
-         h->plt.offset = (bfd_vma) -1;
-         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
        }
-      return true;
     }
-  else
-    h->plt.offset = (bfd_vma) -1;
 
-  /* If this is a weak symbol, and there is a real definition, the
-     processor independent code will have arranged for us to see the
-     real definition first, and we can just use the same value.  */
-  if (h->weakdef != NULL)
-    {
-      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
-                 || h->weakdef->root.type == bfd_link_hash_defweak);
-      h->root.u.def.section = h->weakdef->root.u.def.section;
-      h->root.u.def.value = h->weakdef->root.u.def.value;
-      return true;
-    }
+  return TRUE;
+}
 
-  /* This is a reference to a symbol defined by a dynamic object which
-     is not a function.  */
+/* Run through all the TLS relocs looking for optimization
+   opportunities.  The linker has been hacked (see ppc64elf.em) to do
+   a preliminary section layout so that we know the TLS segment
+   offsets.  We can't optimize earlier because some optimizations need
+   to know the tp offset, and we need to optimize before allocating
+   dynamic relocations.  */
 
-  /* If we are creating a shared library, we must presume that the
-     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;
+bfd_boolean
+ppc64_elf_tls_optimize (obfd, info)
+     bfd *obfd;
+     struct bfd_link_info *info;
+{
+  asection *tls;
+  bfd *ibfd;
+  asection *sec;
+  struct ppc_link_hash_table *htab;
 
-  /* 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->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0)
-    return true;
+  if (info->relocateable)
+    return TRUE;
 
-  eh = (struct ppc_link_hash_entry *) h;
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      s = p->sec->output_section;
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
-       break;
-    }
+  for (tls = obfd->sections; tls != NULL; tls = tls->next)
+    if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
+       == (SEC_THREAD_LOCAL | SEC_LOAD))
+      break;
+  if (tls == NULL)
+    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.  */
-  if (p == NULL)
-    {
-      h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
-      return true;
-    }
+  htab = ppc_hash_table (info);
+  htab->tls_sec = tls;
 
-  /* We must allocate the symbol in our .dynbss section, which will
-     become part of the .bss section of the executable.  There will be
-     an entry for this symbol in the .dynsym section.  The dynamic
-     object will contain position independent code, so all references
-     from the dynamic object to this symbol will go through the global
-     offset table.  The dynamic linker will use the .dynsym entry to
-     determine the address it must put in the global offset table, so
-     both the dynamic object and the regular object will refer to the
-     same memory location for the variable.  */
+  if (info->shared)
+    return TRUE;
 
-  /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to
-     copy the initial value out of the dynamic object and into the
-     runtime process image.  We need to remember the offset into the
-     .rela.bss section we are going to use.  */
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
-      htab->srelbss->_raw_size += sizeof (Elf64_External_Rela);
-      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
-    }
+      Elf_Internal_Sym *locsyms = NULL;
 
-  /* We need to figure out the alignment required for this symbol.  I
-     have no idea how ELF linkers handle this.  */
-  power_of_two = bfd_log2 (h->size);
-  if (power_of_two > 4)
-    power_of_two = 4;
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
+         {
+           Elf_Internal_Rela *relstart, *rel, *relend;
+           int expecting_tls_get_addr;
+
+           /* Read the relocations.  */
+           relstart = _bfd_elf64_link_read_relocs (ibfd, sec, (PTR) NULL,
+                                                   (Elf_Internal_Rela *) NULL,
+                                                   info->keep_memory);
+           if (relstart == NULL)
+             return FALSE;
+
+           expecting_tls_get_addr = 0;
+           relend = relstart + sec->reloc_count;
+           for (rel = relstart; rel < relend; rel++)
+             {
+               enum elf_ppc64_reloc_type r_type;
+               unsigned long r_symndx;
+               struct elf_link_hash_entry *h;
+               Elf_Internal_Sym *sym;
+               asection *sym_sec;
+               char *tls_type;
+               char tls_set, tls_clear, got_tls_type = 0;
+               bfd_vma value;
+               bfd_boolean ok_tprel;
+
+               r_symndx = ELF64_R_SYM (rel->r_info);
+               if (!get_sym_h (&h, &sym, &sym_sec, &tls_type, &locsyms,
+                               r_symndx, ibfd))
+                 {
+                 err_free_rel:
+                   if (elf_section_data (sec)->relocs != relstart)
+                     free (relstart);
+                   if (locsyms != NULL
+                       && (elf_tdata (ibfd)->symtab_hdr.contents
+                           != (unsigned char *) locsyms))
+                     free (locsyms);
+                   return FALSE;
+                 }
 
-  /* Apply the required alignment.  */
-  s = htab->sdynbss;
-  s->_raw_size = BFD_ALIGN (s->_raw_size, (bfd_size_type) (1 << power_of_two));
-  if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
-    {
-      if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
-       return false;
-    }
+               if (h != NULL)
+                 {
+                   if (h->root.type != bfd_link_hash_defined
+                       && h->root.type != bfd_link_hash_defweak)
+                     continue;
+                   value = h->root.u.def.value;
+                 }
+               else
+                 value = sym->st_value;
+               ok_tprel = FALSE;
+               if (sym_sec != NULL && sym_sec->output_section != NULL)
+                 {
+                   value += sym_sec->output_offset;
+                   value += sym_sec->output_section->vma;
+                   value -= htab->tls_sec->vma;
+                   ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
+                               < (bfd_vma) 1 << 32);
+                 }
 
-  /* Define the symbol as being at this point in the section.  */
-  h->root.u.def.section = s;
-  h->root.u.def.value = s->_raw_size;
+               r_type
+                 = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
+               switch (r_type)
+                 {
+                 case R_PPC64_GOT_TLSLD16:
+                 case R_PPC64_GOT_TLSLD16_LO:
+                 case R_PPC64_GOT_TLSLD16_HI:
+                 case R_PPC64_GOT_TLSLD16_HA:
+                   htab->tlsld_got.refcount -= 1;
+                   if (ok_tprel)
+                     /* LD -> LE */
+                     tls_set = 0;
+                   else
+                     /* We still need a GOT entry as the offset is
+                        too big.  ie. LD -> IE.  */
+                     tls_set = TLS_TLS | TLS_TPREL;
+                   tls_clear = TLS_GD_LD;
+                   got_tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+                   expecting_tls_get_addr = 1;
+                   break;
 
-  /* Increment the section size to make room for the symbol.  */
-  s->_raw_size += h->size;
+                 case R_PPC64_GOT_TLSGD16:
+                 case R_PPC64_GOT_TLSGD16_LO:
+                 case R_PPC64_GOT_TLSGD16_HI:
+                 case R_PPC64_GOT_TLSGD16_HA:
+                   if (ok_tprel
+                       && (h == NULL
+                           || ((h->elf_link_hash_flags
+                                & ELF_LINK_HASH_DEF_REGULAR) != 0
+                               && ((h->elf_link_hash_flags
+                                    & ELF_LINK_FORCED_LOCAL) != 0
+                                   || !info->shared
+                                   || info->symbolic))))
+                     /* GD -> LE */
+                     tls_set = 0;
+                   else
+                     /* GD -> IE */
+                     tls_set = TLS_TLS | TLS_TPREL;
+                   tls_clear = TLS_GD_LD;
+                   got_tls_type = TLS_TLS | TLS_GD_LD;
+                   expecting_tls_get_addr = 1;
+                   break;
 
-  return true;
-}
+                 case R_PPC64_GOT_TPREL16_DS:
+                 case R_PPC64_GOT_TPREL16_LO_DS:
+                 case R_PPC64_GOT_TPREL16_HI:
+                 case R_PPC64_GOT_TPREL16_HA:
+                   expecting_tls_get_addr = 0;
+                   if (ok_tprel)
+                     {
+                       /* IE -> LE */
+                       tls_set = 0;
+                       tls_clear = TLS_TPREL;
+                       got_tls_type = TLS_TLS | TLS_TPREL;
+                       break;
+                     }
+                   else
+                     continue;
 
-/* If given a function descriptor symbol, hide both the function code
-   sym and the descriptor.  */
-static void
-ppc64_elf_hide_symbol (info, h, force_local)
-     struct bfd_link_info *info;
-     struct elf_link_hash_entry *h;
-     boolean force_local;
-{
-  _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+                 case R_PPC64_REL14:
+                 case R_PPC64_REL14_BRTAKEN:
+                 case R_PPC64_REL14_BRNTAKEN:
+                 case R_PPC64_REL24:
+                   if (h != NULL
+                       && h == htab->tls_get_addr)
+                     {
+                       if (!expecting_tls_get_addr
+                           && rel != relstart
+                           && ((ELF64_R_TYPE (rel[-1].r_info)
+                                == R_PPC64_TOC16)
+                               || (ELF64_R_TYPE (rel[-1].r_info)
+                                   == R_PPC64_TOC16_LO)))
+                         {
+                           /* Check for toc tls entries.  */
+                           char *toc_tls;
+
+                           if (!get_tls_type (&toc_tls, &locsyms,
+                                              rel - 1, ibfd))
+                             goto err_free_rel;
+                           if (toc_tls != NULL)
+                             expecting_tls_get_addr = *toc_tls != 0;
+                         }
+
+                       if (expecting_tls_get_addr)
+                         {
+                           struct plt_entry *ent;
+                           for (ent = h->plt.plist; ent; ent = ent->next)
+                             if (ent->addend == 0)
+                               {
+                                 if (ent->plt.refcount > 0)
+                                   ent->plt.refcount -= 1;
+                                 break;
+                               }
+                         }
+                     }
+                   expecting_tls_get_addr = 0;
+                   continue;
 
-  if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
-    {
-      struct elf_link_hash_entry *fh = ((struct ppc_link_hash_entry *) h)->oh;
+                 case R_PPC64_TPREL64:
+                   expecting_tls_get_addr = 0;
+                   if (ok_tprel)
+                     {
+                       /* IE -> LE */
+                       tls_set = TLS_EXPLICIT;
+                       tls_clear = TLS_TPREL;
+                       break;
+                     }
+                   else
+                     continue;
 
-      if (fh == NULL)
-       {
-         const char *p, *q;
-         struct ppc_link_hash_table *htab;
-         char save;
+                 case R_PPC64_DTPMOD64:
+                   expecting_tls_get_addr = 0;
+                   if ((*tls_type & TLS_LD) == 0)
+                     {
+                       if ((h == NULL
+                            || ((h->elf_link_hash_flags
+                                 & ELF_LINK_HASH_DEF_REGULAR) != 0
+                                && ((h->elf_link_hash_flags
+                                     & ELF_LINK_FORCED_LOCAL) != 0
+                                    || !info->shared
+                                    || info->symbolic)))
+                           && ok_tprel)
+                         /* GD -> LE */
+                         tls_set = TLS_EXPLICIT;
+                       else
+                         /* GD -> IE */
+                         tls_set = TLS_EXPLICIT | TLS_TPREL;
+                       tls_clear = TLS_GD_LD;
+                     }
+                   else
+                     {
+                       if (ok_tprel)
+                         /* LD -> LE */
+                         tls_set = TLS_EXPLICIT;
+                       else
+                         /* LD -> IE */
+                         tls_set = TLS_EXPLICIT | TLS_TPREL;
+                       tls_clear = TLS_GD_LD;
+                     }
+                   break;
 
-         /* We aren't supposed to use alloca in BFD because on
-            systems which do not have alloca the version in libiberty
-            calls xmalloc, which might cause the program to crash
-            when it runs out of memory.  This function doesn't have a
-            return status, so there's no way to gracefully return an
-            error.  So cheat.  We know that string[-1] can be safely
-            dereferenced;  It's either a string in an ELF string
-            table, or allocated in an objalloc structure.  */
+                 default:
+                   expecting_tls_get_addr = 0;
+                   continue;
+                 }
 
-         p = h->root.root.string - 1;
-         save = *p;
-         *(char *) p = '.';
-         htab = ppc_hash_table (info);
-         fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
-         *(char *) p = save;
+               if ((tls_set & TLS_EXPLICIT) == 0)
+                 {
+                   struct got_entry *ent;
 
-         /* Unfortunately, if it so happens that the string we were
-            looking for was allocated immediately before this string,
-            then we overwrote the string terminator.  That's the only
-            reason the lookup should fail.  */
-         if (fh == NULL)
-           {
-             q = h->root.root.string + strlen (h->root.root.string);
-             while (q >= h->root.root.string && *q == *p)
-               --q, --p;
-             if (q < h->root.root.string && *p == '.')
-               fh = elf_link_hash_lookup (&htab->elf, p, false, false, false);
-           }
-         if (fh != NULL)
-           {
-             ((struct ppc_link_hash_entry *) h)->oh = fh;
-             ((struct ppc_link_hash_entry *) fh)->oh = h;
-           }
+                   /* Adjust got entry for this reloc.  */
+                   if (h != NULL)
+                     ent = h->got.glist;
+                   else
+                     ent = elf_local_got_ents (ibfd)[r_symndx];
+
+                   for (; ent != NULL; ent = ent->next)
+                     if (ent->addend == rel->r_addend
+                         && ent->tls_type == got_tls_type)
+                       break;
+                   if (ent == NULL)
+                     abort ();
+
+                   if (tls_set == 0)
+                     {
+                       /* We managed to get rid of a got entry.  */
+                       if (ent->got.refcount > 0)
+                         ent->got.refcount -= 1;
+                     }
+                   else
+                     ent->tls_type = tls_set;
+                 }
+               else if (h != NULL)
+                 {
+                   struct ppc_link_hash_entry * eh;
+                   struct ppc_dyn_relocs **pp;
+                   struct ppc_dyn_relocs *p;
+
+                   /* Adjust dynamic relocs.  */
+                   eh = (struct ppc_link_hash_entry *) h;
+                   for (pp = &eh->dyn_relocs;
+                        (p = *pp) != NULL;
+                        pp = &p->next)
+                     if (p->sec == sec)
+                       {
+                         /* If we got rid of a DTPMOD/DTPREL reloc
+                            pair then we'll lose one or two dyn
+                            relocs.  */
+                         if (tls_clear == TLS_GD_LD
+                             && rel + 1 < relend
+                             && (rel[1].r_info
+                                 == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64))
+                             && rel[1].r_offset == rel->r_offset + 8)
+                           p->count -= 1;
+                         if (tls_set == TLS_EXPLICIT)
+                           p->count -= 1;
+                         if (p->count == 0)
+                           *pp = p->next;
+                         break;
+                       }
+                 }
+
+               *tls_type |= tls_set;
+               *tls_type &= ~tls_clear;
+             }
+
+           if (elf_section_data (sec)->relocs != relstart)
+             free (relstart);
+         }
+
+      if (locsyms != NULL
+         && (elf_tdata (ibfd)->symtab_hdr.contents
+             != (unsigned char *) locsyms))
+       {
+         if (!info->keep_memory)
+           free (locsyms);
+         else
+           elf_tdata (ibfd)->symtab_hdr.contents = (unsigned char *) locsyms;
        }
-      if (fh != NULL)
-       _bfd_elf_link_hash_hide_symbol (info, fh, force_local);
     }
+  return TRUE;
 }
 
 /* This is the condition under which ppc64_elf_finish_dynamic_symbol
@@ -3581,7 +5443,7 @@ ppc64_elf_hide_symbol (info, h, force_local)
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
-static boolean
+static bfd_boolean
 allocate_dynrelocs (h, inf)
      struct elf_link_hash_entry *h;
      PTR inf;
@@ -3591,9 +5453,10 @@ allocate_dynrelocs (h, inf)
   asection *s;
   struct ppc_link_hash_entry *eh;
   struct ppc_dyn_relocs *p;
+  struct got_entry *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return true;
+    return TRUE;
 
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -3602,75 +5465,90 @@ allocate_dynrelocs (h, inf)
   htab = ppc_hash_table (info);
 
   if (htab->elf.dynamic_sections_created
-      && h->plt.refcount > 0
-      && h->dynindx != -1)
+      && h->dynindx != -1
+      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
     {
-      BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
-
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h))
-       {
-         /* If this is the first .plt entry, make room for the special
-            first entry.  */
-         s = htab->splt;
-         if (s->_raw_size == 0)
-           s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
-
-         h->plt.offset = s->_raw_size;
-
-         /* Make room for this entry.  */
-         s->_raw_size += PLT_ENTRY_SIZE;
-
-         /* Make room for the .glink code.  */
-         s = htab->sglink;
-         if (s->_raw_size == 0)
-           s->_raw_size += GLINK_CALL_STUB_SIZE;
-         /* We need bigger stubs past index 32767.  */
-         if (s->_raw_size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
-           s->_raw_size += 4;
-         s->_raw_size += 2*4;
-
-         /* We also need to make an entry in the .rela.plt section.  */
-         s = htab->srelplt;
-         s->_raw_size += sizeof (Elf64_External_Rela);
-       }
-      else
+      struct plt_entry *pent;
+      bfd_boolean doneone = FALSE;
+      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
+       if (pent->plt.refcount > 0)
+         {
+           BFD_ASSERT (((struct ppc_link_hash_entry *) h)->is_func_descriptor);
+
+           /* If this is the first .plt entry, make room for the special
+              first entry.  */
+           s = htab->splt;
+           if (s->_raw_size == 0)
+             s->_raw_size += PLT_INITIAL_ENTRY_SIZE;
+
+           pent->plt.offset = s->_raw_size;
+
+           /* Make room for this entry.  */
+           s->_raw_size += PLT_ENTRY_SIZE;
+
+           /* Make room for the .glink code.  */
+           s = htab->sglink;
+           if (s->_raw_size == 0)
+             s->_raw_size += GLINK_CALL_STUB_SIZE;
+           /* We need bigger stubs past index 32767.  */
+           if (s->_raw_size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+             s->_raw_size += 4;
+           s->_raw_size += 2*4;
+
+           /* We also need to make an entry in the .rela.plt section.  */
+           s = htab->srelplt;
+           s->_raw_size += sizeof (Elf64_External_Rela);
+           doneone = TRUE;
+         }
+       else
+         pent->plt.offset = (bfd_vma) -1;
+      if (!doneone)
        {
-         h->plt.offset = (bfd_vma) -1;
+         h->plt.plist = NULL;
          h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
        }
     }
   else
     {
-      h->plt.offset = (bfd_vma) -1;
+      h->plt.plist = NULL;
       h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
     }
 
-  if (h->got.refcount > 0)
-    {
-      boolean dyn;
-
-      /* Make sure this symbol is output as a dynamic symbol.
-        Undefined weak syms won't yet be marked as dynamic.  */
-      if (h->dynindx == -1
-         && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
-       {
-         if (! bfd_elf64_link_record_dynamic_symbol (info, h))
-           return false;
-       }
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (gent->got.refcount > 0)
+      {
+       /* Make sure this symbol is output as a dynamic symbol.
+          Undefined weak syms won't yet be marked as dynamic.  */
+       if (h->dynindx == -1
+           && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+         {
+           if (! bfd_elf64_link_record_dynamic_symbol (info, h))
+             return FALSE;
+         }
 
-      s = htab->sgot;
-      h->got.offset = s->_raw_size;
-      s->_raw_size += 8;
-      dyn = htab->elf.dynamic_sections_created;
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
-       htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
-    }
-  else
-    h->got.offset = (bfd_vma) -1;
+       if ((gent->tls_type & TLS_LD) != 0)
+         gent->got.offset = htab->tlsld_got.offset;
+       else
+         {
+           bfd_boolean dyn;
+
+           s = htab->sgot;
+           gent->got.offset = s->_raw_size;
+           s->_raw_size += (gent->tls_type & TLS_GD_LD) != 0 ? 16 : 8;
+           dyn = htab->elf.dynamic_sections_created;
+           if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h))
+             htab->srelgot->_raw_size
+               += ((gent->tls_type & TLS_GD_LD) != 0
+                   ? 2 * sizeof (Elf64_External_Rela)
+                   : sizeof (Elf64_External_Rela));
+         }
+      }
+    else
+      gent->got.offset = (bfd_vma) -1;
 
   eh = (struct ppc_link_hash_entry *) h;
   if (eh->dyn_relocs == NULL)
-    return true;
+    return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
      dynamic pc-relative relocs against symbols which turn out to be
@@ -3716,7 +5594,7 @@ allocate_dynrelocs (h, inf)
              && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
            {
              if (! bfd_elf64_link_record_dynamic_symbol (info, h))
-               return false;
+               return FALSE;
            }
 
          /* If that succeeded, we know we'll be keeping all the
@@ -3737,12 +5615,12 @@ allocate_dynrelocs (h, inf)
       sreloc->_raw_size += p->count * sizeof (Elf64_External_Rela);
     }
 
-  return true;
+  return TRUE;
 }
 
 /* Find any dynamic relocs that apply to read-only sections.  */
 
-static boolean
+static bfd_boolean
 readonly_dynrelocs (h, inf)
      struct elf_link_hash_entry *h;
      PTR inf;
@@ -3765,15 +5643,15 @@ readonly_dynrelocs (h, inf)
          info->flags |= DF_TEXTREL;
 
          /* Not an error, just cut short the traversal.  */
-         return false;
+         return FALSE;
        }
     }
-  return true;
+  return TRUE;
 }
 
 /* Set the sizes of the dynamic sections.  */
 
-static boolean
+static bfd_boolean
 ppc64_elf_size_dynamic_sections (output_bfd, info)
      bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
@@ -3781,7 +5659,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
   struct ppc_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
-  boolean relocs;
+  bfd_boolean relocs;
   bfd *ibfd;
 
   htab = ppc_hash_table (info);
@@ -3802,12 +5680,22 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
        }
     }
 
+  if (htab->tlsld_got.refcount > 0)
+    {
+      htab->tlsld_got.offset = htab->sgot->_raw_size;
+      htab->sgot->_raw_size += 16;
+      if (info->shared)
+       htab->srelgot->_raw_size += sizeof (Elf64_External_Rela);
+    }
+  else
+    htab->tlsld_got.offset = (bfd_vma) -1;
+
   /* Set up .got offsets for local syms, and space for local dynamic
      relocs.  */
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
-      bfd_signed_vma *local_got;
-      bfd_signed_vma *end_local_got;
+      struct got_entry **lgot_ents;
+      struct got_entry **end_lgot_ents;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -3842,26 +5730,52 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
            }
        }
 
-      local_got = elf_local_got_refcounts (ibfd);
-      if (!local_got)
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
        continue;
 
       symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
       locsymcount = symtab_hdr->sh_info;
-      end_local_got = local_got + locsymcount;
+      end_lgot_ents = lgot_ents + locsymcount;
       s = htab->sgot;
       srel = htab->srelgot;
-      for (; local_got < end_local_got; ++local_got)
+      for (; lgot_ents < end_lgot_ents; ++lgot_ents)
        {
-         if (*local_got > 0)
-           {
-             *local_got = s->_raw_size;
-             s->_raw_size += 8;
-             if (info->shared)
-               srel->_raw_size += sizeof (Elf64_External_Rela);
-           }
-         else
-           *local_got = (bfd_vma) -1;
+         struct got_entry *ent;
+
+         for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+           if (ent->got.refcount > 0)
+             {
+               if ((ent->tls_type & TLS_LD) != 0)
+                 {
+                   if (htab->tlsld_got.offset == (bfd_vma) -1)
+                     {
+                       htab->tlsld_got.offset = s->_raw_size;
+                       s->_raw_size += 16;
+                       if (info->shared)
+                         srel->_raw_size += sizeof (Elf64_External_Rela);
+                     }
+                   ent->got.offset = htab->tlsld_got.offset;
+                 }
+               else
+                 {
+                   ent->got.offset = s->_raw_size;
+                   if ((ent->tls_type & TLS_GD_LD) != 0)
+                     {
+                       s->_raw_size += 16;
+                       if (info->shared)
+                         srel->_raw_size += 2 * sizeof (Elf64_External_Rela);
+                     }
+                   else
+                     {
+                       s->_raw_size += 8;
+                       if (info->shared)
+                         srel->_raw_size += sizeof (Elf64_External_Rela);
+                     }
+                 }
+             }
+           else
+             ent->got.offset = (bfd_vma) -1;
        }
     }
 
@@ -3871,12 +5785,16 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
 
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
-  relocs = false;
+  relocs = FALSE;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
+      /* Reset _cooked_size since prelim layout will set it wrongly,
+        and a non-zero _cooked_size sticks.  */
+      s->_cooked_size = 0;
+
       if (s == htab->sbrlt || s == htab->srelbrlt)
        /* These haven't been allocated yet;  don't strip.  */
        continue;
@@ -3904,7 +5822,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
          else
            {
              if (s != htab->srelplt)
-               relocs = true;
+               relocs = TRUE;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -3930,11 +5848,13 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
       /* Allocate memory for the section contents.  We use bfd_zalloc
         here in case unused entries are not reclaimed before the
         section's contents are written out.  This should not happen,
-        but this way if it does, we get a R_PPC64_NONE reloc instead
-        of garbage.  */
+        but this way if it does we get a R_PPC64_NONE reloc in .rela
+        sections instead of garbage.
+        We also rely on the section contents being zero when writing
+        the GOT.  */
       s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
       if (s->contents == NULL)
-       return false;
+       return FALSE;
     }
 
   if (htab->elf.dynamic_sections_created)
@@ -3950,7 +5870,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
       if (!info->shared)
        {
          if (!add_dynamic_entry (DT_DEBUG, 0))
-           return false;
+           return FALSE;
        }
 
       if (htab->splt != NULL && htab->splt->_raw_size != 0)
@@ -3960,14 +5880,14 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
              || !add_dynamic_entry (DT_PLTREL, DT_RELA)
              || !add_dynamic_entry (DT_JMPREL, 0)
              || !add_dynamic_entry (DT_PPC64_GLINK, 0))
-           return false;
+           return FALSE;
        }
 
       if (NO_OPD_RELOCS)
        {
          if (!add_dynamic_entry (DT_PPC64_OPD, 0)
              || !add_dynamic_entry (DT_PPC64_OPDSZ, 0))
-           return false;
+           return FALSE;
        }
 
       if (relocs)
@@ -3975,7 +5895,7 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
          if (!add_dynamic_entry (DT_RELA, 0)
              || !add_dynamic_entry (DT_RELASZ, 0)
              || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
-           return false;
+           return FALSE;
 
          /* If any dynamic relocs apply to a read-only section,
             then we need a DT_TEXTREL entry.  */
@@ -3986,13 +5906,13 @@ ppc64_elf_size_dynamic_sections (output_bfd, info)
          if ((info->flags & DF_TEXTREL) != 0)
            {
              if (!add_dynamic_entry (DT_TEXTREL, 0))
-               return false;
+               return FALSE;
            }
        }
     }
 #undef add_dynamic_entry
 
-  return true;
+  return TRUE;
 }
 
 /* Determine the type of stub needed, if any, for a call.  */
@@ -4013,11 +5933,16 @@ ppc_type_of_stub (input_sec, rel, hash, destination)
   if (h != NULL)
     {
       if (h->oh != NULL
-         && h->oh->plt.offset != (bfd_vma) -1
          && h->oh->dynindx != -1)
        {
-         *hash = (struct ppc_link_hash_entry *) h->oh;
-         return ppc_stub_plt_call;
+         struct plt_entry *ent;
+         for (ent = h->oh->plt.plist; ent != NULL; ent = ent->next)
+           if (ent->addend == rel->r_addend
+               && ent->plt.offset != (bfd_vma) -1)
+             {
+               *hash = (struct ppc_link_hash_entry *) h->oh;
+               return ppc_stub_plt_call;
+             }
        }
 
       if (h->elf.root.type == bfd_link_hash_undefweak
@@ -4078,7 +6003,7 @@ build_plt_stub (obfd, p, offset, glink)
   return p;
 }
 
-static boolean
+static bfd_boolean
 ppc_build_one_stub (gen_entry, in_arg)
      struct bfd_hash_entry *gen_entry;
      PTR in_arg;
@@ -4092,6 +6017,7 @@ ppc_build_one_stub (gen_entry, in_arg)
   bfd_byte *loc;
   bfd_byte *p;
   unsigned int indx;
+  struct plt_entry *ent;
   bfd_vma off;
   int size;
 
@@ -4130,13 +6056,13 @@ ppc_build_one_stub (gen_entry, in_arg)
     case ppc_stub_plt_branch:
       br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                         stub_entry->root.string + 9,
-                                        false, false);
+                                        FALSE, FALSE);
       if (br_entry == NULL)
        {
          (*_bfd_error_handler) (_("can't find branch stub `%s'"),
                                 stub_entry->root.string + 9);
-         htab->stub_error = true;
-         return false;
+         htab->stub_error = TRUE;
+         return FALSE;
        }
 
       off = (stub_entry->target_value
@@ -4150,7 +6076,7 @@ ppc_build_one_stub (gen_entry, in_arg)
        {
          /* Create a reloc for the branch lookup table entry.  */
          Elf_Internal_Rela rela;
-         Elf64_External_Rela *r;
+         bfd_byte *loc;
 
          rela.r_offset = (br_entry->offset
                           + htab->sbrlt->output_offset
@@ -4158,9 +6084,9 @@ ppc_build_one_stub (gen_entry, in_arg)
          rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
          rela.r_addend = off;
 
-         r = (Elf64_External_Rela *) htab->srelbrlt->contents;
-         r += htab->srelbrlt->reloc_count++;
-         bfd_elf64_swap_reloca_out (htab->srelbrlt->owner, &rela, r);
+         loc = htab->srelbrlt->contents;
+         loc += htab->srelbrlt->reloc_count++ * sizeof (Elf64_External_Rela);
+         bfd_elf64_swap_reloca_out (htab->srelbrlt->owner, &rela, loc);
        }
 
       off = (br_entry->offset
@@ -4175,40 +6101,19 @@ ppc_build_one_stub (gen_entry, in_arg)
            (_("linkage table error against `%s'"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
-         htab->stub_error = true;
-         return false;
+         htab->stub_error = TRUE;
+         return FALSE;
        }
 
       indx = off;
       bfd_put_32 (stub_bfd, (bfd_vma) ADDIS_R12_R2 | PPC_HA (indx), loc);
       bfd_put_32 (stub_bfd, (bfd_vma) LD_R11_0R12 | PPC_LO (indx), loc + 4);
       bfd_put_32 (stub_bfd, (bfd_vma) MTCTR_R11, loc + 8);
-      bfd_put_32 (stub_bfd, (bfd_vma) BCTR, loc + 12);
-      size = 16;
-      break;
-
-    case ppc_stub_plt_call:
-      /* Build the .glink lazy link call stub.  */
-      p = htab->sglink->contents + htab->sglink->_cooked_size;
-      indx = htab->sglink->reloc_count;
-      if (indx < 0x8000)
-       {
-         bfd_put_32 (htab->sglink->owner, LI_R0_0 | indx, p);
-         p += 4;
-       }
-      else
-       {
-         bfd_put_32 (htab->sglink->owner, LIS_R0_0 | PPC_HI (indx), p);
-         p += 4;
-         bfd_put_32 (htab->sglink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
-         p += 4;
-       }
-      bfd_put_32 (htab->sglink->owner,
-                 B_DOT | ((htab->sglink->contents - p) & 0x3fffffc), p);
-      p += 4;
-      htab->sglink->_cooked_size = p - htab->sglink->contents;
-      htab->sglink->reloc_count += 1;
+      bfd_put_32 (stub_bfd, (bfd_vma) BCTR, loc + 12);
+      size = 16;
+      break;
 
+    case ppc_stub_plt_call:
       /* Do the best we can for shared libraries built without
         exporting ".foo" for each "foo".  This can happen when symbol
         versioning scripts strip all bar a subset of symbols.  */
@@ -4224,7 +6129,13 @@ ppc_build_one_stub (gen_entry, in_arg)
        }
 
       /* Now build the stub.  */
-      off = stub_entry->h->elf.plt.offset;
+      off = (bfd_vma) -1;
+      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
+       if (ent->addend == stub_entry->addend)
+         {
+           off = ent->plt.offset;
+           break;
+         }
       if (off >= (bfd_vma) -2)
        abort ();
 
@@ -4240,8 +6151,8 @@ ppc_build_one_stub (gen_entry, in_arg)
            (_("linkage table error against `%s'"),
             stub_entry->h->elf.root.root.string);
          bfd_set_error (bfd_error_bad_value);
-         htab->stub_error = true;
-         return false;
+         htab->stub_error = TRUE;
+         return FALSE;
        }
 
       p = build_plt_stub (stub_bfd, loc, (int) off, 0);
@@ -4250,18 +6161,18 @@ ppc_build_one_stub (gen_entry, in_arg)
 
     default:
       BFD_FAIL ();
-      return false;
+      return FALSE;
     }
 
   stub_sec->_cooked_size += size;
-  return true;
+  return TRUE;
 }
 
 /* As above, but don't actually build the stub.  Just bump offset so
    we know stub section sizes, and select plt_branch stubs where
    long_branch stubs won't do.  */
 
-static boolean
+static bfd_boolean
 ppc_size_one_stub (gen_entry, in_arg)
      struct bfd_hash_entry *gen_entry;
      PTR in_arg;
@@ -4277,7 +6188,15 @@ ppc_size_one_stub (gen_entry, in_arg)
 
   if (stub_entry->stub_type == ppc_stub_plt_call)
     {
-      off = stub_entry->h->elf.plt.offset & ~(bfd_vma) 1;
+      struct plt_entry *ent;
+      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
+       if (ent->addend == stub_entry->addend)
+         {
+           off = ent->plt.offset & ~(bfd_vma) 1;
+           break;
+         }
+      if (ent == NULL)
+       abort ();
       off += (htab->splt->output_offset
              + htab->splt->output_section->vma
              - elf_gp (htab->splt->output_section->owner)
@@ -4306,13 +6225,13 @@ ppc_size_one_stub (gen_entry, in_arg)
 
          br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                             stub_entry->root.string + 9,
-                                            true, false);
+                                            TRUE, FALSE);
          if (br_entry == NULL)
            {
              (*_bfd_error_handler) (_("can't build branch stub `%s'"),
                                     stub_entry->root.string + 9);
-             htab->stub_error = true;
-             return false;
+             htab->stub_error = TRUE;
+             return FALSE;
            }
 
          if (br_entry->iter != htab->stub_iteration)
@@ -4327,7 +6246,7 @@ ppc_size_one_stub (gen_entry, in_arg)
     }
 
   stub_entry->stub_sec->_raw_size += size;
-  return true;
+  return TRUE;
 }
 
 /* Set up various things so that we can make a list of input sections
@@ -4340,7 +6259,6 @@ ppc64_elf_setup_section_lists (output_bfd, info)
      struct bfd_link_info *info;
 {
   bfd *input_bfd;
-  unsigned int bfd_count;
   int top_id, top_index;
   asection *section;
   asection **input_list, **list;
@@ -4351,12 +6269,11 @@ ppc64_elf_setup_section_lists (output_bfd, info)
       || htab->sbrlt == NULL)
     return 0;
 
-  /* Count the number of input BFDs and find the top input section id.  */
-  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+  /* Find the top input section id.  */
+  for (input_bfd = info->input_bfds, top_id = 0;
        input_bfd != NULL;
        input_bfd = input_bfd->link_next)
     {
-      bfd_count += 1;
       for (section = input_bfd->sections;
           section != NULL;
           section = section->next)
@@ -4365,7 +6282,6 @@ ppc64_elf_setup_section_lists (output_bfd, info)
            top_id = section->id;
        }
     }
-  htab->bfd_count = bfd_count;
 
   amt = sizeof (struct map_stub) * (top_id + 1);
   htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
@@ -4446,7 +6362,7 @@ static void
 group_sections (htab, stub_group_size, stubs_always_before_branch)
      struct ppc_link_hash_table *htab;
      bfd_size_type stub_group_size;
-     boolean stubs_always_before_branch;
+     bfd_boolean stubs_always_before_branch;
 {
   asection **list = htab->input_list + htab->top_index;
   do
@@ -4510,107 +6426,13 @@ group_sections (htab, stub_group_size, stubs_always_before_branch)
 #undef PREV_SEC
 }
 
-/* Read in all local syms for all input bfds.  */
-
-static boolean
-get_local_syms (input_bfd, htab)
-     bfd *input_bfd;
-     struct ppc_link_hash_table *htab;
-{
-  unsigned int bfd_indx;
-  Elf_Internal_Sym *local_syms, **all_local_syms;
-
-  /* We want to read in symbol extension records only once.  To do this
-     we need to read in the local symbols in parallel and save them for
-     later use; so hold pointers to the local symbols in an array.  */
-  bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
-  all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
-  htab->all_local_syms = all_local_syms;
-  if (all_local_syms == NULL)
-    return false;
-
-  /* Walk over all the input BFDs, swapping in local symbols.
-     If we are creating a shared library, create hash entries for the
-     export stubs.  */
-  for (bfd_indx = 0;
-       input_bfd != NULL;
-       input_bfd = input_bfd->link_next, bfd_indx++)
-    {
-      Elf_Internal_Shdr *symtab_hdr;
-      Elf_Internal_Shdr *shndx_hdr;
-      Elf_Internal_Sym *isym;
-      Elf64_External_Sym *ext_syms, *esym, *end_sy;
-      Elf_External_Sym_Shndx *shndx_buf, *shndx;
-      bfd_size_type sec_size;
-
-      /* We'll need the symbol table in a second.  */
-      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-      if (symtab_hdr->sh_info == 0)
-       continue;
-
-      /* We need an array of the local symbols attached to the input bfd.
-        Unfortunately, we're going to have to read & swap them in.  */
-      sec_size = symtab_hdr->sh_info;
-      sec_size *= sizeof (Elf_Internal_Sym);
-      local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
-      if (local_syms == NULL)
-       return false;
-
-      all_local_syms[bfd_indx] = local_syms;
-      sec_size = symtab_hdr->sh_info;
-      sec_size *= sizeof (Elf64_External_Sym);
-      ext_syms = (Elf64_External_Sym *) bfd_malloc (sec_size);
-      if (ext_syms == NULL)
-       return false;
-
-      if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
-         || bfd_bread ((PTR) ext_syms, sec_size, input_bfd) != sec_size)
-       {
-       error_ret_free_ext_syms:
-         free (ext_syms);
-         return false;
-       }
-
-      shndx_buf = NULL;
-      shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
-      if (shndx_hdr->sh_size != 0)
-       {
-         sec_size = symtab_hdr->sh_info;
-         sec_size *= sizeof (Elf_External_Sym_Shndx);
-         shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (sec_size);
-         if (shndx_buf == NULL)
-           goto error_ret_free_ext_syms;
-
-         if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
-             || bfd_bread ((PTR) shndx_buf, sec_size, input_bfd) != sec_size)
-           {
-             free (shndx_buf);
-             goto error_ret_free_ext_syms;
-           }
-       }
-
-      /* Swap the local symbols in.  */
-      for (esym = ext_syms, end_sy = esym + symtab_hdr->sh_info,
-            isym = local_syms, shndx = shndx_buf;
-          esym < end_sy;
-          esym++, isym++, shndx = (shndx ? shndx + 1 : NULL))
-       bfd_elf64_swap_symbol_in (input_bfd, esym, shndx, isym);
-
-      /* Now we can free the external symbols.  */
-      free (shndx_buf);
-      free (ext_syms);
-    }
-
-  return true;
-}
-
 /* Determine and set the size of the stub section for a final link.
 
    The basic idea here is to examine all the relocations looking for
    PC-relative calls to a target that is unreachable with a "bl"
    instruction.  */
 
-boolean
+bfd_boolean
 ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                      add_stub_section, layout_sections_again)
      bfd *output_bfd;
@@ -4621,8 +6443,7 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
      void (*layout_sections_again) PARAMS ((void));
 {
   bfd_size_type stub_group_size;
-  boolean stubs_always_before_branch;
-  boolean ret = false;
+  bfd_boolean stubs_always_before_branch;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
   /* Stash our params away.  */
@@ -4644,22 +6465,15 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
 
   group_sections (htab, stub_group_size, stubs_always_before_branch);
 
-  if (! get_local_syms (info->input_bfds, htab))
-    {
-      if (htab->all_local_syms)
-       goto error_ret_free_local;
-      return false;
-    }
-
   while (1)
     {
       bfd *input_bfd;
       unsigned int bfd_indx;
       asection *stub_sec;
-      boolean stub_changed;
+      bfd_boolean stub_changed;
 
       htab->stub_iteration += 1;
-      stub_changed = false;
+      stub_changed = FALSE;
 
       for (input_bfd = info->input_bfds, bfd_indx = 0;
           input_bfd != NULL;
@@ -4667,24 +6481,19 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
        {
          Elf_Internal_Shdr *symtab_hdr;
          asection *section;
-         Elf_Internal_Sym *local_syms;
+         Elf_Internal_Sym *local_syms = NULL;
 
          /* We'll need the symbol table in a second.  */
          symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
          if (symtab_hdr->sh_info == 0)
            continue;
 
-         local_syms = htab->all_local_syms[bfd_indx];
-
          /* Walk over each section attached to the input bfd.  */
          for (section = input_bfd->sections;
               section != NULL;
               section = section->next)
            {
-             Elf_Internal_Shdr *input_rel_hdr;
-             Elf64_External_Rela *external_relocs, *erelaend, *erela;
              Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
-             bfd_size_type amt;
 
              /* If there aren't any relocs, then there's nothing more
                 to do.  */
@@ -4698,47 +6507,13 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                  || section->output_section->owner != output_bfd)
                continue;
 
-             /* Allocate space for the external relocations.  */
-             amt = section->reloc_count;
-             amt *= sizeof (Elf64_External_Rela);
-             external_relocs = (Elf64_External_Rela *) bfd_malloc (amt);
-             if (external_relocs == NULL)
-               {
-                 goto error_ret_free_local;
-               }
-
-             /* Likewise for the internal relocations.  */
-             amt = section->reloc_count;
-             amt *= sizeof (Elf_Internal_Rela);
-             internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt);
+             /* Get the relocs.  */
+             internal_relocs
+               = _bfd_elf64_link_read_relocs (input_bfd, section, NULL,
+                                              (Elf_Internal_Rela *) NULL,
+                                              info->keep_memory);
              if (internal_relocs == NULL)
-               {
-                 free (external_relocs);
-                 goto error_ret_free_local;
-               }
-
-             /* Read in the external relocs.  */
-             input_rel_hdr = &elf_section_data (section)->rel_hdr;
-             if (bfd_seek (input_bfd, input_rel_hdr->sh_offset, SEEK_SET) != 0
-                 || bfd_bread ((PTR) external_relocs,
-                               input_rel_hdr->sh_size,
-                               input_bfd) != input_rel_hdr->sh_size)
-               {
-                 free (external_relocs);
-               error_ret_free_internal:
-                 free (internal_relocs);
-                 goto error_ret_free_local;
-               }
-
-             /* Swap in the relocs.  */
-             erela = external_relocs;
-             erelaend = erela + section->reloc_count;
-             irela = internal_relocs;
-             for (; erela < erelaend; erela++, irela++)
-               bfd_elf64_swap_reloca_in (input_bfd, erela, irela);
-
-             /* We're done with the external relocs, free them.  */
-             free (external_relocs);
+               goto error_ret_free_local;
 
              /* Now examine each relocation.  */
              irela = internal_relocs;
@@ -4752,13 +6527,15 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                  bfd_vma sym_value;
                  bfd_vma destination;
                  struct ppc_link_hash_entry *hash;
+                 struct elf_link_hash_entry *h;
+                 Elf_Internal_Sym *sym;
                  char *stub_name;
                  const asection *id_sec;
 
                  r_type = ELF64_R_TYPE (irela->r_info);
                  r_indx = ELF64_R_SYM (irela->r_info);
 
-                 if (r_type >= (unsigned int) R_PPC_max)
+                 if (r_type >= (unsigned int) R_PPC64_max)
                    {
                      bfd_set_error (bfd_error_bad_value);
                      goto error_ret_free_internal;
@@ -4773,21 +6550,16 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
 
                  /* Now determine the call target, its name, value,
                     section.  */
-                 sym_sec = NULL;
-                 sym_value = 0;
                  destination = 0;
-                 hash = NULL;
-                 if (r_indx < symtab_hdr->sh_info)
+                 if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                                 r_indx, input_bfd))
+                   goto error_ret_free_internal;
+                 hash = (struct ppc_link_hash_entry *) h;
+
+                 if (hash == NULL)
                    {
                      /* It's a local symbol.  */
-                     Elf_Internal_Sym *sym;
-                     Elf_Internal_Shdr *hdr;
-
-                     sym = local_syms + r_indx;
-                     hdr = elf_elfsections (input_bfd)[sym->st_shndx];
-                     sym_sec = hdr->bfd_section;
-                     if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
-                       sym_value = sym->st_value;
+                     sym_value = sym->st_value;
                      destination = (sym_value + irela->r_addend
                                     + sym_sec->output_offset
                                     + sym_sec->output_section->vma);
@@ -4795,21 +6567,10 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                  else
                    {
                      /* It's an external symbol.  */
-                     int e_indx;
-
-                     e_indx = r_indx - symtab_hdr->sh_info;
-                     hash = ((struct ppc_link_hash_entry *)
-                             elf_sym_hashes (input_bfd)[e_indx]);
-
-                     while (hash->elf.root.type == bfd_link_hash_indirect
-                            || hash->elf.root.type == bfd_link_hash_warning)
-                       hash = ((struct ppc_link_hash_entry *)
-                               hash->elf.root.u.i.link);
-
+                     sym_value = 0;
                      if (hash->elf.root.type == bfd_link_hash_defined
                          || hash->elf.root.type == bfd_link_hash_defweak)
                        {
-                         sym_sec = hash->elf.root.u.def.section;
                          sym_value = hash->elf.root.u.def.value;
                          if (sym_sec->output_section != NULL)
                            destination = (sym_value + irela->r_addend
@@ -4833,6 +6594,24 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                  if (stub_type == ppc_stub_none)
                    continue;
 
+                 /* __tls_get_addr calls might be eliminated.  */
+                 if (stub_type != ppc_stub_plt_call
+                     && hash != NULL
+                     && &hash->elf == htab->tls_get_addr
+                     && section->has_tls_reloc
+                     && irela != internal_relocs)
+                   {
+                     /* Get tls info.  */
+                     char *tls_type;
+
+                     if (!get_tls_type (&tls_type, &local_syms,
+                                        irela - 1, input_bfd))
+                       goto error_ret_free_internal;
+                     if (tls_type != NULL
+                         && (*tls_type & (TLS_TLS | TLS_GD_LD)) == TLS_TLS)
+                       continue;
+                   }
+
                  /* Support for grouping stub sections.  */
                  id_sec = htab->stub_group[section->id].link_sec;
 
@@ -4842,7 +6621,7 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                    goto error_ret_free_internal;
 
                  stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table,
-                                                    stub_name, false, false);
+                                                    stub_name, FALSE, FALSE);
                  if (stub_entry != NULL)
                    {
                      /* The proper stub has already been created.  */
@@ -4854,18 +6633,37 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
                  if (stub_entry == NULL)
                    {
                      free (stub_name);
-                     goto error_ret_free_local;
+                   error_ret_free_internal:
+                     if (elf_section_data (section)->relocs == NULL)
+                       free (internal_relocs);
+                   error_ret_free_local:
+                     if (local_syms != NULL
+                         && (symtab_hdr->contents
+                             != (unsigned char *) local_syms))
+                       free (local_syms);
+                     return FALSE;
                    }
 
                  stub_entry->target_value = sym_value;
                  stub_entry->target_section = sym_sec;
                  stub_entry->stub_type = stub_type;
                  stub_entry->h = hash;
-                 stub_changed = true;
+                 stub_entry->addend = irela->r_addend;
+                 stub_changed = TRUE;
                }
 
              /* We're done with the internal relocs, free them.  */
-             free (internal_relocs);
+             if (elf_section_data (section)->relocs != internal_relocs)
+               free (internal_relocs);
+           }
+
+         if (local_syms != NULL
+             && symtab_hdr->contents != (unsigned char *) local_syms)
+           {
+             if (!info->keep_memory)
+               free (local_syms);
+             else
+               symtab_hdr->contents = (unsigned char *) local_syms;
            }
        }
 
@@ -4895,15 +6693,7 @@ ppc64_elf_size_stubs (output_bfd, stub_bfd, info, group_size,
      the dynamic symbol table is corrupted since the section symbol
      for the stripped section isn't written.  */
 
-  ret = true;
-
- error_ret_free_local:
-  while (htab->bfd_count-- > 0)
-    if (htab->all_local_syms[htab->bfd_count])
-      free (htab->all_local_syms[htab->bfd_count]);
-  free (htab->all_local_syms);
-
-  return ret;
+  return TRUE;
 }
 
 /* Called after we have determined section placement.  If sections
@@ -4967,7 +6757,7 @@ ppc64_elf_toc (obfd)
    The stubs are kept in a hash table attached to the main linker
    hash table.  This function is called via gldelf64ppc_finish.  */
 
-boolean
+bfd_boolean
 ppc64_elf_build_stubs (info)
      struct bfd_link_info *info;
 {
@@ -4988,13 +6778,15 @@ ppc64_elf_build_stubs (info)
        {
          stub_sec->contents = (bfd_byte *) bfd_zalloc (htab->stub_bfd, size);
          if (stub_sec->contents == NULL)
-           return false;
+           return FALSE;
        }
       stub_sec->_cooked_size = 0;
     }
 
   if (htab->splt != NULL)
     {
+      unsigned int indx;
+
       /* Build the .glink plt call stub.  */
       plt_r2 = (htab->splt->output_offset
                + htab->splt->output_section->vma
@@ -5002,15 +6794,34 @@ ppc64_elf_build_stubs (info)
                - TOC_BASE_OFF);
       p = htab->sglink->contents;
       p = build_plt_stub (htab->sglink->owner, p, (int) plt_r2, 1);
-      while (p - htab->sglink->contents < GLINK_CALL_STUB_SIZE)
+      while (p < htab->sglink->contents + GLINK_CALL_STUB_SIZE)
        {
          bfd_put_32 (htab->sglink->owner, NOP, p);
          p += 4;
        }
-      htab->sglink->_cooked_size = p - htab->sglink->contents;
 
-      /* Use reloc_count to count entries.  */
-      htab->sglink->reloc_count = 0;
+      /* Build the .glink lazy link call stubs.  */
+      indx = 0;
+      while (p < htab->sglink->contents + htab->sglink->_raw_size)
+       {
+         if (indx < 0x8000)
+           {
+             bfd_put_32 (htab->sglink->owner, LI_R0_0 | indx, p);
+             p += 4;
+           }
+         else
+           {
+             bfd_put_32 (htab->sglink->owner, LIS_R0_0 | PPC_HI (indx), p);
+             p += 4;
+             bfd_put_32 (htab->sglink->owner, ORI_R0_R0_0 | PPC_LO (indx), p);
+             p += 4;
+           }
+         bfd_put_32 (htab->sglink->owner,
+                     B_DOT | ((htab->sglink->contents - p) & 0x3fffffc), p);
+         indx++;
+         p += 4;
+       }
+      htab->sglink->_cooked_size = p - htab->sglink->contents;
     }
 
   if (htab->sbrlt->_raw_size != 0)
@@ -5018,12 +6829,11 @@ ppc64_elf_build_stubs (info)
       htab->sbrlt->contents = (bfd_byte *) bfd_zalloc (htab->sbrlt->owner,
                                                       htab->sbrlt->_raw_size);
       if (htab->sbrlt->contents == NULL)
-       return false;
+       return FALSE;
     }
 
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
-  htab->sglink->reloc_count = 0;
 
   for (stub_sec = htab->stub_bfd->sections;
        stub_sec != NULL;
@@ -5036,30 +6846,13 @@ ppc64_elf_build_stubs (info)
   if (stub_sec != NULL
       || htab->sglink->_raw_size != htab->sglink->_cooked_size)
     {
-      htab->stub_error = true;
+      htab->stub_error = TRUE;
       (*_bfd_error_handler) (_("stubs don't match calculated size"));
     }
 
   return !htab->stub_error;
 }
 
-/* Set up any other section flags and such that may be necessary.  */
-
-static boolean
-ppc64_elf_fake_sections (abfd, shdr, asect)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     Elf64_Internal_Shdr *shdr;
-     asection *asect;
-{
-  if ((asect->flags & SEC_EXCLUDE) != 0)
-    shdr->sh_flags |= SHF_EXCLUDE;
-
-  if ((asect->flags & SEC_SORT_ENTRIES) != 0)
-    shdr->sh_type = SHT_ORDERED;
-
-  return true;
-}
-
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -5089,7 +6882,7 @@ ppc64_elf_fake_sections (abfd, shdr, asect)
    section, which means that the addend must be adjusted
    accordingly.  */
 
-static boolean
+static bfd_boolean
 ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                            contents, relocs, local_syms, local_sections)
      bfd *output_bfd;
@@ -5106,33 +6899,50 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   struct elf_link_hash_entry **sym_hashes;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
-  bfd_vma *local_got_offsets;
+  Elf_Internal_Rela outrel;
+  bfd_byte *loc;
+  unsigned int tls_get_addr_type;
+  struct got_entry **local_got_ents;
   bfd_vma TOCstart;
-  boolean ret = true;
-  boolean is_opd;
+  bfd_boolean ret = TRUE;
+  bfd_boolean is_opd;
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
-  boolean is_power4 = false;
+  bfd_boolean is_power4 = FALSE;
 
   if (info->relocateable)
-    return true;
+    return TRUE;
 
   /* Initialize howto table if needed.  */
   if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
     ppc_howto_init ();
 
   htab = ppc_hash_table (info);
-  local_got_offsets = elf_local_got_offsets (input_bfd);
+  if (info->shared && (htab->tlsld_got.offset & 1) == 0)
+    {
+      outrel.r_offset = (htab->sgot->output_section->vma
+                        + htab->sgot->output_offset
+                        + htab->tlsld_got.offset);
+      outrel.r_info = ELF64_R_INFO (0, R_PPC64_DTPMOD64);
+      outrel.r_addend = 0;
+
+      loc = htab->srelgot->contents;
+      loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
+      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+      htab->tlsld_got.offset |= 1;
+    }
+
+  local_got_ents = elf_local_got_ents (input_bfd);
   TOCstart = elf_gp (output_bfd);
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
-  is_opd = strcmp (bfd_get_section_name (abfd, input_section), ".opd") == 0;
+  is_opd = ppc64_elf_section_data (input_section)->opd.adjust != NULL;
 
+  tls_get_addr_type = 0;
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
     {
-      enum elf_ppc_reloc_type r_type;
-      bfd_vma offset;
+      enum elf_ppc64_reloc_type r_type;
       bfd_vma addend;
       bfd_reloc_status_type r;
       Elf_Internal_Sym *sym;
@@ -5141,25 +6951,24 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       struct elf_link_hash_entry *fdh;
       const char *sym_name;
       unsigned long r_symndx;
+      char tls_type;
       bfd_vma relocation;
-      boolean unresolved_reloc;
-      boolean warned;
+      bfd_boolean unresolved_reloc;
+      bfd_boolean warned;
       long insn;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
 
-      r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rel->r_info);
+      r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
-      offset = rel->r_offset;
-      addend = rel->r_addend;
       r = bfd_reloc_other;
       sym = (Elf_Internal_Sym *) 0;
       sec = (asection *) 0;
       h = (struct elf_link_hash_entry *) 0;
       sym_name = (const char *) 0;
-      unresolved_reloc = false;
-      warned = false;
+      unresolved_reloc = FALSE;
+      warned = FALSE;
 
       if (r_type == R_PPC64_TOC)
        {
@@ -5171,11 +6980,16 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* It's a local symbol.  */
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
-         sym_name = "<local symbol>";
-
+         sym_name = bfd_elf_local_sym_name (input_bfd, sym);
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
-         /* rel may have changed, update our copy of addend.  */
-         addend = rel->r_addend;
+         if (elf_section_data (sec) != NULL)
+           {
+             long *opd_sym_adjust;
+
+             opd_sym_adjust = ppc64_elf_section_data (sec)->opd.adjust;
+             if (opd_sym_adjust != NULL && sym->st_value % 24 == 0)
+               relocation += opd_sym_adjust[sym->st_value / 24];
+           }
        }
       else
        {
@@ -5195,7 +7009,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                   relocation value for this symbol.  output_section
                   is typically NULL for symbols satisfied by a shared
                   library.  */
-               unresolved_reloc = true;
+               unresolved_reloc = TRUE;
              else
                relocation = (h->root.u.def.value
                              + sec->output_section->vma
@@ -5212,15 +7026,275 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            {
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd, input_section,
-                     offset, (!info->shared
-                              || info->no_undefined
-                              || ELF_ST_VISIBILITY (h->other)))))
-               return false;
-             warned = true;
+                     rel->r_offset, (!info->shared
+                                     || info->no_undefined
+                                     || ELF_ST_VISIBILITY (h->other)))))
+               return FALSE;
+             warned = TRUE;
+           }
+       }
+
+      /* TLS optimizations.  */
+      tls_type = 0;
+      if (IS_TLS_RELOC (r_type))
+       {
+         if (h != NULL)
+           tls_type = ((struct ppc_link_hash_entry *) h)->tls_type;
+         else if (local_got_ents != NULL)
+           {
+             char *lgot_types;
+             lgot_types = (char *) (local_got_ents + symtab_hdr->sh_info);
+             tls_type = lgot_types[r_symndx];
+           }
+       }
+
+      /* Ensure reloc mapping code below stays sane.  */
+      if (R_PPC64_TOC16_LO_DS != R_PPC64_TOC16_DS + 1
+         || R_PPC64_TOC16_LO != R_PPC64_TOC16 + 1
+         || (R_PPC64_GOT_TLSLD16 & 3)    != (R_PPC64_GOT_TLSGD16 & 3)
+         || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TLSGD16_LO & 3)
+         || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TLSGD16_HI & 3)
+         || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TLSGD16_HA & 3)
+         || (R_PPC64_GOT_TLSLD16 & 3)    != (R_PPC64_GOT_TPREL16_DS & 3)
+         || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TPREL16_LO_DS & 3)
+         || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3)
+         || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3))
+       abort ();
+      switch (r_type)
+       {
+       default:
+         tls_get_addr_type = 0;
+         break;
+
+       case R_PPC64_TOC16:
+       case R_PPC64_TOC16_LO:
+       case R_PPC64_TOC16_DS:
+       case R_PPC64_TOC16_LO_DS:
+         tls_get_addr_type = 0;
+         {
+           /* Check for toc tls entries.  */
+           char *toc_tls;
+
+           if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd))
+             return FALSE;
+
+           if (toc_tls)
+             {
+               tls_type = *toc_tls;
+               if (r_type == R_PPC64_TOC16_DS
+                   || r_type == R_PPC64_TOC16_LO_DS)
+                 goto toctprel;
+               else
+                 tls_get_addr_type = tls_type;
+             }
+         }
+         break;
+
+       case R_PPC64_GOT_TPREL16_DS:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+         tls_get_addr_type = 0;
+       toctprel:
+         if (tls_type != 0
+             && (tls_type & TLS_TPREL) == 0)
+           {
+             bfd_vma insn;
+             insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
+             insn &= 31 << 21;
+             insn |= 0x3c0d0000;       /* addis 0,13,0 */
+             bfd_put_32 (output_bfd, insn, contents + rel->r_offset - 2);
+             r_type = R_PPC64_TPREL16_HA;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+           }
+         break;
+
+       case R_PPC64_TLS:
+         tls_get_addr_type = 0;
+         if (tls_type == 0)
+           {
+             /* Check for toc tls entries.  */
+             char *toc_tls;
+
+             if (!get_tls_type (&toc_tls, &local_syms, rel, input_bfd))
+               return FALSE;
+
+             if (toc_tls)
+               tls_type = *toc_tls;
+           }
+         if (tls_type != 0
+             && (tls_type & TLS_TPREL) == 0)
+           {
+             bfd_vma insn, rtra;
+             insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+             if ((insn & ((31 << 26) | (31 << 11)))
+                 == ((31 << 26) | (13 << 11)))
+               rtra = insn & ((1 << 26) - (1 << 16));
+             else if ((insn & ((31 << 26) | (31 << 16)))
+                      == ((31 << 26) | (13 << 16)))
+               rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
+             else
+               abort ();
+             if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1)
+               /* add -> addi.  */
+               insn = 14 << 26;
+             else if ((insn & (31 << 1)) == 23 << 1
+                      && ((insn & (31 << 6)) < 14 << 6
+                          || ((insn & (31 << 6)) >= 16 << 6
+                              && (insn & (31 << 6)) < 24 << 6)))
+               /* load and store indexed -> dform.  */
+               insn = (32 | ((insn >> 6) & 31)) << 26;
+             else if ((insn & (31 << 1)) == 21 << 1
+                      && (insn & (0x1a << 6)) == 0)
+               /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
+               insn = (((58 | ((insn >> 6) & 4)) << 26)
+                       | ((insn >> 6) & 1));
+             else if ((insn & (31 << 1)) == 21 << 1
+                      && (insn & ((1 << 11) - (1 << 1))) == 341 << 1)
+               /* lwax -> lwa.  */
+               insn = (58 << 26) | 2;
+             else
+               abort ();
+             insn |= rtra;
+             bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+             r_type = R_PPC64_TPREL16_LO;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             /* Was PPC64_TLS which sits on insn boundary, now
+                PPC64_TPREL16_LO which is at insn+2.  */
+             rel->r_offset += 2;
+           }
+         break;
+
+       case R_PPC64_GOT_TLSGD16:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TLSGD16_HI:
+       case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TLSLD16:
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSLD16_HI:
+       case R_PPC64_GOT_TLSLD16_HA:
+         tls_get_addr_type = 0;
+         if (tls_type != 0 && (tls_type & TLS_GD_LD) == 0)
+           {
+             if (r_type == R_PPC64_GOT_TLSGD16_HI
+                 || r_type == R_PPC64_GOT_TLSGD16_HA
+                 || r_type == R_PPC64_GOT_TLSLD16_HI
+                 || r_type == R_PPC64_GOT_TLSLD16_HA)
+               {
+                 if ((tls_type & TLS_LD) != 0)
+                   {
+                     bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+                     r_type = R_PPC64_NONE;
+                     rel->r_offset -= 2;
+                   }
+                 else
+                   r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
+                             + R_PPC64_GOT_TPREL16_DS);
+                 rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+                 break;
+               }
+
+             /* This reloc and its instruction will be replaced so there's
+                not much point in doing anything more here.  We know the
+                next reloc will be a REL24 to __tls_get_addr, and will
+                be handled below.  */
+             tls_get_addr_type = tls_type;
+             continue;
+           }
+         break;
+
+       case R_PPC64_REL14:
+       case R_PPC64_REL14_BRTAKEN:
+       case R_PPC64_REL14_BRNTAKEN:
+       case R_PPC64_REL24:
+         if (h != NULL
+             && h == htab->tls_get_addr
+             && tls_get_addr_type != 0
+             && (tls_get_addr_type & TLS_GD_LD) == 0)
+           {
+             /* Replace the call.  */
+             bfd_vma insn1, insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             insn1 = bfd_get_32 (output_bfd, contents + rel[-1].r_offset - 2);
+             insn3 = bfd_get_32 (output_bfd, contents + offset + 4);
+             if (tls_get_addr_type & TLS_TPREL)
+               {
+                 /* IE */
+                 insn1 &= (1 << 26) - (1 << 2);
+                 insn1 |= 58 << 26;    /* ld */
+                 insn2 = 0x7c636a14;   /* add 3,3,13 */
+                 /* Fix the relocs for --emit-relocs.  */
+                 r_type = ELF64_R_TYPE (rel[-1].r_info);
+                 if (tls_get_addr_type & TLS_EXPLICIT)
+                   r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
+                 else
+                   r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
+                             + R_PPC64_GOT_TPREL16_DS);
+                 rel[-1].r_info
+                   = ELF64_R_INFO (ELF64_R_SYM (rel[-1].r_info), r_type);
+                 rel->r_info = 0;
+               }
+             else
+               {
+                 /* LE */
+                 insn1 = 0x3c6d0000;   /* addis 3,13,0 */
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+                 if (tls_get_addr_type & TLS_LD)
+                   {
+                     r_symndx = 0;
+                     rel[-1].r_addend = htab->tls_sec->vma + DTP_OFFSET;
+                     rel->r_addend = htab->tls_sec->vma + DTP_OFFSET;
+                   }
+                 else
+                   r_symndx = ELF64_R_SYM (rel[-1].r_info);
+                 rel[-1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_HA);
+                 rel->r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_LO);
+                 rel->r_offset += 2;
+               }
+             if (insn3 == NOP
+                 || insn3 == CROR_151515 || insn3 == CROR_313131)
+               {
+                 insn3 = insn2;
+                 insn2 = NOP;
+                 rel->r_offset += 4;
+               }
+             bfd_put_32 (output_bfd, insn1, contents + rel[-1].r_offset - 2);
+             bfd_put_32 (output_bfd, insn2, contents + offset);
+             bfd_put_32 (output_bfd, insn3, contents + offset + 4);
+             /* Do the relocs again.  */
+             rel -= 2;
+             tls_get_addr_type = 0;
+             continue;
+           }
+         tls_get_addr_type = 0;
+         break;
+
+       case R_PPC64_DTPMOD64:
+         if ((tls_type & TLS_GD_LD) == 0)
+           {
+             if ((tls_type & TLS_TPREL) != 0)
+               r_type = R_PPC64_TPREL64;
+             else
+               {
+                 bfd_put_64 (output_bfd, (bfd_vma) 1,
+                             contents + rel->r_offset);
+                 r_type = R_PPC64_NONE;
+               }
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             if ((tls_type & TLS_LD) == 0)
+               rel[1].r_info = 0;
+           }
+         break;
+
+       case R_PPC64_TPREL64:
+         if ((tls_type & TLS_TPREL) == 0)
+           {
+             r_type = R_PPC64_NONE;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
            }
+         break;
        }
 
-      /* First handle relocations that tweak non-addend part of insn.  */
+      /* Handle other relocations that tweak non-addend part of insn.  */
       insn = 0;
       switch (r_type)
        {
@@ -5236,7 +7310,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* Branch not taken prediction relocations.  */
        case R_PPC64_ADDR14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
-         insn |= bfd_get_32 (output_bfd, contents + offset) & ~(0x01 << 21);
+         insn |= bfd_get_32 (output_bfd,
+                             contents + rel->r_offset) & ~(0x01 << 21);
          if (is_power4)
            {
              /* Set 'a' bit.  This is 0b00010 in BO field for branch
@@ -5251,16 +7326,16 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else
            {
-             from = (offset
+             from = (rel->r_offset
                      + input_section->output_offset
                      + input_section->output_section->vma);
 
              /* Invert 'y' bit if not the default.  */
-             if ((bfd_signed_vma) (relocation + addend - from) < 0)
+             if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
                insn ^= 0x01 << 21;
            }
 
-         bfd_put_32 (output_bfd, (bfd_vma) insn, contents + offset);
+         bfd_put_32 (output_bfd, (bfd_vma) insn, contents + rel->r_offset);
          break;
 
        case R_PPC64_REL24:
@@ -5271,20 +7346,20 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             need for a PLT entry.  */
          if (h != NULL
              && (fdh = ((struct ppc_link_hash_entry *) h)->oh) != NULL
-             && fdh->plt.offset != (bfd_vma) -1
+             && fdh->plt.plist != NULL
              && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
                                                   rel, htab)) != NULL)
            {
-             boolean can_plt_call = 0;
+             bfd_boolean can_plt_call = 0;
 
-             if (offset + 8 <= input_section->_cooked_size)
+             if (rel->r_offset + 8 <= input_section->_cooked_size)
                {
-                 insn = bfd_get_32 (input_bfd, contents + offset + 4);
+                 insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
                  if (insn == NOP
                      || insn == CROR_151515 || insn == CROR_313131)
                    {
                      bfd_put_32 (input_bfd, (bfd_vma) LD_R2_40R1,
-                                 contents + offset + 4);
+                                 contents + rel->r_offset + 4);
                      can_plt_call = 1;
                    }
                }
@@ -5293,7 +7368,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                {
                  /* If this is a plain branch rather than a branch
                     and link, don't require a nop.  */
-                 insn = bfd_get_32 (input_bfd, contents + offset);
+                 insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  if ((insn & 1) == 0)
                    can_plt_call = 1;
                }
@@ -5303,15 +7378,14 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                  relocation = (stub_entry->stub_offset
                                + stub_entry->stub_sec->output_offset
                                + stub_entry->stub_sec->output_section->vma);
-                 addend = 0;
-                 unresolved_reloc = false;
+                 unresolved_reloc = FALSE;
                }
            }
 
          if (h != NULL
              && h->root.type == bfd_link_hash_undefweak
              && relocation == 0
-             && addend == 0)
+             && rel->r_addend == 0)
            {
              /* Tweak calls to undefined weak functions to point at a
                 blr.  We can thus call a weak function without first
@@ -5321,7 +7395,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              relocation = (htab->sfpr->_raw_size - 4
                            + htab->sfpr->output_offset
                            + htab->sfpr->output_section->vma);
-             from = (offset
+             from = (rel->r_offset
                      + input_section->output_offset
                      + input_section->output_section->vma);
 
@@ -5335,6 +7409,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        }
 
       /* Set `addend'.  */
+      tls_type = 0;
+      addend = rel->r_addend;
       switch (r_type)
        {
        default:
@@ -5343,38 +7419,85 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             bfd_archive_filename (input_bfd), (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
-         ret = false;
+         ret = FALSE;
          continue;
 
        case R_PPC64_NONE:
-       case R_PPC_GNU_VTINHERIT:
-       case R_PPC_GNU_VTENTRY:
+       case R_PPC64_TLS:
+       case R_PPC64_GNU_VTINHERIT:
+       case R_PPC64_GNU_VTENTRY:
          continue;
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
             address in the GOT as relocation value instead of the
-            symbols value itself.  Also, create a GOT entry for the
+            symbol's value itself.  Also, create a GOT entry for the
             symbol and put the symbol value there.  */
+       case R_PPC64_GOT_TLSGD16:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TLSGD16_HI:
+       case R_PPC64_GOT_TLSGD16_HA:
+         tls_type = TLS_TLS | TLS_GD_LD;
+         goto dogot;
+
+       case R_PPC64_GOT_TLSLD16:
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSLD16_HI:
+       case R_PPC64_GOT_TLSLD16_HA:
+         tls_type = TLS_TLS | TLS_GD_LD | TLS_LD;
+         goto dogot;
+
+       case R_PPC64_GOT_TPREL16_DS:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_TPREL16_HI:
+       case R_PPC64_GOT_TPREL16_HA:
+         tls_type = TLS_TLS | TLS_TPREL;
+         goto dogot;
+
+       case R_PPC64_GOT_DTPREL16_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_HI:
+       case R_PPC64_GOT_DTPREL16_HA:
+         tls_type = TLS_TLS | TLS_DTPREL;
+         goto dogot;
+
        case R_PPC64_GOT16:
        case R_PPC64_GOT16_LO:
        case R_PPC64_GOT16_HI:
        case R_PPC64_GOT16_HA:
        case R_PPC64_GOT16_DS:
        case R_PPC64_GOT16_LO_DS:
+       dogot:
          {
            /* Relocation is to the entry for this symbol in the global
               offset table.  */
+           struct got_entry *ent;
            bfd_vma off;
+           unsigned long indx;
 
            if (htab->sgot == NULL)
              abort ();
 
            if (h != NULL)
+             ent = h->got.glist;
+           else
              {
-               boolean dyn;
+               if (local_got_ents == NULL)
+                 abort ();
+               ent = local_got_ents[r_symndx];
+             }
 
-               off = h->got.offset;
-               dyn = htab->elf.dynamic_sections_created;
+           for (; ent != NULL; ent = ent->next)
+             if (ent->addend == rel->r_addend
+                 && ent->tls_type == tls_type)
+               break;
+           if (ent == NULL)
+             abort ();
+
+           off = ent->got.offset;
+           indx = 0;
+           if (h != NULL)
+             {
+               bfd_boolean dyn = htab->elf.dynamic_sections_created;
                if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)
                    || (info->shared
                        && (info->symbolic
@@ -5383,67 +7506,87 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                & ELF_LINK_FORCED_LOCAL))
                        && (h->elf_link_hash_flags
                            & ELF_LINK_HASH_DEF_REGULAR)))
+                 /* This is actually a static link, or it is a
+                    -Bsymbolic link and the symbol is defined
+                    locally, or the symbol was forced to be local
+                    because of a version file.  */
+                 ;
+               else
                  {
-                   /* This is actually a static link, or it is a
-                      -Bsymbolic link and the symbol is defined
-                      locally, or the symbol was forced to be local
-                      because of a version file.  We must initialize
-                      this entry in the global offset table.  Since the
-                      offset must always be a multiple of 8, we use the
-                      least significant bit to record whether we have
-                      initialized it already.
-
-                      When doing a dynamic link, we create a .rel.got
-                      relocation entry to initialize the value.  This
-                      is done in the finish_dynamic_symbol routine.  */
-                   if ((off & 1) != 0)
-                     off &= ~1;
-                   else
-                     {
-                       bfd_put_64 (output_bfd, relocation,
-                                   htab->sgot->contents + off);
-                       h->got.offset |= 1;
-                     }
+                   indx = h->dynindx;
+                   unresolved_reloc = FALSE;
                  }
-               else
-                 unresolved_reloc = false;
              }
+
+           /* The offset must always be a multiple of 8.  We use the
+              least significant bit to record whether we have already
+              processed this entry.  */
+           if ((off & 1) != 0)
+             off &= ~1;
            else
              {
-               if (local_got_offsets == NULL)
-                 abort ();
-
-               off = local_got_offsets[r_symndx];
+               /* Generate relocs for the dynamic linker, except in
+                  the case of TLSLD where we'll use one entry per
+                  module.  */
+               if ((info->shared || indx != 0)
+                   && ent->tls_type != (TLS_TLS | TLS_GD_LD | TLS_LD))
+                 {
+                   outrel.r_offset = (htab->sgot->output_section->vma
+                                      + htab->sgot->output_offset
+                                      + off);
+                   if (ent->tls_type == (TLS_TLS | TLS_GD_LD))
+                     {
+                       outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64);
+                       outrel.r_addend = 0;
+                       loc = htab->srelgot->contents;
+                       loc += (htab->srelgot->reloc_count++
+                               * sizeof (Elf64_External_Rela));
+                       bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+                       outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
+                       outrel.r_offset += 8;
+                     }
+                   else if (ent->tls_type == (TLS_TLS | TLS_DTPREL))
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
+                   else if (ent->tls_type == (TLS_TLS | TLS_TPREL))
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
+                   else if (indx == 0)
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE);
+                   else
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
+                   outrel.r_addend = ent->addend;
+                   if (indx == 0)
+                     outrel.r_addend += relocation;
+                   loc = htab->srelgot->contents;
+                   loc += (htab->srelgot->reloc_count++
+                           * sizeof (Elf64_External_Rela));
+                   bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+                 }
 
-               /* The offset must always be a multiple of 8.  We use
-                  the least significant bit to record whether we have
-                  already processed this entry.  */
-               if ((off & 1) != 0)
-                 off &= ~1;
-               else
+               /* Init the .got section contents if we're not
+                  emitting a reloc.  */
+               if (!(info->shared || indx != 0))
                  {
-                   bfd_put_64 (output_bfd, relocation,
-                               htab->sgot->contents + off);
 
-                   if (info->shared)
+                   relocation += ent->addend;
+                   if ((tls_type & TLS_TLS) != 0)
                      {
-                       Elf_Internal_Rela outrel;
-                       Elf64_External_Rela *loc;
-
-                       /* We need to generate a R_PPC64_RELATIVE reloc
-                          for the dynamic linker.  */
-                       outrel.r_offset = (htab->sgot->output_section->vma
-                                          + htab->sgot->output_offset
-                                          + off);
-                       outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-                       outrel.r_addend = relocation;
-                       loc = (Elf64_External_Rela *) htab->srelgot->contents;
-                       loc += htab->srelgot->reloc_count++;
-                       bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
+                       relocation -= htab->tls_sec->vma + DTP_OFFSET;
+                       if ((tls_type & TLS_TPREL) != 0)
+                         relocation += DTP_OFFSET - TP_OFFSET;
                      }
 
-                   local_got_offsets[r_symndx] |= 1;
+                   if ((tls_type & TLS_GD_LD) != 0)
+                     {
+                       if ((tls_type & TLS_LD) != 0)
+                         relocation = - DTP_OFFSET;
+                       bfd_put_64 (output_bfd, relocation,
+                                   htab->sgot->contents + off + 8);
+                       relocation = 1;
+                     }
+                   bfd_put_64 (output_bfd, relocation,
+                               htab->sgot->contents + off);
                  }
+               ent->got.offset |= 1;
              }
 
            if (off >= (bfd_vma) -2)
@@ -5452,7 +7595,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            relocation = htab->sgot->output_offset + off;
 
            /* TOC base (r2) is TOC start plus 0x8000.  */
-           addend -= TOC_BASE_OFF;
+           addend = - TOC_BASE_OFF;
          }
          break;
 
@@ -5469,19 +7612,23 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          if (h == NULL)
            break;
 
-         if (h->plt.offset == (bfd_vma) -1
-             || htab->splt == NULL)
+         /* It's possible that we didn't make a PLT entry for this
+            symbol.  This happens when statically linking PIC code,
+            or when using -Bsymbolic.  Go find a match if there is a
+            PLT entry.  */
+         if (htab->splt != NULL)
            {
-             /* We didn't make a PLT entry for this symbol.  This
-                happens when statically linking PIC code, or when
-                using -Bsymbolic.  */
-             break;
+             struct plt_entry *ent;
+             for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->addend == rel->r_addend
+                   && ent->plt.offset != (bfd_vma) -1)
+                 {
+                   relocation = (htab->splt->output_section->vma
+                                 + htab->splt->output_offset
+                                 + ent->plt.offset);
+                   unresolved_reloc = FALSE;
+                 }
            }
-
-         relocation = (htab->splt->output_section->vma
-                       + htab->splt->output_offset
-                       + h->plt.offset);
-         unresolved_reloc = false;
          break;
 
          /* TOC16 relocs.  We want the offset relative to the TOC base,
@@ -5514,8 +7661,49 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC64_REL24:
          break;
 
+       case R_PPC64_TPREL16:
+       case R_PPC64_TPREL16_LO:
+       case R_PPC64_TPREL16_HI:
+       case R_PPC64_TPREL16_HA:
+       case R_PPC64_TPREL16_DS:
+       case R_PPC64_TPREL16_LO_DS:
+       case R_PPC64_TPREL16_HIGHER:
+       case R_PPC64_TPREL16_HIGHERA:
+       case R_PPC64_TPREL16_HIGHEST:
+       case R_PPC64_TPREL16_HIGHESTA:
+         addend -= htab->tls_sec->vma + TP_OFFSET;
+         if (info->shared)
+           /* 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;
+         break;
+
+       case R_PPC64_DTPREL16:
+       case R_PPC64_DTPREL16_LO:
+       case R_PPC64_DTPREL16_HI:
+       case R_PPC64_DTPREL16_HA:
+       case R_PPC64_DTPREL16_DS:
+       case R_PPC64_DTPREL16_LO_DS:
+       case R_PPC64_DTPREL16_HIGHER:
+       case R_PPC64_DTPREL16_HIGHERA:
+       case R_PPC64_DTPREL16_HIGHEST:
+       case R_PPC64_DTPREL16_HIGHESTA:
+         addend -= htab->tls_sec->vma + DTP_OFFSET;
+         break;
+
+       case R_PPC64_TPREL64:
+         addend -= htab->tls_sec->vma + TP_OFFSET;
+         goto dodyn;
+
+       case R_PPC64_DTPREL64:
+         addend -= htab->tls_sec->vma + DTP_OFFSET;
+         /* Fall thru */
+
          /* Relocations that may need to be propagated if this is a
             dynamic object.  */
+       case R_PPC64_DTPMOD64:
+       case R_PPC64_REL30:
        case R_PPC64_REL32:
        case R_PPC64_REL64:
        case R_PPC64_ADDR14:
@@ -5532,7 +7720,6 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC64_ADDR16_LO:
        case R_PPC64_ADDR16_LO_DS:
        case R_PPC64_ADDR24:
-       case R_PPC64_ADDR30:
        case R_PPC64_ADDR32:
        case R_PPC64_ADDR64:
        case R_PPC64_UADDR16:
@@ -5541,6 +7728,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          /* r_symndx will be zero only for relocs against symbols
             from removed linkonce sections, or sections discarded by
             a linker script.  */
+       dodyn:
          if (r_symndx == 0)
            break;
          /* Fall thru.  */
@@ -5553,7 +7741,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            break;
 
          if ((info->shared
-              && (IS_ABSOLUTE_RELOC (r_type)
+              && (MUST_BE_DYN_RELOC (r_type)
                   || (h != NULL
                       && h->dynindx != -1
                       && (! info->symbolic
@@ -5571,34 +7759,34 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      || h->root.type == bfd_link_hash_undefined)))
            {
              Elf_Internal_Rela outrel;
-             boolean skip, relocate;
+             bfd_boolean skip, relocate;
              asection *sreloc;
-             Elf64_External_Rela *loc;
+             bfd_byte *loc;
 
              /* When generating a dynamic object, these relocations
                 are copied into the output file to be resolved at run
                 time.  */
 
-             skip = false;
-             relocate = false;
+             skip = FALSE;
+             relocate = FALSE;
 
              outrel.r_offset =
                _bfd_elf_section_offset (output_bfd, info, input_section,
                                         rel->r_offset);
              if (outrel.r_offset == (bfd_vma) -1)
-               skip = true;
+               skip = TRUE;
              else if (outrel.r_offset == (bfd_vma) -2)
-               skip = true, relocate = true;
+               skip = TRUE, relocate = TRUE;
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
-             outrel.r_addend = addend;
+             outrel.r_addend = rel->r_addend;
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
              else if (h != NULL
                       && h->dynindx != -1
                       && !is_opd
-                      && (!IS_ABSOLUTE_RELOC (r_type)
+                      && (!MUST_BE_DYN_RELOC (r_type)
                           || !info->shared
                           || !info->symbolic
                           || (h->elf_link_hash_flags
@@ -5610,18 +7798,23 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                     or this is an opd section reloc which must point
                     at a local function.  */
                  outrel.r_addend += relocation;
-                 relocate = true;
+                 /* ??? why? */
+                 relocate = TRUE;
                  if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC)
                    {
-                     if (is_opd && h != NULL && info->shared)
+                     if (is_opd && h != NULL)
                        {
                          /* Lie about opd entries.  This case occurs
                             when building shared libraries and we
                             reference a function in another shared
-                            lib.  In that case we won't use the opd
-                            entry in this lib;  We ought to edit the
-                            opd section to remove unused entries.  */
-                         unresolved_reloc = false;
+                            lib.  The same thing happens for a weak
+                            definition in an application that's
+                            overridden by a strong definition in a
+                            shared lib.  (I believe this is a generic
+                            bug in binutils handling of weak syms.)
+                            In these cases we won't use the opd
+                            entry in this lib.  */
+                         unresolved_reloc = FALSE;
                        }
                      outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
                    }
@@ -5634,7 +7827,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                      else if (sec == NULL || sec->owner == NULL)
                        {
                          bfd_set_error (bfd_error_bad_value);
-                         return false;
+                         return FALSE;
                        }
                      else
                        {
@@ -5659,8 +7852,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              if (sreloc == NULL)
                abort ();
 
-             loc = (Elf64_External_Rela *) sreloc->contents;
-             loc += sreloc->reloc_count++;
+             loc = sreloc->contents;
+             loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
              bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
 
              /* If this reloc is against an external symbol, it will
@@ -5695,7 +7888,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             ppc64_elf_howto_table[(int) r_type]->name, sym_name);
 
          bfd_set_error (bfd_error_invalid_operation);
-         ret = false;
+         ret = FALSE;
          continue;
        }
 
@@ -5708,9 +7901,25 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC64_ADDR16_HA:
        case R_PPC64_ADDR16_HIGHERA:
        case R_PPC64_ADDR16_HIGHESTA:
+       case R_PPC64_GOT16_HA:
+       case R_PPC64_PLTGOT16_HA:
        case R_PPC64_PLT16_HA:
        case R_PPC64_TOC16_HA:
        case R_PPC64_SECTOFF_HA:
+       case R_PPC64_TPREL16_HA:
+       case R_PPC64_DTPREL16_HA:
+       case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TLSLD16_HA:
+       case R_PPC64_GOT_TPREL16_HA:
+       case R_PPC64_GOT_DTPREL16_HA:
+       case R_PPC64_TPREL16_HIGHER:
+       case R_PPC64_TPREL16_HIGHERA:
+       case R_PPC64_TPREL16_HIGHEST:
+       case R_PPC64_TPREL16_HIGHESTA:
+       case R_PPC64_DTPREL16_HIGHER:
+       case R_PPC64_DTPREL16_HIGHERA:
+       case R_PPC64_DTPREL16_HIGHEST:
+       case R_PPC64_DTPREL16_HIGHESTA:
          /* It's just possible that this symbol is a weak symbol
             that's not actually defined anywhere. In that case,
             'sec' would be NULL, and we should leave the symbol
@@ -5731,6 +7940,14 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        case R_PPC64_TOC16_LO_DS:
        case R_PPC64_PLTGOT16_DS:
        case R_PPC64_PLTGOT16_LO_DS:
+       case R_PPC64_GOT_TPREL16_DS:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_TPREL16_DS:
+       case R_PPC64_TPREL16_LO_DS:
+       case R_PPC64_DTPREL16_DS:
+       case R_PPC64_DTPREL16_LO_DS:
          if (((relocation + addend) & 3) != 0)
            {
              (*_bfd_error_handler)
@@ -5738,7 +7955,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 bfd_archive_filename (input_bfd),
                 ppc64_elf_howto_table[(int) r_type]->name);
              bfd_set_error (bfd_error_bad_value);
-             ret = false;
+             ret = FALSE;
              continue;
            }
          break;
@@ -5755,7 +7972,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        branch_check:
          /* If the branch is out of reach, then redirect the
             call to the local stub for this function.  */
-         from = (offset
+         from = (rel->r_offset
                  + input_section->output_offset
                  + input_section->output_section->vma);
          if (relocation + addend - from + max_br_offset >= 2 * max_br_offset
@@ -5772,13 +7989,11 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
          break;
        }
 
-      /* FIXME: Why do we allow debugging sections to escape this error?
-        More importantly, why do we not emit dynamic relocs above in
-        debugging sections (which are ! SEC_ALLOC)?  If we had
-        emitted the dynamic reloc, we could remove the fudge here.  */
+      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+        because such sections are not SEC_ALLOC and thus ld.so will
+        not process them.  */
       if (unresolved_reloc
-         && !(info->shared
-              && (input_section->flags & SEC_DEBUGGING) != 0
+         && !((input_section->flags & SEC_DEBUGGING) != 0
               && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
        {
          (*_bfd_error_handler)
@@ -5787,14 +8002,14 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
             bfd_get_section_name (input_bfd, input_section),
             (long) rel->r_offset,
             h->root.root.string);
-         ret = false;
+         ret = FALSE;
        }
 
       r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type],
                                    input_bfd,
                                    input_section,
                                    contents,
-                                   offset,
+                                   rel->r_offset,
                                    relocation,
                                    addend);
 
@@ -5820,13 +8035,9 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
          else
            {
-             name = bfd_elf_string_from_elf_section (input_bfd,
-                                                     symtab_hdr->sh_link,
-                                                     sym->st_name);
+             name = bfd_elf_local_sym_name (input_bfd, sym);
              if (name == NULL)
                continue;
-             if (*name == '\0')
-               name = bfd_section_name (input_bfd, sec);
            }
 
          if (r == bfd_reloc_overflow)
@@ -5835,8 +8046,8 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                continue;
              if (!((*info->callbacks->reloc_overflow)
                    (info, name, ppc64_elf_howto_table[(int) r_type]->name,
-                    rel->r_addend, input_bfd, input_section, offset)))
-               return false;
+                    rel->r_addend, input_bfd, input_section, rel->r_offset)))
+               return FALSE;
            }
          else
            {
@@ -5845,7 +8056,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                 bfd_archive_filename (input_bfd),
                 bfd_get_section_name (input_bfd, input_section),
                 (long) rel->r_offset, name, (int) r);
-             ret = false;
+             ret = FALSE;
            }
        }
     }
@@ -5856,7 +8067,7 @@ ppc64_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
-static boolean
+static bfd_boolean
 ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
      bfd *output_bfd;
      struct bfd_link_info *info;
@@ -5869,84 +8080,43 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
   htab = ppc_hash_table (info);
   dynobj = htab->elf.dynobj;
 
-  if (h->plt.offset != (bfd_vma) -1
-      && ((struct ppc_link_hash_entry *) h)->is_func_descriptor)
+  if (((struct ppc_link_hash_entry *) h)->is_func_descriptor)
     {
+      struct plt_entry *ent;
       Elf_Internal_Rela rela;
-      Elf64_External_Rela *loc;
-
-      /* This symbol has an entry in the procedure linkage table.  Set
-         it up.  */
-
-      if (htab->splt == NULL
-         || htab->srelplt == NULL
-         || htab->sglink == NULL)
-       abort ();
-
-      /* Create a JMP_SLOT reloc to inform the dynamic linker to
-        fill in the PLT entry.  */
-
-      rela.r_offset = (htab->splt->output_section->vma
-                      + htab->splt->output_offset
-                      + h->plt.offset);
-      rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-      rela.r_addend = 0;
-
-      loc = (Elf64_External_Rela *) htab->srelplt->contents;
-      loc += (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE;
-      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-    }
+      bfd_byte *loc;
 
-  if (h->got.offset != (bfd_vma) -1)
-    {
-      Elf_Internal_Rela rela;
-      Elf64_External_Rela *loc;
+      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+       if (ent->plt.offset != (bfd_vma) -1)
+         {
+           /* This symbol has an entry in the procedure linkage
+              table.  Set it up.  */
 
-      /* This symbol has an entry in the global offset table.  Set it
-         up.  */
+           if (htab->splt == NULL
+               || htab->srelplt == NULL
+               || htab->sglink == NULL)
+             abort ();
 
-      if (htab->sgot == NULL || htab->srelgot == NULL)
-       abort ();
+           /* Create a JMP_SLOT reloc to inform the dynamic linker to
+              fill in the PLT entry.  */
 
-      rela.r_offset = (htab->sgot->output_section->vma
-                      + htab->sgot->output_offset
-                      + (h->got.offset &~ (bfd_vma) 1));
-
-      /* If this is a static link, or it is a -Bsymbolic link and the
-        symbol is defined locally or was forced to be local because
-        of a version file, we just want to emit a RELATIVE reloc.
-        The entry in the global offset table will already have been
-        initialized in the relocate_section function.  */
-      if (info->shared
-         && (info->symbolic
-             || h->dynindx == -1
-             || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))
-         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
-       {
-         BFD_ASSERT((h->got.offset & 1) != 0);
-         rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-         rela.r_addend = (h->root.u.def.value
-                          + h->root.u.def.section->output_section->vma
-                          + h->root.u.def.section->output_offset);
-       }
-      else
-       {
-         BFD_ASSERT ((h->got.offset & 1) == 0);
-         bfd_put_64 (output_bfd, (bfd_vma) 0,
-                     htab->sgot->contents + h->got.offset);
-         rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_GLOB_DAT);
-         rela.r_addend = 0;
-       }
+           rela.r_offset = (htab->splt->output_section->vma
+                            + htab->splt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+           rela.r_addend = ent->addend;
 
-      loc = (Elf64_External_Rela *) htab->srelgot->contents;
-      loc += htab->srelgot->reloc_count++;
-      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
+           loc = htab->srelplt->contents;
+           loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+                   * sizeof (Elf64_External_Rela));
+           bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
+         }
     }
 
   if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
     {
       Elf_Internal_Rela rela;
-      Elf64_External_Rela *loc;
+      bfd_byte *loc;
 
       /* This symbol needs a copy reloc.  Set it up.  */
 
@@ -5961,8 +8131,8 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
                       + h->root.u.def.section->output_offset);
       rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY);
       rela.r_addend = 0;
-      loc = (Elf64_External_Rela *) htab->srelbss->contents;
-      loc += htab->srelbss->reloc_count++;
+      loc = htab->srelbss->contents;
+      loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
@@ -5970,7 +8140,7 @@ ppc64_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
   if (strcmp (h->root.root.string, "_DYNAMIC") == 0)
     sym->st_shndx = SHN_ABS;
 
-  return true;
+  return TRUE;
 }
 
 /* Used to decide how to sort relocs in an optimal manner for the
@@ -5980,9 +8150,9 @@ static enum elf_reloc_type_class
 ppc64_elf_reloc_type_class (rela)
      const Elf_Internal_Rela *rela;
 {
-  enum elf_ppc_reloc_type r_type;
+  enum elf_ppc64_reloc_type r_type;
 
-  r_type = (enum elf_ppc_reloc_type) ELF64_R_TYPE (rela->r_info);
+  r_type = (enum elf_ppc64_reloc_type) ELF64_R_TYPE (rela->r_info);
   switch (r_type)
     {
     case R_PPC64_RELATIVE:
@@ -5998,7 +8168,7 @@ ppc64_elf_reloc_type_class (rela)
 
 /* Finish up the dynamic sections.  */
 
-static boolean
+static bfd_boolean
 ppc64_elf_finish_dynamic_sections (output_bfd, info)
      bfd *output_bfd;
      struct bfd_link_info *info;
@@ -6033,30 +8203,32 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
              continue;
 
            case DT_PPC64_GLINK:
-             dyn.d_un.d_ptr = (htab->sglink->output_section->vma
-                               + htab->sglink->output_offset);
+             s = htab->sglink;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_PPC64_OPD:
              s = bfd_get_section_by_name (output_bfd, ".opd");
-             if (s != NULL)
-               dyn.d_un.d_ptr = s->vma;
+             if (s == NULL)
+               continue;
+             dyn.d_un.d_ptr = s->vma;
              break;
 
            case DT_PPC64_OPDSZ:
              s = bfd_get_section_by_name (output_bfd, ".opd");
-             if (s != NULL)
-               dyn.d_un.d_val = s->_raw_size;
+             if (s == NULL)
+               continue;
+             dyn.d_un.d_val = s->_raw_size;
              break;
 
            case DT_PLTGOT:
-             dyn.d_un.d_ptr = (htab->splt->output_section->vma
-                               + htab->splt->output_offset);
+             s = htab->splt;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_JMPREL:
-             dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
-                               + htab->srelplt->output_offset);
+             s = htab->srelplt;
+             dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
            case DT_PLTRELSZ:
@@ -6066,8 +8238,22 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
            case DT_RELASZ:
              /* Don't count procedure linkage table relocs in the
                 overall reloc count.  */
-             if (htab->srelplt != NULL)
-               dyn.d_un.d_val -= htab->srelplt->_raw_size;
+             s = htab->srelplt;
+             if (s == NULL)
+               continue;
+             dyn.d_un.d_val -= s->_raw_size;
+             break;
+
+           case DT_RELA:
+             /* We may not be using the standard ELF linker script.
+                If .rela.plt is the first .rela section, we adjust
+                DT_RELA to not include it.  */
+             s = htab->srelplt;
+             if (s == NULL)
+               continue;
+             if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset)
+               continue;
+             dyn.d_un.d_ptr += s->_raw_size;
              break;
            }
 
@@ -6094,7 +8280,7 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
        = PLT_ENTRY_SIZE;
     }
 
-  return true;
+  return TRUE;
 }
 
 #define TARGET_LITTLE_SYM      bfd_elf64_powerpcle_vec
@@ -6126,13 +8312,12 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
 #define elf_backend_rela_normal 1
 
 #define bfd_elf64_bfd_reloc_type_lookup              ppc64_elf_reloc_type_lookup
-#define bfd_elf64_bfd_set_private_flags              ppc64_elf_set_private_flags
 #define bfd_elf64_bfd_merge_private_bfd_data  ppc64_elf_merge_private_bfd_data
+#define bfd_elf64_new_section_hook           ppc64_elf_new_section_hook
 #define bfd_elf64_bfd_link_hash_table_create  ppc64_elf_link_hash_table_create
 #define bfd_elf64_bfd_link_hash_table_free    ppc64_elf_link_hash_table_free
-#define bfd_elf64_get_symbol_info            ppc64_elf_get_symbol_info
 
-#define elf_backend_section_from_shdr        ppc64_elf_section_from_shdr
+#define elf_backend_object_p                 ppc64_elf_object_p
 #define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
 #define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
 #define elf_backend_check_relocs             ppc64_elf_check_relocs
@@ -6142,7 +8327,6 @@ ppc64_elf_finish_dynamic_sections (output_bfd, info)
 #define elf_backend_hide_symbol                      ppc64_elf_hide_symbol
 #define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
-#define elf_backend_fake_sections            ppc64_elf_fake_sections
 #define elf_backend_relocate_section         ppc64_elf_relocate_section
 #define elf_backend_finish_dynamic_symbol     ppc64_elf_finish_dynamic_symbol
 #define elf_backend_reloc_type_class         ppc64_elf_reloc_type_class
This page took 0.14166 seconds and 4 git commands to generate.