OSDN Git Service

2011-12-13 Shinichiro Hamaji <shinichiro.hamaji@gmail.com>
[pf3gnuchains/pf3gnuchains4x.git] / bfd / elf64-ppc.c
index a181c28..4560599 100644 (file)
@@ -1,9 +1,9 @@
 /* PowerPC64-specific support for 64-bit ELF.
    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009 Free Software Foundation, Inc.
+   2009, 2010, 2011 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
-   Largely rewritten by Alan Modra <amodra@bigpond.net.au>
+   Largely rewritten by Alan Modra.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -34,6 +34,7 @@
 #include "elf-bfd.h"
 #include "elf/ppc64.h"
 #include "elf64-ppc.h"
+#include "dwarf2.h"
 
 static bfd_reloc_status_type ppc64_elf_ha_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
@@ -61,6 +62,7 @@ static bfd_vma opd_entry_value
 #define TARGET_BIG_SYM         bfd_elf64_powerpc_vec
 #define TARGET_BIG_NAME                "elf64-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
+#define ELF_TARGET_ID          PPC64_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
 #define ELF_COMMONPAGESIZE     0x1000
@@ -78,12 +80,13 @@ static bfd_vma opd_entry_value
 
 #define bfd_elf64_mkobject                   ppc64_elf_mkobject
 #define bfd_elf64_bfd_reloc_type_lookup              ppc64_elf_reloc_type_lookup
-#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup
-#define bfd_elf64_bfd_merge_private_bfd_data  ppc64_elf_merge_private_bfd_data
+#define bfd_elf64_bfd_reloc_name_lookup              ppc64_elf_reloc_name_lookup
+#define bfd_elf64_bfd_merge_private_bfd_data  _bfd_generic_verify_endian_match
 #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_synthetic_symtab       ppc64_elf_get_synthetic_symtab
+#define bfd_elf64_bfd_link_just_syms         ppc64_elf_link_just_syms
 
 #define elf_backend_object_p                 ppc64_elf_object_p
 #define elf_backend_grok_prstatus            ppc64_elf_grok_prstatus
@@ -1279,6 +1282,20 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_TOCSAVE,
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_TOCSAVE",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC64_DTPMOD64,
@@ -2526,6 +2543,54 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   return bfd_reloc_dangerous;
 }
 
+/* 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;
+
+  /* The symbol addend that we'll be placing in the GOT.  */
+  bfd_vma addend;
+
+  /* Unlike other ELF targets, we use separate GOT entries for the same
+     symbol referenced from different input files.  This is to support
+     automatic multiple TOC/GOT sections, where the TOC base can vary
+     from one input file to another.  After partitioning into TOC groups
+     we merge entries within the group.
+
+     Point to the BFD owning this GOT entry.  */
+  bfd *owner;
+
+  /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
+     TLS_TPREL or TLS_DTPREL for tls entries.  */
+  unsigned char tls_type;
+
+  /* Non-zero if got.ent points to real entry.  */
+  unsigned char is_indirect;
+
+  /* Reference count until size_dynamic_sections, GOT offset thereafter.  */
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+      struct got_entry *ent;
+    } got;
+};
+
+/* The same for PLT.  */
+struct plt_entry
+{
+  struct plt_entry *next;
+
+  bfd_vma addend;
+
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } plt;
+};
+
 struct ppc64_elf_obj_tdata
 {
   struct elf_obj_tdata elf;
@@ -2538,15 +2603,20 @@ struct ppc64_elf_obj_tdata
      on removed .opd entries to this section so that the sym is removed.  */
   asection *deleted_section;
 
-  /* TLS local dynamic got entry handling.  Suppose for multiple GOT
+  /* TLS local dynamic got entry handling.  Support for multiple GOT
      sections means we potentially need one of these for each input bfd.  */
-  union {
-    bfd_signed_vma refcount;
-    bfd_vma offset;
-  } tlsld_got;
+  struct got_entry tlsld_got;
 
   /* A copy of relocs before they are modified for --emit-relocs.  */
   Elf_Internal_Rela *opd_relocs;
+
+  /* Nonzero if this bfd has small toc/got relocs, ie. that expect
+     the reloc to be in the range -32768 to 32767.  */
+  unsigned int has_small_toc_reloc : 1;
+
+  /* Set if toc/got ha relocs detected not using r2, or lo reloc
+     instruction not one we handle.  */
+  unsigned int unexpected_toc_insn : 1;
 };
 
 #define ppc64_elf_tdata(bfd) \
@@ -2557,7 +2627,7 @@ struct ppc64_elf_obj_tdata
 
 #define is_ppc64_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
-   && elf_object_id (bfd) == PPC64_ELF_TDATA)
+   && elf_object_id (bfd) == PPC64_ELF_DATA)
 
 /* Override the generic function because we store some extras.  */
 
@@ -2565,7 +2635,7 @@ static bfd_boolean
 ppc64_elf_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct ppc64_elf_obj_tdata),
-                                 PPC64_ELF_TDATA);
+                                 PPC64_ELF_DATA);
 }
 
 /* Fix bad default arch selected for a 64 bit input bfd when the
@@ -2602,7 +2672,7 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
 
   /* pr_pid */
-  elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 32);
+  elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
 
   /* pr_reg */
   offset = 112;
@@ -2619,6 +2689,8 @@ ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   if (note->descsz != 136)
     return FALSE;
 
+  elf_tdata (abfd)->core_pid
+    = bfd_get_32 (abfd, note->descdata + 24);
   elf_tdata (abfd)->core_program
     = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
   elf_tdata (abfd)->core_command
@@ -2674,35 +2746,6 @@ ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
     }
 }
 
-/* Merge backend specific data from an object file to the output
-   object file when linking.  */
-
-static bfd_boolean
-ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
-{
-  /* 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;
-
-      if (bfd_big_endian (ibfd))
-       msg = _("%B: compiled for a big endian system "
-               "and target is little endian");
-      else
-       msg = _("%B: compiled for a little endian system "
-               "and target is big endian");
-
-      (*_bfd_error_handler) (msg, ibfd);
-
-      bfd_set_error (bfd_error_wrong_format);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
 /* Add extra PPC sections.  */
 
 static const struct bfd_elf_special_section ppc64_elf_special_sections[]=
@@ -3266,8 +3309,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
                {
                  if (sec->vma > ent)
                    break;
-                 if ((sec->flags & SEC_ALLOC) == 0
-                     || (sec->flags & SEC_LOAD) == 0)
+                 /* SEC_LOAD may not be set if SEC is from a separate debug
+                    info file.  */
+                 if ((sec->flags & SEC_ALLOC) == 0)
                    break;
                  if ((sec->flags & SEC_CODE) != 0)
                    s->section = sec;
@@ -3433,70 +3477,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
    calls may use the function descriptor symbol, ie. "bl foo".  This
    behaves exactly as "bl .foo".  */
 
-/* The linker needs to keep track of the number of relocs that it
-   decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct ppc_dyn_relocs
-{
-  struct ppc_dyn_relocs *next;
-
-  /* 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;
-
-  /* The symbol addend that we'll be placing in the GOT.  */
-  bfd_vma addend;
-
-  /* Unlike other ELF targets, we use separate GOT entries for the same
-     symbol referenced from different input files.  This is to support
-     automatic multiple TOC/GOT sections, where the TOC base can vary
-     from one input file to another.  FIXME: After group_sections we
-     ought to merge entries within the group.
-
-     Point to the BFD owning this GOT entry.  */
-  bfd *owner;
-
-  /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
-     TLS_TPREL or TLS_DTPREL for tls entries.  */
-  char tls_type;
-
-  /* Reference count until size_dynamic_sections, GOT offset thereafter.  */
-  union
-    {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } got;
-};
-
-/* The same for PLT.  */
-struct plt_entry
-{
-  struct plt_entry *next;
-
-  bfd_vma addend;
-
-  union
-    {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } plt;
-};
-
 /* Of those relocs that might be copied as dynamic relocs, this function
    selects those that must be copied when linking a shared library,
    even when the symbol is local.  */
@@ -3663,7 +3643,7 @@ struct ppc_link_hash_entry
   } u;
 
   /* Track dynamic relocs copied for this symbol.  */
-  struct ppc_dyn_relocs *dyn_relocs;
+  struct elf_dyn_relocs *dyn_relocs;
 
   /* Link between function code and descriptor symbols.  */
   struct ppc_link_hash_entry *oh;
@@ -3697,7 +3677,7 @@ struct ppc_link_hash_entry
 #define TLS_EXPLICIT   32      /* Marks TOC section TLS relocs. */
 #define TLS_TPRELGD    64      /* TPREL reloc resulting from GD->IE. */
 #define PLT_IFUNC      128     /* STT_GNU_IFUNC.  */
-  char tls_mask;
+  unsigned char tls_mask;
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -3712,6 +3692,9 @@ struct ppc_link_hash_table
   /* Another hash table for plt_branch stubs.  */
   struct bfd_hash_table branch_hash_table;
 
+  /* Hash table for function prologue tocsave.  */
+  htab_t tocsave_htab;
+
   /* Linker stub bfd.  */
   bfd *stub_bfd;
 
@@ -3732,6 +3715,8 @@ struct ppc_link_hash_table
 
   /* Temp used when calculating TOC pointers.  */
   bfd_vma toc_curr;
+  bfd *toc_bfd;
+  asection *toc_first_sec;
 
   /* Highest input section id.  */
   int top_id;
@@ -3757,17 +3742,24 @@ struct ppc_link_hash_table
   asection *sfpr;
   asection *brlt;
   asection *relbrlt;
+  asection *glink_eh_frame;
 
   /* Shortcut to .__tls_get_addr and __tls_get_addr.  */
   struct ppc_link_hash_entry *tls_get_addr;
   struct ppc_link_hash_entry *tls_get_addr_fd;
 
+  /* The size of reliplt used by got entry relocs.  */
+  bfd_size_type got_reli_size;
+
   /* Statistics.  */
   unsigned long stub_count[ppc_stub_plt_call];
 
   /* Number of stubs against global syms.  */
   unsigned long stub_globals;
 
+  /* Set if PLT call stubs should load r11.  */
+  unsigned int plt_static_chain:1;
+
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
@@ -3775,8 +3767,10 @@ struct ppc_link_hash_table
   unsigned int no_tls_get_addr_opt:1;
 
   /* Support for multiple toc sections.  */
-  unsigned int no_multi_toc:1;
+  unsigned int do_multi_toc:1;
   unsigned int multi_toc_needed:1;
+  unsigned int second_toc_pass:1;
+  unsigned int do_toc_opt:1;
 
   /* Set on error.  */
   unsigned int stub_error:1;
@@ -3793,14 +3787,29 @@ struct ppc_link_hash_table
 
 /* Rename some of the generic section flags to better document how they
    are used here.  */
-#define has_toc_reloc has_gp_reloc
-#define makes_toc_func_call need_finalize_relax
-#define call_check_in_progress reloc_done
+
+/* Nonzero if this section has TLS related relocations.  */
+#define has_tls_reloc sec_flg0
+
+/* Nonzero if this section has a call to __tls_get_addr.  */
+#define has_tls_get_addr_call sec_flg1
+
+/* Nonzero if this section has any toc or got relocs.  */
+#define has_toc_reloc sec_flg2
+
+/* Nonzero if this section has a call to another section that uses
+   the toc or got.  */
+#define makes_toc_func_call sec_flg3
+
+/* Recursion protection when determining above flag.  */
+#define call_check_in_progress sec_flg4
+#define call_check_done sec_flg5
 
 /* Get the ppc64 ELF linker hash table from a link_info structure.  */
 
 #define ppc_hash_table(p) \
-  ((struct ppc_link_hash_table *) ((p)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == PPC64_ELF_DATA ? ((struct ppc_link_hash_table *) ((p)->hash)) : NULL)
 
 #define ppc_stub_hash_lookup(table, string, create, copy) \
   ((struct ppc_stub_hash_entry *) \
@@ -3932,6 +3941,26 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
   return entry;
 }
 
+struct tocsave_entry {
+  asection *sec;
+  bfd_vma offset;
+};
+
+static hashval_t
+tocsave_htab_hash (const void *p)
+{
+  const struct tocsave_entry *e = (const struct tocsave_entry *) p;
+  return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
+}
+
+static int
+tocsave_htab_eq (const void *p1, const void *p2)
+{
+  const struct tocsave_entry *e1 = (const struct tocsave_entry *) p1;
+  const struct tocsave_entry *e2 = (const struct tocsave_entry *) p2;
+  return e1->sec == e2->sec && e1->offset == e2->offset;
+}
+
 /* Create a ppc64 ELF linker hash table.  */
 
 static struct bfd_link_hash_table *
@@ -3945,7 +3974,8 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc,
-                                     sizeof (struct ppc_link_hash_entry)))
+                                     sizeof (struct ppc_link_hash_entry),
+                                     PPC64_ELF_DATA))
     {
       free (htab);
       return NULL;
@@ -3961,6 +3991,13 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
                            sizeof (struct ppc_branch_hash_entry)))
     return NULL;
 
+  htab->tocsave_htab = htab_try_create (1024,
+                                       tocsave_htab_hash,
+                                       tocsave_htab_eq,
+                                       NULL);
+  if (htab->tocsave_htab == NULL)
+    return NULL;
+
   /* Initializing two fields of the union is just cosmetic.  We really
      only care about glist, but when compiled on a 32-bit host the
      bfd_vma fields are larger.  Setting the bfd_vma to zero makes
@@ -3982,10 +4019,12 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
 static void
 ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
 {
-  struct ppc_link_hash_table *ret = (struct ppc_link_hash_table *) hash;
+  struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash;
 
-  bfd_hash_table_free (&ret->stub_hash_table);
-  bfd_hash_table_free (&ret->branch_hash_table);
+  bfd_hash_table_free (&htab->stub_hash_table);
+  bfd_hash_table_free (&htab->branch_hash_table);
+  if (htab->tocsave_htab)
+    htab_delete (htab->tocsave_htab);
   _bfd_generic_link_hash_table_free (hash);
 }
 
@@ -4002,6 +4041,8 @@ ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
    linker created stub bfd.  This ensures that the GOT header is at
    the start of the output TOC section.  */
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return;
   htab->stub_bfd = abfd;
   htab->elf.dynobj = abfd;
 }
@@ -4103,8 +4144,9 @@ ppc_get_stub_entry (const asection *input_section,
 static struct ppc_stub_hash_entry *
 ppc_add_stub (const char *stub_name,
              asection *section,
-             struct ppc_link_hash_table *htab)
+             struct bfd_link_info *info)
 {
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
   asection *link_sec;
   asection *stub_sec;
   struct ppc_stub_hash_entry *stub_entry;
@@ -4141,8 +4183,8 @@ ppc_add_stub (const char *stub_name,
                                     TRUE, FALSE);
   if (stub_entry == NULL)
     {
-      (*_bfd_error_handler) (_("%B: cannot create stub entry %s"),
-                            section->owner, stub_name);
+      info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
+                             section->owner, stub_name);
       return NULL;
     }
 
@@ -4161,6 +4203,8 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   flagword flags;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Create .sfpr for code to save and restore fp regs.  */
   flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
@@ -4178,6 +4222,18 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
     return FALSE;
 
+  if (!info->no_ld_generated_unwind_info)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
+                                                                ".eh_frame",
+                                                                flags);
+      if (htab->glink_eh_frame == NULL
+         || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2))
+       return FALSE;
+    }
+
   flags = SEC_ALLOC | SEC_LINKER_CREATED;
   htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
   if (htab->iplt == NULL
@@ -4229,6 +4285,8 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   if (!is_ppc64_elf (abfd))
     return FALSE;
+  if (htab == NULL)
+    return FALSE;
 
   if (!htab->got)
     {
@@ -4270,6 +4328,9 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   if (!htab->got)
     htab->got = bfd_get_section_by_name (dynobj, ".got");
   htab->plt = bfd_get_section_by_name (dynobj, ".plt");
@@ -4355,19 +4416,38 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
   edir = (struct ppc_link_hash_entry *) dir;
   eind = (struct ppc_link_hash_entry *) ind;
 
+  edir->is_func |= eind->is_func;
+  edir->is_func_descriptor |= eind->is_func_descriptor;
+  edir->tls_mask |= eind->tls_mask;
+  if (eind->oh != NULL)
+    edir->oh = ppc_follow_link (eind->oh);
+
+  /* If called to transfer flags for a weakdef during processing
+     of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
+     We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
+  if (!(ELIMINATE_COPY_RELOCS
+       && eind->elf.root.type != bfd_link_hash_indirect
+       && edir->elf.dynamic_adjusted))
+    edir->elf.non_got_ref |= eind->elf.non_got_ref;
+
+  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
+  edir->elf.ref_regular |= eind->elf.ref_regular;
+  edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
+  edir->elf.needs_plt |= eind->elf.needs_plt;
+
   /* 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;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          /* Add reloc counts against the indirect sym to the direct sym
             list.  Merge any entries against the same section.  */
          for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
            {
-             struct ppc_dyn_relocs *q;
+             struct elf_dyn_relocs *q;
 
              for (q = edir->dyn_relocs; q != NULL; q = q->next)
                if (q->sec == p->sec)
@@ -4387,26 +4467,13 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
       eind->dyn_relocs = NULL;
     }
 
-  edir->is_func |= eind->is_func;
-  edir->is_func_descriptor |= eind->is_func_descriptor;
-  edir->tls_mask |= eind->tls_mask;
-  if (eind->oh != NULL)
-    edir->oh = ppc_follow_link (eind->oh);
-
-  /* If called to transfer flags for a weakdef during processing
-     of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
-     We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
-  if (!(ELIMINATE_COPY_RELOCS
-       && eind->elf.root.type != bfd_link_hash_indirect
-       && edir->elf.dynamic_adjusted))
-    edir->elf.non_got_ref |= eind->elf.non_got_ref;
-
-  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
-  edir->elf.ref_regular |= eind->elf.ref_regular;
-  edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
-  edir->elf.needs_plt |= eind->elf.needs_plt;
-
-  /* If we were called to copy over info for a weak sym, that's all.  */
+  /* If we were called to copy over info for a weak sym, that's all.
+     You might think dyn_relocs need not be copied over;  After all,
+     both syms will be dynamic or both non-dynamic so we're just
+     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS 
+     code in ppc64_elf_adjust_dynamic_symbol needs to check for
+     dyn_relocs in read-only sections, and it does so on what is the
+     DIR sym here.  */
   if (eind->elf.root.type != bfd_link_hash_indirect)
     return;
 
@@ -4522,7 +4589,7 @@ make_fdh (struct bfd_link_info *info,
    function type.  */
 
 static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
                           struct bfd_link_info *info,
                           Elf_Internal_Sym *isym,
                           const char **name ATTRIBUTE_UNUSED,
@@ -4530,12 +4597,19 @@ ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
                           asection **sec,
                           bfd_vma *value ATTRIBUTE_UNUSED)
 {
+  if ((ibfd->flags & DYNAMIC) == 0
+      && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+
   if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+    {
+      if ((ibfd->flags & DYNAMIC) == 0)
+       elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+    }
   else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
     ;
   else if (*sec != NULL
-          && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
+          && strcmp ((*sec)->name, ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
   return TRUE;
@@ -4602,6 +4676,9 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
     abort ();
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   fdh = lookup_fdh (eh, htab);
   if (fdh == NULL)
     {
@@ -4649,9 +4726,11 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry **p, *eh;
 
-  htab = ppc_hash_table (info);
   if (!is_ppc64_elf (info->output_bfd))
     return TRUE;
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (is_ppc64_elf (ibfd))
     {
@@ -4690,17 +4769,41 @@ static bfd_boolean
 ppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED,
                             struct bfd_link_info *info)
 {
-  ppc_hash_table (info)->dot_syms = NULL;
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  if (htab == NULL)
+    return FALSE;
+
+  htab->dot_syms = NULL;
   return TRUE;
 }
 
+/* If --just-symbols against a final linked binary, then assume we need
+   toc adjusting stubs when calling functions defined there.  */
+
+static void
+ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
+{
+  if ((sec->flags & SEC_CODE) != 0
+      && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0
+      && is_ppc64_elf (sec->owner))
+    {
+      asection *got = bfd_get_section_by_name (sec->owner, ".got");
+      if (got != NULL
+         && got->size >= elf_backend_got_header_size
+         && bfd_get_section_by_name (sec->owner, ".opd") != NULL)
+       sec->has_toc_reloc = 1;
+    }
+  _bfd_elf_link_just_syms (sec, info);
+}
+
 static struct plt_entry **
 update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
                       unsigned long r_symndx, bfd_vma r_addend, int tls_type)
 {
   struct got_entry **local_got_ents = elf_local_got_ents (abfd);
   struct plt_entry **local_plt;
-  char *local_got_tls_masks;
+  unsigned char *local_got_tls_masks;
 
   if (local_got_ents == NULL)
     {
@@ -4734,6 +4837,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
          ent->addend = r_addend;
          ent->owner = abfd;
          ent->tls_type = tls_type;
+         ent->is_indirect = FALSE;
          ent->got.refcount = 0;
          local_got_ents[r_symndx] = ent;
        }
@@ -4741,7 +4845,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
     }
 
   local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
-  local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
+  local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
   local_got_tls_masks[r_symndx] |= tls_type;
 
   return local_plt + r_symndx;
@@ -4793,7 +4897,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 {
   struct ppc_link_hash_table *htab;
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
@@ -4815,20 +4919,18 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   BFD_ASSERT (is_ppc64_elf (abfd));
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
                              FALSE, FALSE, TRUE);
   dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
                                 FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
-
   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)
+  if (strcmp (sec->name, ".opd") == 0)
     {
       /* Garbage collection needs some extra help with .opd sections.
         We don't want to necessarily keep everything referenced by
@@ -4966,6 +5068,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT16_LO_DS:
          /* This symbol requires a global offset table entry.  */
          sec->has_toc_reloc = 1;
+         if (r_type == R_PPC64_GOT_TLSLD16
+             || r_type == R_PPC64_GOT_TLSGD16
+             || r_type == R_PPC64_GOT_TPREL16_DS
+             || r_type == R_PPC64_GOT_DTPREL16_DS
+             || r_type == R_PPC64_GOT16
+             || r_type == R_PPC64_GOT16_DS)
+           {
+             htab->do_multi_toc = 1;
+             ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
+           }
+
          if (ppc64_elf_tdata (abfd)->got == NULL
              && !create_got_section (abfd, info))
            return FALSE;
@@ -4991,6 +5104,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  ent->addend = rel->r_addend;
                  ent->owner = abfd;
                  ent->tls_type = tls_type;
+                 ent->is_indirect = FALSE;
                  ent->got.refcount = 0;
                  eh->elf.got.glist = ent;
                }
@@ -5061,10 +5175,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
        case R_PPC64_TOC16:
+       case R_PPC64_TOC16_DS:
+         htab->do_multi_toc = 1;
+         ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
        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:
          sec->has_toc_reloc = 1;
          break;
@@ -5314,8 +5430,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              || (!info->shared
                  && ifunc != NULL))
            {
-             struct ppc_dyn_relocs *p;
-             struct ppc_dyn_relocs **head;
+             struct elf_dyn_relocs *p;
+             struct elf_dyn_relocs **head;
 
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
@@ -5354,7 +5470,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    s = sec;
 
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct ppc_dyn_relocs **) vpp;
+                 head = (struct elf_dyn_relocs **) vpp;
                }
 
              p = *head;
@@ -5401,9 +5517,12 @@ opd_entry_value (asection *opd_sec,
   /* No relocs implies we are linking a --just-symbols object.  */
   if (opd_sec->reloc_count == 0)
     {
-      if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
+      char buf[8];
+
+      if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
        return (bfd_vma) -1;
 
+      val = bfd_get_64 (opd_bfd, buf);
       if (code_sec != NULL)
        {
          asection *sec, *likely = NULL;
@@ -5498,6 +5617,17 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
+/* Return true if symbol is defined in a regular object file.  */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+  return ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section != NULL
+         && h->root.u.def.section->output_section != NULL);
+}
+
 /* If FDH is a function descriptor symbol, return the associated code
    entry symbol if it is defined.  Return NULL otherwise.  */
 
@@ -5539,6 +5669,9 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   struct bfd_sym_chain *sym;
 
+  if (htab == NULL)
+    return;
+
   for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
     {
       struct ppc_link_hash_entry *eh, *fh;
@@ -5580,9 +5713,6 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
   struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
   struct ppc_link_hash_entry *fdh;
 
-  if (eh->elf.root.type == bfd_link_hash_warning)
-    eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
-
   /* Dynamic linking info is on the func descriptor sym.  */
   fdh = defined_func_desc (eh);
   if (fdh != NULL)
@@ -5594,7 +5724,10 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
          || (!info->executable
              && eh->elf.def_regular
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
-             && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN)))
+             && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
+             && (strchr (eh->elf.root.root.string, ELF_VER_CHR) != NULL
+                 || !bfd_hide_sym_by_version (info->version_info,
+                                              eh->elf.root.root.string)))))
     {
       asection *code_sec;
       struct ppc_link_hash_entry *fh;
@@ -5624,7 +5757,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
 
 static asection *
 ppc64_elf_gc_mark_hook (asection *sec,
-                       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                       struct bfd_link_info *info,
                        Elf_Internal_Rela *rel,
                        struct elf_link_hash_entry *h,
                        Elf_Internal_Sym *sym)
@@ -5683,7 +5816,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
              break;
 
            default:
-             break;
+             return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
            }
        }
     }
@@ -5726,6 +5859,9 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   elf_section_data (sec)->local_dynrel = NULL;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_ents = elf_local_got_ents (abfd);
@@ -5736,15 +5872,15 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h = NULL;
-      char tls_type = 0;
+      unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       r_type = ELF64_R_TYPE (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
        {
          struct ppc_link_hash_entry *eh;
-         struct ppc_dyn_relocs **pp;
-         struct ppc_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
@@ -5771,7 +5907,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            {
              struct plt_entry **local_plt = (struct plt_entry **)
                (local_got_ents + symtab_hdr->sh_info);
-             char *local_got_tls_masks = (char *)
+             unsigned char *local_got_tls_masks = (unsigned char *)
                (local_plt + symtab_hdr->sh_info);
              if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
                ifunc = local_plt + r_symndx;
@@ -5864,9 +6000,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *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)
+             if (ent != NULL && ent->plt.refcount > 0)
                ent->plt.refcount -= 1;
            }
          break;
@@ -5891,7 +6025,7 @@ struct sfpr_def_parms
 
 /* Auto-generate _save*, _rest* functions in .sfpr.  */
 
-static unsigned int
+static bfd_boolean
 sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
@@ -5900,6 +6034,9 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
   bfd_boolean writing = FALSE;
   char sym[16];
 
+  if (htab == NULL)
+    return FALSE;
+
   memcpy (sym, parm->name, len);
   sym[len + 2] = 0;
 
@@ -6121,11 +6258,10 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (fh->elf.root.type == bfd_link_hash_warning)
-    fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link;
-
   info = inf;
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Resolve undefined references to dot-symbols as the value
      in the function descriptor, if we have one in a regular object.
@@ -6264,6 +6400,9 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
     };
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   if (htab->sfpr == NULL)
     /* We don't have any relocs.  */
     return TRUE;
@@ -6296,6 +6435,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   asection *s;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
@@ -6354,7 +6495,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (ELIMINATE_COPY_RELOCS)
     {
       struct ppc_link_hash_entry * eh;
-      struct ppc_dyn_relocs *p;
+      struct elf_dyn_relocs *p;
 
       eh = (struct ppc_link_hash_entry *) h;
       for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -6380,9 +6521,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         function pointers, vtable refs and suchlike in read-only
         sections.  Allow them to proceed, but warn that this might
         break at runtime.  */
-      (*_bfd_error_handler)
-       (_("copy reloc against `%s' requires lazy plt linking; "
-          "avoid setting LD_BIND_NOW=1 or upgrade gcc"),
+      info->callbacks->einfo
+       (_("%P: copy reloc against `%s' requires lazy plt linking; "
+          "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
         h->root.root.string);
     }
 
@@ -6391,8 +6532,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   if (h->size == 0)
     {
-      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
-                            h->root.root.string);
+      info->callbacks->einfo (_("%P: dynamic variable `%s' is zero size\n"),
+                             h->root.root.string);
       return TRUE;
     }
 
@@ -6455,6 +6596,9 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
          save = *p;
          *(char *) p = '.';
          htab = ppc_hash_table (info);
+         if (htab == NULL)
+           return;
+
          fh = (struct ppc_link_hash_entry *)
            elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
          *(char *) p = save;
@@ -6487,7 +6631,7 @@ static bfd_boolean
 get_sym_h (struct elf_link_hash_entry **hp,
           Elf_Internal_Sym **symp,
           asection **symsecp,
-          char **tls_maskp,
+          unsigned char **tls_maskp,
           Elf_Internal_Sym **locsymsp,
           unsigned long r_symndx,
           bfd *ibfd)
@@ -6555,7 +6699,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
       if (tls_maskp != NULL)
        {
          struct got_entry **lgot_ents;
-         char *tls_mask;
+         unsigned char *tls_mask;
 
          tls_mask = NULL;
          lgot_ents = elf_local_got_ents (ibfd);
@@ -6563,7 +6707,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
            {
              struct plt_entry **local_plt = (struct plt_entry **)
                (lgot_ents + symtab_hdr->sh_info);
-             char *lgot_masks = (char *)
+             unsigned char *lgot_masks = (unsigned char *)
                (local_plt + symtab_hdr->sh_info);
              tls_mask = &lgot_masks[r_symndx];
            }
@@ -6578,7 +6722,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
    type suitable for optimization, and 1 otherwise.  */
 
 static int
-get_tls_mask (char **tls_maskp,
+get_tls_mask (unsigned char **tls_maskp,
              unsigned long *toc_symndx,
              bfd_vma *toc_addend,
              Elf_Internal_Sym **locsymsp,
@@ -6598,6 +6742,7 @@ get_tls_mask (char **tls_maskp,
 
   if ((*tls_maskp != NULL && **tls_maskp != 0)
       || sec == NULL
+      || ppc64_elf_section_data (sec) == NULL
       || ppc64_elf_section_data (sec)->sec_type != sec_toc)
     return 1;
 
@@ -6619,15 +6764,61 @@ get_tls_mask (char **tls_maskp,
     *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
   if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
     return 0;
-  if ((h == NULL
-       || ((h->root.type == bfd_link_hash_defined
-           || h->root.type == bfd_link_hash_defweak)
-          && !h->def_dynamic))
+  if ((h == NULL || is_static_defined (h))
       && (next_r == -1 || next_r == -2))
     return 1 - next_r;
   return 1;
 }
 
+/* Find (or create) an entry in the tocsave hash table.  */
+
+static struct tocsave_entry *
+tocsave_find (struct ppc_link_hash_table *htab,
+             enum insert_option insert,
+             Elf_Internal_Sym **local_syms,
+             const Elf_Internal_Rela *irela,
+             bfd *ibfd)
+{
+  unsigned long r_indx;
+  struct elf_link_hash_entry *h;
+  Elf_Internal_Sym *sym;
+  struct tocsave_entry ent, *p;
+  hashval_t hash;
+  struct tocsave_entry **slot;
+
+  r_indx = ELF64_R_SYM (irela->r_info);
+  if (!get_sym_h (&h, &sym, &ent.sec, NULL, local_syms, r_indx, ibfd))
+    return NULL;
+  if (ent.sec == NULL || ent.sec->output_section == NULL)
+    {
+      (*_bfd_error_handler)
+       (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
+      return NULL;
+    }
+
+  if (h != NULL)
+    ent.offset = h->root.u.def.value;
+  else
+    ent.offset = sym->st_value;
+  ent.offset += irela->r_addend;
+
+  hash = tocsave_htab_hash (&ent);
+  slot = ((struct tocsave_entry **)
+         htab_find_slot_with_hash (htab->tocsave_htab, &ent, hash, insert));
+  if (slot == NULL)
+    return NULL;
+
+  if (*slot == NULL)
+    {
+      p = (struct tocsave_entry *) bfd_alloc (ibfd, sizeof (*p));
+      if (p == NULL)
+       return NULL;
+      *p = ent;
+      *slot = p;
+    }
+  return *slot;
+}
+
 /* Adjust all global syms defined in opd sections.  In gcc generated
    code for the old ABI, these will already have been done.  */
 
@@ -6641,9 +6832,6 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   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;
-
   if (h->root.type != bfd_link_hash_defined
       && h->root.type != bfd_link_hash_defweak)
     return TRUE;
@@ -6693,8 +6881,8 @@ dec_dynrel_count (bfd_vma r_info,
                  asection *sym_sec)
 {
   enum elf_ppc64_reloc_type r_type;
-  struct ppc_dyn_relocs *p;
-  struct ppc_dyn_relocs **pp;
+  struct elf_dyn_relocs *p;
+  struct elf_dyn_relocs **pp;
 
   /* Can this reloc be dynamic?  This switch, and later tests here
      should be kept in sync with the code in check_relocs.  */
@@ -6779,12 +6967,12 @@ dec_dynrel_count (bfd_vma r_info,
       if (sym_sec != NULL)
        {
          void *vpp = &elf_section_data (sym_sec)->local_dynrel;
-         pp = (struct ppc_dyn_relocs **) vpp;
+         pp = (struct elf_dyn_relocs **) vpp;
        }
       else
        {
          void *vpp = &elf_section_data (sec)->local_dynrel;
-         pp = (struct ppc_dyn_relocs **) vpp;
+         pp = (struct elf_dyn_relocs **) vpp;
        }
 
       /* elf_gc_sweep may have already removed all dyn relocs associated
@@ -6808,8 +6996,8 @@ dec_dynrel_count (bfd_vma r_info,
       pp = &p->next;
     }
 
-  (*_bfd_error_handler) (_("dynreloc miscount for %B, section %A"),
-                          sec->owner, sec);
+  info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
+                         sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
   return FALSE;
 }
@@ -6821,8 +7009,7 @@ dec_dynrel_count (bfd_vma r_info,
    applications.  */
 
 bfd_boolean
-ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
-                   bfd_boolean non_overlapping)
+ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 {
   bfd *ibfd;
   bfd_boolean some_edited = FALSE;
@@ -6834,12 +7021,14 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       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;
       struct _opd_sec_data *opd;
       bfd_boolean need_edit, add_aux_fields;
       bfd_size_type cnt_16b = 0;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       sec = bfd_get_section_by_name (ibfd, ".opd");
       if (sec == NULL || sec->size == 0)
        continue;
@@ -6856,7 +7045,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
       local_syms = NULL;
       symtab_hdr = &elf_symtab_hdr (ibfd);
-      sym_hashes = elf_sym_hashes (ibfd);
 
       /* Read the relocations.  */
       relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -6983,6 +7171,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       if (need_edit || add_aux_fields)
        {
          Elf_Internal_Rela *write_rel;
+         Elf_Internal_Shdr *rel_hdr;
          bfd_byte *rptr, *wptr;
          bfd_byte *new_contents;
          bfd_boolean skip;
@@ -6992,7 +7181,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
          new_contents = NULL;
          amt = sec->size * sizeof (long) / 8;
          opd = &ppc64_elf_section_data (sec)->u.opd;
-         opd->adjust = bfd_zalloc (obfd, amt);
+         opd->adjust = bfd_zalloc (sec->owner, amt);
          if (opd->adjust == NULL)
            return FALSE;
          ppc64_elf_section_data (sec)->sec_type = sec_opd;
@@ -7068,8 +7257,12 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
                  if (h != NULL
                      && h->root.root.string[0] == '.')
                    {
-                     fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
-                                       ppc_hash_table (info));
+                     struct ppc_link_hash_table *htab;
+
+                     htab = ppc_hash_table (info);
+                     if (htab != NULL)
+                       fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
+                                         htab);
                      if (fdh != NULL
                          && fdh->elf.root.type != bfd_link_hash_defined
                          && fdh->elf.root.type != bfd_link_hash_defweak)
@@ -7158,9 +7351,8 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
          /* Fudge the header 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);
+         rel_hdr = _bfd_elf_single_rel_hdr (sec);
+         rel_hdr->sh_size = sec->reloc_count * rel_hdr->sh_entsize;
          some_edited = TRUE;
        }
       else if (elf_section_data (sec)->relocs != relstart)
@@ -7219,13 +7411,21 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 /* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 asection *
-ppc64_elf_tls_setup (bfd *obfd,
-                    struct bfd_link_info *info,
-                    int no_tls_get_addr_opt)
+ppc64_elf_tls_setup (struct bfd_link_info *info,
+                    int no_tls_get_addr_opt,
+                    int *no_multi_toc)
 {
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return NULL;
+
+  if (*no_multi_toc)
+    htab->do_multi_toc = 0;
+  else if (!htab->do_multi_toc)
+    *no_multi_toc = 1;
+
   htab->tls_get_addr = ((struct ppc_link_hash_entry *)
                        elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
                                              FALSE, FALSE, TRUE));
@@ -7279,7 +7479,7 @@ ppc64_elf_tls_setup (bfd *obfd,
                      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
                                              opt_fd->dynstr_index);
                      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
-                       return FALSE;
+                       return NULL;
                    }
                  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
                  tga = &htab->tls_get_addr->elf;
@@ -7306,7 +7506,7 @@ ppc64_elf_tls_setup (bfd *obfd,
        no_tls_get_addr_opt = TRUE;
     }
   htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
-  return _bfd_elf_tls_setup (obfd, info);
+  return _bfd_elf_tls_setup (info->output_bfd, info);
 }
 
 /* Return TRUE iff REL is a branch reloc with a global symbol matching
@@ -7343,34 +7543,40 @@ branch_reloc_hash_match (const bfd *ibfd,
    dynamic relocations.  */
 
 bfd_boolean
-ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+ppc64_elf_tls_optimize (struct bfd_link_info *info)
 {
   bfd *ibfd;
   asection *sec;
   struct ppc_link_hash_table *htab;
+  unsigned char *toc_ref;
   int pass;
 
   if (info->relocatable || !info->executable)
     return TRUE;
 
   htab = ppc_hash_table (info);
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
-    {
-      Elf_Internal_Sym *locsyms = NULL;
-      asection *toc = bfd_get_section_by_name (ibfd, ".toc");
-      unsigned char *toc_ref = NULL;
-
-      /* Look at all the sections for this file.  Make two passes over
-        the relocs.  On the first pass, mark toc entries involved
-        with tls relocs, and check that tls relocs involved in
-        setting up a tls_get_addr call are indeed followed by such a
-        call.  If they are not, exclude them from the optimizations
-        done on the second pass.  */
-      for (pass = 0; pass < 2; ++pass)
+  if (htab == NULL)
+    return FALSE;
+
+  /* Make two passes over the relocs.  On the first pass, mark toc
+     entries involved with tls relocs, and check that tls relocs
+     involved in setting up a tls_get_addr call are indeed followed by
+     such a call.  If they are not, we can't do any tls optimization.
+     On the second pass twiddle tls_mask flags to notify
+     relocate_section that optimization can be done, and adjust got
+     and plt refcounts.  */
+  toc_ref = NULL;
+  for (pass = 0; pass < 2; ++pass)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+      {
+       Elf_Internal_Sym *locsyms = NULL;
+       asection *toc = bfd_get_section_by_name (ibfd, ".toc");
+
        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;
+             bfd_boolean found_tls_get_addr_arg = 0;
 
              /* Read the relocations.  */
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -7386,12 +7592,13 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                  struct elf_link_hash_entry *h;
                  Elf_Internal_Sym *sym;
                  asection *sym_sec;
-                 char *tls_mask;
-                 char tls_set, tls_clear, tls_type = 0;
+                 unsigned char *tls_mask;
+                 unsigned char tls_set, tls_clear, tls_type = 0;
                  bfd_vma value;
                  bfd_boolean ok_tprel, is_local;
                  long toc_ref_index = 0;
                  int expecting_tls_get_addr = 0;
+                 bfd_boolean ret = FALSE;
 
                  r_symndx = ELF64_R_SYM (rel->r_info);
                  if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms,
@@ -7406,15 +7613,21 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          && (elf_symtab_hdr (ibfd).contents
                              != (unsigned char *) locsyms))
                        free (locsyms);
-                     return FALSE;
+                     return ret;
                    }
 
                  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;
+                     if (h->root.type == bfd_link_hash_defined
+                         || h->root.type == bfd_link_hash_defweak)
+                       value = h->root.u.def.value;
+                     else if (h->root.type == bfd_link_hash_undefweak)
+                       value = 0;
+                     else
+                       {
+                         found_tls_get_addr_arg = 0;
+                         continue;
+                       }
                    }
                  else
                    /* Symbols referenced by TLS relocs must be of type
@@ -7427,19 +7640,48 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      || !h->def_dynamic)
                    {
                      is_local = TRUE;
-                     value += sym_sec->output_offset;
-                     value += sym_sec->output_section->vma;
-                     value -= htab->elf.tls_sec->vma;
-                     ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
-                                 < (bfd_vma) 1 << 32);
+                     if (h != NULL
+                         && h->root.type == bfd_link_hash_undefweak)
+                       ok_tprel = TRUE;
+                     else
+                       {
+                         value += sym_sec->output_offset;
+                         value += sym_sec->output_section->vma;
+                         value -= htab->elf.tls_sec->vma;
+                         ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
+                                     < (bfd_vma) 1 << 32);
+                       }
                    }
 
                  r_type = ELF64_R_TYPE (rel->r_info);
+                 /* If this section has old-style __tls_get_addr calls
+                    without marker relocs, then check that each
+                    __tls_get_addr call reloc is preceded by a reloc
+                    that conceivably belongs to the __tls_get_addr arg
+                    setup insn.  If we don't find matching arg setup
+                    relocs, don't do any tls optimization.  */
+                 if (pass == 0
+                     && sec->has_tls_get_addr_call
+                     && h != NULL
+                     && (h == &htab->tls_get_addr->elf
+                         || h == &htab->tls_get_addr_fd->elf)
+                     && !found_tls_get_addr_arg
+                     && is_branch_reloc (r_type))
+                   {
+                     info->callbacks->minfo (_("%H __tls_get_addr lost arg, "
+                                               "TLS optimization disabled\n"),
+                                             ibfd, sec, rel->r_offset);
+                     ret = TRUE;
+                     goto err_free_rel;
+                   }
+
+                 found_tls_get_addr_arg = 0;
                  switch (r_type)
                    {
                    case R_PPC64_GOT_TLSLD16:
                    case R_PPC64_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
+                     found_tls_get_addr_arg = 1;
                      /* Fall thru */
 
                    case R_PPC64_GOT_TLSLD16_HI:
@@ -7459,6 +7701,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                    case R_PPC64_GOT_TLSGD16:
                    case R_PPC64_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
+                     found_tls_get_addr_arg = 1;
                      /* Fall thru */
 
                    case R_PPC64_GOT_TLSGD16_HI:
@@ -7487,11 +7730,14 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                        }
                      continue;
 
-                   case R_PPC64_TOC16:
-                   case R_PPC64_TOC16_LO:
-                   case R_PPC64_TLS:
                    case R_PPC64_TLSGD:
                    case R_PPC64_TLSLD:
+                     found_tls_get_addr_arg = 1;
+                     /* Fall thru */
+
+                   case R_PPC64_TLS:
+                   case R_PPC64_TOC16:
+                   case R_PPC64_TOC16_LO:
                      if (sym_sec == NULL || sym_sec != toc)
                        continue;
 
@@ -7500,18 +7746,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                         case of R_PPC64_TLS, and after checking for
                         tls_get_addr for the TOC16 relocs.  */
                      if (toc_ref == NULL)
-                       {
-                         toc_ref = bfd_zmalloc (toc->size / 8);
-                         if (toc_ref == NULL)
-                           goto err_free_rel;
-                       }
+                       toc_ref = bfd_zmalloc (toc->output_section->rawsize / 8);
+                     if (toc_ref == NULL)
+                       goto err_free_rel;
+
                      if (h != NULL)
                        value = h->root.u.def.value;
                      else
                        value = sym->st_value;
                      value += rel->r_addend;
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
-                     toc_ref_index = value / 8;
+                     toc_ref_index = (value + toc->output_offset) / 8;
                      if (r_type == R_PPC64_TLS
                          || r_type == R_PPC64_TLSGD
                          || r_type == R_PPC64_TLSLD)
@@ -7532,7 +7777,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      if (pass == 0
                          || sec != toc
                          || toc_ref == NULL
-                         || !toc_ref[rel->r_offset / 8])
+                         || !toc_ref[(rel->r_offset + toc->output_offset) / 8])
                        continue;
                      if (ok_tprel)
                        {
@@ -7547,7 +7792,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      if (pass == 0
                          || sec != toc
                          || toc_ref == NULL
-                         || !toc_ref[rel->r_offset / 8])
+                         || !toc_ref[(rel->r_offset + toc->output_offset) / 8])
                        continue;
                      if (rel + 1 < relend
                          && (rel[1].r_info
@@ -7591,7 +7836,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          if (expecting_tls_get_addr == 2)
                            {
                              /* Check for toc tls entries.  */
-                             char *toc_tls;
+                             unsigned char *toc_tls;
                              int retval;
 
                              retval = get_tls_mask (&toc_tls, NULL, NULL,
@@ -7599,8 +7844,13 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                                                     rel, ibfd);
                              if (retval == 0)
                                goto err_free_rel;
-                             if (retval > 1 && toc_tls != NULL)
-                               toc_ref[toc_ref_index] = 1;
+                             if (toc_tls != NULL)
+                               {
+                                 if ((*toc_tls & (TLS_GD | TLS_LD)) != 0)
+                                   found_tls_get_addr_arg = 1;
+                                 if (retval > 1)
+                                   toc_ref[toc_ref_index] = 1;
+                               }
                            }
                          continue;
                        }
@@ -7611,9 +7861,12 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
-                        the entire section.  */
-                     sec->has_tls_reloc = 0;
-                     break;
+                        the entire optimization.  */
+                     info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
+                                               "TLS optimization disabled\n"),
+                                             ibfd, sec, rel->r_offset);
+                     ret = TRUE;
+                     goto err_free_rel;
                    }
 
                  if (expecting_tls_get_addr && htab->tls_get_addr != NULL)
@@ -7699,18 +7952,18 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                free (relstart);
            }
 
-      if (toc_ref != NULL)
-       free (toc_ref);
+       if (locsyms != NULL
+           && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
+         {
+           if (!info->keep_memory)
+             free (locsyms);
+           else
+             elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
+         }
+      }
 
-      if (locsyms != NULL
-         && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
-       {
-         if (!info->keep_memory)
-           free (locsyms);
-         else
-           elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
-       }
-    }
+  if (toc_ref != NULL)
+    free (toc_ref);
   return TRUE;
 }
 
@@ -7727,17 +7980,14 @@ struct adjust_toc_info
   bfd_boolean global_toc_syms;
 };
 
+enum toc_skip_enum { ref_from_discarded = 1, can_optimize = 2 };
+
 static bfd_boolean
 adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 {
   struct ppc_link_hash_entry *eh;
   struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
-
-  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;
+  unsigned long i;
 
   if (h->root.type != bfd_link_hash_defined
       && h->root.type != bfd_link_hash_defweak)
@@ -7749,16 +7999,22 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
 
   if (eh->elf.root.u.def.section == toc_inf->toc)
     {
-      unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3];
-      if (skip != (unsigned long) -1)
-       eh->elf.root.u.def.value -= skip;
+      if (eh->elf.root.u.def.value > toc_inf->toc->rawsize)
+       i = toc_inf->toc->rawsize >> 3;
       else
+       i = eh->elf.root.u.def.value >> 3;
+
+      if ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0)
        {
          (*_bfd_error_handler)
-           (_("%s defined in removed toc entry"), eh->elf.root.root.string);
-         eh->elf.root.u.def.section = &bfd_abs_section;
-         eh->elf.root.u.def.value = 0;
+           (_("%s defined on removed toc entry"), eh->elf.root.root.string);
+         do
+           ++i;
+         while ((toc_inf->skip[i] & (ref_from_discarded | can_optimize)) != 0);
+         eh->elf.root.u.def.value = (bfd_vma) i << 3;
        }
+
+      eh->elf.root.u.def.value -= toc_inf->skip[i];
       eh->adjust_done = 1;
     }
   else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0)
@@ -7767,27 +8023,57 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
+/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc.  */
+
+static bfd_boolean
+ok_lo_toc_insn (unsigned int insn)
+{
+  return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+         || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+         || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+         || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+         || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+         || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+         || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+         || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+         || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+         || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+         || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+         || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+         || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+         || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+         || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+             && (insn & 3) != 1)
+         || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+             && ((insn & 3) == 0 || (insn & 3) == 3))
+         || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
+}
+
 /* Examine all relocs referencing .toc sections in order to remove
    unused .toc entries.  */
 
 bfd_boolean
-ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+ppc64_elf_edit_toc (struct bfd_link_info *info)
 {
   bfd *ibfd;
   struct adjust_toc_info toc_inf;
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
+  htab->do_toc_opt = 1;
   toc_inf.global_toc_syms = TRUE;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
       asection *toc, *sec;
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
-      struct elf_link_hash_entry **sym_hashes;
-      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Rela *relstart, *rel, *toc_relocs;
       unsigned long *skip, *drop;
       unsigned char *used;
       unsigned char *keep, last, some_unused;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       toc = bfd_get_section_by_name (ibfd, ".toc");
       if (toc == NULL
          || toc->size == 0
@@ -7795,9 +8081,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
          || elf_discarded_section (toc))
        continue;
 
+      toc_relocs = NULL;
       local_syms = NULL;
       symtab_hdr = &elf_symtab_hdr (ibfd);
-      sym_hashes = elf_sym_hashes (ibfd);
 
       /* Look at sections dropped from the final link.  */
       skip = NULL;
@@ -7865,18 +8151,101 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 
              if (skip == NULL)
                {
-                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
                  if (skip == NULL)
                    goto error_ret;
                }
 
-             skip[val >> 3] = 1;
+             skip[val >> 3] = ref_from_discarded;
            }
 
          if (elf_section_data (sec)->relocs != relstart)
            free (relstart);
        }
 
+      /* For largetoc loads of address constants, we can convert
+        .  addis rx,2,addr@got@ha
+        .  ld ry,addr@got@l(rx)
+        to
+        .  addis rx,2,addr@toc@ha
+        .  addi ry,rx,addr@toc@l
+        when addr is within 2G of the toc pointer.  This then means
+        that the word storing "addr" in the toc is no longer needed.  */
+        
+      if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
+         && toc->output_section->rawsize < (bfd_vma) 1 << 31
+         && toc->reloc_count != 0)
+       {
+         /* Read toc relocs.  */
+         toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                 info->keep_memory);
+         if (toc_relocs == NULL)
+           goto error_ret;
+
+         for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
+           {
+             enum elf_ppc64_reloc_type r_type;
+             unsigned long r_symndx;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             Elf_Internal_Sym *sym;
+             bfd_vma val, addr;
+
+             r_type = ELF64_R_TYPE (rel->r_info);
+             if (r_type != R_PPC64_ADDR64)
+               continue;
+
+             r_symndx = ELF64_R_SYM (rel->r_info);
+             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                             r_symndx, ibfd))
+               goto error_ret;
+
+             if (sym_sec == NULL
+                 || elf_discarded_section (sym_sec))
+               continue;
+
+             if (!SYMBOL_CALLS_LOCAL (info, h))
+               continue;
+
+             if (h != NULL)
+               {
+                 if (h->type == STT_GNU_IFUNC)
+                   continue;
+                 val = h->root.u.def.value;
+               }
+             else
+               {
+                 if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   continue;
+                 val = sym->st_value;
+               }
+             val += rel->r_addend;
+             val += sym_sec->output_section->vma + sym_sec->output_offset;
+
+             /* We don't yet know the exact toc pointer value, but we
+                know it will be somewhere in the toc section.  Don't
+                optimize if the difference from any possible toc
+                pointer is outside [ff..f80008000, 7fff7fff].  */
+             addr = toc->output_section->vma + TOC_BASE_OFF;
+             if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32)
+               continue;
+
+             addr = toc->output_section->vma + toc->output_section->rawsize;
+             if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32)
+               continue;
+
+             if (skip == NULL)
+               {
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
+                 if (skip == NULL)
+                   goto error_ret;
+               }
+
+             skip[rel->r_offset >> 3]
+               |= can_optimize | ((rel - toc_relocs) << 2);
+           }
+       }
+
       if (skip == NULL)
        continue;
 
@@ -7891,6 +8260,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              && relstart != NULL
              && elf_section_data (sec)->relocs != relstart)
            free (relstart);
+         if (toc_relocs != NULL
+             && elf_section_data (toc)->relocs != toc_relocs)
+           free (toc_relocs);
          if (skip != NULL)
            free (skip);
          return FALSE;
@@ -7915,7 +8287,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              || (sec->flags & SEC_DEBUGGING) != 0)
            continue;
 
-         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                               info->keep_memory);
          if (relstart == NULL)
            goto error_ret;
 
@@ -7930,10 +8303,66 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                struct elf_link_hash_entry *h;
                Elf_Internal_Sym *sym;
                bfd_vma val;
+               enum {no_check, check_lo, check_ha} insn_check;
 
                r_type = ELF64_R_TYPE (rel->r_info);
                switch (r_type)
                  {
+                 default:
+                   insn_check = no_check;
+                   break;
+
+                 case R_PPC64_GOT_TLSLD16_HA:
+                 case R_PPC64_GOT_TLSGD16_HA:
+                 case R_PPC64_GOT_TPREL16_HA:
+                 case R_PPC64_GOT_DTPREL16_HA:
+                 case R_PPC64_GOT16_HA:
+                 case R_PPC64_TOC16_HA:
+                   insn_check = check_ha;
+                   break;
+
+                 case R_PPC64_GOT_TLSLD16_LO:
+                 case R_PPC64_GOT_TLSGD16_LO:
+                 case R_PPC64_GOT_TPREL16_LO_DS:
+                 case R_PPC64_GOT_DTPREL16_LO_DS:
+                 case R_PPC64_GOT16_LO:
+                 case R_PPC64_GOT16_LO_DS:
+                 case R_PPC64_TOC16_LO:
+                 case R_PPC64_TOC16_LO_DS:
+                   insn_check = check_lo;
+                   break;
+                 }
+
+               if (insn_check != no_check)
+                 {
+                   bfd_vma off = rel->r_offset & ~3;
+                   unsigned char buf[4];
+                   unsigned int insn;
+
+                   if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+                     {
+                       free (used);
+                       goto error_ret;
+                     }
+                   insn = bfd_get_32 (ibfd, buf);
+                   if (insn_check == check_lo
+                       ? !ok_lo_toc_insn (insn)
+                       : ((insn & ((0x3f << 26) | 0x1f << 16))
+                          != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+                     {
+                       char str[12];
+
+                       ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+                       sprintf (str, "%#08x", insn);
+                       info->callbacks->einfo
+                         (_("%P: %H: toc optimization is not supported for"
+                            " %s instruction.\n"),
+                          ibfd, sec, rel->r_offset & ~3, str);
+                     }
+                 }
+
+               switch (r_type)
+                 {
                  case R_PPC64_TOC16:
                  case R_PPC64_TOC16_LO:
                  case R_PPC64_TOC16_HI:
@@ -7968,12 +8397,40 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                if (val >= toc->size)
                  continue;
 
+               if ((skip[val >> 3] & can_optimize) != 0)
+                 {
+                   bfd_vma off;
+                   unsigned char opc;
+
+                   switch (r_type)
+                     {
+                     case R_PPC64_TOC16_HA:
+                       break;
+
+                     case R_PPC64_TOC16_LO_DS:
+                       off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
+                       if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
+                         {
+                           free (used);
+                           goto error_ret;
+                         }
+                       if ((opc & (0x3f << 2)) == (58u << 2))
+                         break;
+                       /* Fall thru */
+
+                     default:
+                       /* Wrong sort of reloc, or not a ld.  We may
+                          as well clear ref_from_discarded too.  */
+                       skip[val >> 3] = 0;
+                     }
+                 }
+
                /* For the toc section, we only mark as used if
                   this entry itself isn't unused.  */
                if (sec == toc
                    && !used[val >> 3]
                    && (used[rel->r_offset >> 3]
-                       || !skip[rel->r_offset >> 3]))
+                       || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
                  /* Do all the relocs again, to catch reference
                     chains.  */
                  repeat = 1;
@@ -7981,6 +8438,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                used[val >> 3] = 1;
              }
          while (repeat);
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
        }
 
       /* Merge the used and skip arrays.  Assume that TOC
@@ -7992,13 +8452,15 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
        {
          if (*keep)
            {
-             *drop = 0;
+             *drop &= ~ref_from_discarded;
+             if ((*drop & can_optimize) != 0)
+               some_unused = 1;
              last = 0;
            }
-         else if (*drop)
+         else if ((*drop & ref_from_discarded) != 0)
            {
              some_unused = 1;
-             last = 1;
+             last = ref_from_discarded;
            }
          else
            *drop = last;
@@ -8010,6 +8472,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
        {
          bfd_byte *contents, *src;
          unsigned long off;
+         Elf_Internal_Sym *sym;
+         bfd_boolean local_toc_syms = FALSE;
 
          /* Shuffle the toc contents, and at the same time convert the
             skip array from booleans into offsets.  */
@@ -8022,52 +8486,20 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
               src < contents + toc->size;
               src += 8, ++drop)
            {
-             if (*drop)
-               {
-                 *drop = (unsigned long) -1;
-                 off += 8;
-               }
+             if ((*drop & (can_optimize | ref_from_discarded)) != 0)
+               off += 8;
              else if (off != 0)
                {
                  *drop = off;
                  memcpy (src - off, src, 8);
                }
            }
+         *drop = off;
          toc->rawsize = toc->size;
          toc->size = src - contents - off;
 
-         if (toc->reloc_count != 0)
-           {
-             Elf_Internal_Rela *wrel;
-             bfd_size_type sz;
-
-             /* Read toc relocs.  */
-             relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-                                                   TRUE);
-             if (relstart == NULL)
-               goto error_ret;
-
-             /* Remove unused toc relocs, and adjust those we keep.  */
-             wrel = relstart;
-             for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
-               if (skip[rel->r_offset >> 3] != (unsigned long) -1)
-                 {
-                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
-                   wrel->r_info = rel->r_info;
-                   wrel->r_addend = rel->r_addend;
-                   ++wrel;
-                 }
-               else if (!dec_dynrel_count (rel->r_info, toc, info,
-                                           &local_syms, NULL, NULL))
-                 goto error_ret;
-
-             toc->reloc_count = wrel - relstart;
-             sz = elf_section_data (toc)->rel_hdr.sh_entsize;
-             elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
-             BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
-           }
-
-         /* Adjust addends for relocs against the toc section sym.  */
+         /* Adjust addends for relocs against the toc section sym,
+            and optimize any accesses we can.  */
          for (sec = ibfd->sections; sec != NULL; sec = sec->next)
            {
              if (sec->reloc_count == 0
@@ -8075,7 +8507,7 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                continue;
 
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
-                                                   TRUE);
+                                                   info->keep_memory);
              if (relstart == NULL)
                goto error_ret;
 
@@ -8085,7 +8517,7 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                  unsigned long r_symndx;
                  asection *sym_sec;
                  struct elf_link_hash_entry *h;
-                 Elf_Internal_Sym *sym;
+                 bfd_vma val;
 
                  r_type = ELF64_R_TYPE (rel->r_info);
                  switch (r_type)
@@ -8108,41 +8540,100 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                                  r_symndx, ibfd))
                    goto error_ret;
 
-                 if (sym_sec != toc || h != NULL || sym->st_value != 0)
+                 if (sym_sec != toc)
+                   continue;
+
+                 if (h != NULL)
+                   val = h->root.u.def.value;
+                 else
+                   {
+                     val = sym->st_value;
+                     if (val != 0)
+                       local_toc_syms = TRUE;
+                   }
+
+                 val += rel->r_addend;
+
+                 if (val > toc->rawsize)
+                   val = toc->rawsize;
+                 else if ((skip[val >> 3] & ref_from_discarded) != 0)
+                   continue;
+                 else if ((skip[val >> 3] & can_optimize) != 0)
+                   {
+                     Elf_Internal_Rela *tocrel
+                       = toc_relocs + (skip[val >> 3] >> 2);
+                     unsigned long tsym = ELF64_R_SYM (tocrel->r_info);
+
+                     switch (r_type)
+                       {
+                       case R_PPC64_TOC16_HA:
+                         rel->r_info = ELF64_R_INFO (tsym, R_PPC64_TOC16_HA);
+                         break;
+
+                       case R_PPC64_TOC16_LO_DS:
+                         rel->r_info = ELF64_R_INFO (tsym, R_PPC64_LO_DS_OPT);
+                         break;
+
+                       default:
+                         if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
+                           ppc_howto_init ();
+                         info->callbacks->einfo
+                           (_("%P: %H: %s relocation references "
+                              "optimized away TOC entry\n"),
+                            ibfd, sec, rel->r_offset,
+                            ppc64_elf_howto_table[r_type]->name);
+                         bfd_set_error (bfd_error_bad_value);
+                         goto error_ret;
+                       }
+                     rel->r_addend = tocrel->r_addend;
+                     elf_section_data (sec)->relocs = relstart;
+                     continue;
+                   }
+
+                 if (h != NULL || sym->st_value != 0)
                    continue;
 
-                 rel->r_addend -= skip[rel->r_addend >> 3];
+                 rel->r_addend -= skip[val >> 3];
+                 elf_section_data (sec)->relocs = relstart;
                }
+
+             if (elf_section_data (sec)->relocs != relstart)
+               free (relstart);
            }
 
          /* We shouldn't have local or global symbols defined in the TOC,
             but handle them anyway.  */
          if (local_syms != NULL)
-           {
-             Elf_Internal_Sym *sym;
+           for (sym = local_syms;
+                sym < local_syms + symtab_hdr->sh_info;
+                ++sym)
+             if (sym->st_value != 0
+                 && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+               {
+                 unsigned long i;
 
-             for (sym = local_syms;
-                  sym < local_syms + symtab_hdr->sh_info;
-                  ++sym)
-               if (sym->st_value != 0
-                   && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
-                 {
-                   if (skip[sym->st_value >> 3] != (unsigned long) -1)
-                     sym->st_value -= skip[sym->st_value >> 3];
-                   else
-                     {
+                 if (sym->st_value > toc->rawsize)
+                   i = toc->rawsize >> 3;
+                 else
+                   i = sym->st_value >> 3;
+
+                 if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
+                   {
+                     if (local_toc_syms)
                        (*_bfd_error_handler)
-                         (_("%s defined in removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym,
-                                            NULL));
-                       sym->st_value = 0;
-                       sym->st_shndx = SHN_ABS;
-                     }
-                   symtab_hdr->contents = (unsigned char *) local_syms;
-                 }
-           }
+                         (_("%s defined on removed toc entry"),
+                          bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+                     do
+                       ++i;
+                     while ((skip[i] & (ref_from_discarded | can_optimize)));
+                     sym->st_value = (bfd_vma) i << 3;
+                   }
+
+                 sym->st_value -= skip[i];
+                 symtab_hdr->contents = (unsigned char *) local_syms;
+               }
 
-         /* Finally, adjust any global syms defined in the toc.  */
+         /* Adjust any global syms defined in this toc input section.  */
          if (toc_inf.global_toc_syms)
            {
              toc_inf.toc = toc;
@@ -8151,22 +8642,125 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
                                      &toc_inf);
            }
-       }
-
-      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;
-       }
-      free (skip);
-    }
+
+         if (toc->reloc_count != 0)
+           {
+             Elf_Internal_Shdr *rel_hdr;
+             Elf_Internal_Rela *wrel;
+             bfd_size_type sz;
+
+             /* Remove unused toc relocs, and adjust those we keep.  */
+             if (toc_relocs == NULL)
+               toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                       info->keep_memory);
+             if (toc_relocs == NULL)
+               goto error_ret;
+
+             wrel = toc_relocs;
+             for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
+               if ((skip[rel->r_offset >> 3]
+                    & (ref_from_discarded | can_optimize)) == 0)
+                 {
+                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
+                   wrel->r_info = rel->r_info;
+                   wrel->r_addend = rel->r_addend;
+                   ++wrel;
+                 }
+               else if (!dec_dynrel_count (rel->r_info, toc, info,
+                                           &local_syms, NULL, NULL))
+                 goto error_ret;
+
+             elf_section_data (toc)->relocs = toc_relocs;
+             toc->reloc_count = wrel - toc_relocs;
+             rel_hdr = _bfd_elf_single_rel_hdr (toc);
+             sz = rel_hdr->sh_entsize;
+             rel_hdr->sh_size = toc->reloc_count * sz;
+           }
+       }
+      else if (toc_relocs != NULL
+              && elf_section_data (toc)->relocs != toc_relocs)
+       free (toc_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;
+       }
+      free (skip);
+    }
 
   return TRUE;
 }
 
+/* Return true iff input section I references the TOC using
+   instructions limited to +/-32k offsets.  */
+
+bfd_boolean
+ppc64_elf_has_small_toc_reloc (asection *i)
+{
+  return (is_ppc64_elf (i->owner)
+         && ppc64_elf_tdata (i->owner)->has_small_toc_reloc);
+}
+
+/* Allocate space for one GOT entry.  */
+
+static void
+allocate_got (struct elf_link_hash_entry *h,
+             struct bfd_link_info *info,
+             struct got_entry *gent)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd_boolean dyn;
+  struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+  int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
+                ? 16 : 8);
+  int rentsize = (gent->tls_type & eh->tls_mask & TLS_GD
+                 ? 2 : 1) * sizeof (Elf64_External_Rela);
+  asection *got = ppc64_elf_tdata (gent->owner)->got;
+
+  gent->got.offset = got->size;
+  got->size += entsize;
+
+  dyn = htab->elf.dynamic_sections_created;
+  if ((info->shared
+       || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+               || h->root.type != bfd_link_hash_undefweak))
+    {
+      asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
+      relgot->size += rentsize;
+    }
+  else if (h->type == STT_GNU_IFUNC)
+    {
+      asection *relgot = htab->reliplt;
+      relgot->size += rentsize;
+      htab->got_reli_size += rentsize;
+    }
+}
+
+/* This function merges got entries in the same toc group.  */
+
+static void
+merge_got_entries (struct got_entry **pent)
+{
+  struct got_entry *ent, *ent2;
+
+  for (ent = *pent; ent != NULL; ent = ent->next)
+    if (!ent->is_indirect)
+      for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
+       if (!ent2->is_indirect
+           && ent2->addend == ent->addend
+           && ent2->tls_type == ent->tls_type
+           && elf_gp (ent2->owner) == elf_gp (ent->owner))
+         {
+           ent2->is_indirect = TRUE;
+           ent2->got.ent = ent;
+         }
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
@@ -8177,17 +8771,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct ppc_link_hash_table *htab;
   asection *s;
   struct ppc_link_hash_entry *eh;
-  struct ppc_dyn_relocs *p;
-  struct got_entry *gent;
+  struct elf_dyn_relocs *p;
+  struct got_entry **pgent, *gent;
 
   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 (htab == NULL)
+    return FALSE;
 
   if ((htab->elf.dynamic_sections_created
        && h->dynindx != -1
@@ -8275,12 +8868,31 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            gent->tls_type = TLS_TLS | TLS_TPREL;
        }
 
-  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+  /* Remove any list entry that won't generate a word in the GOT before
+     we call merge_got_entries.  Otherwise we risk merging to empty
+     entries.  */
+  pgent = &h->got.glist;
+  while ((gent = *pgent) != NULL)
     if (gent->got.refcount > 0)
       {
-       bfd_boolean dyn;
-       asection *rsec;
+       if ((gent->tls_type & TLS_LD) != 0
+           && !h->def_dynamic)
+         {
+           ppc64_tlsld_got (gent->owner)->got.refcount += 1;
+           *pgent = gent->next;
+         }
+       else
+         pgent = &gent->next;
+      }
+    else
+      *pgent = gent->next;
+
+  if (!htab->do_multi_toc)
+    merge_got_entries (&h->got.glist);
 
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (!gent->is_indirect)
+      {
        /* Make sure this symbol is output as a dynamic symbol.
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
@@ -8293,37 +8905,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              return FALSE;
          }
 
-       if ((gent->tls_type & TLS_LD) != 0
-           && !h->def_dynamic)
-         {
-           ppc64_tlsld_got (gent->owner)->refcount += 1;
-           gent->got.offset = (bfd_vma) -1;
-           continue;
-         }
-
        if (!is_ppc64_elf (gent->owner))
-         continue;
+         abort ();
 
-       s = ppc64_elf_tdata (gent->owner)->got;
-       gent->got.offset = s->size;
-       s->size
-         += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
-       dyn = htab->elf.dynamic_sections_created;
-       rsec = NULL;
-       if ((info->shared
-            || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
-           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-               || h->root.type != bfd_link_hash_undefweak))
-         rsec = ppc64_elf_tdata (gent->owner)->relgot;
-       else if (h->type == STT_GNU_IFUNC)
-         rsec = htab->reliplt;
-       if (rsec != NULL)
-         rsec->size += (gent->tls_type & eh->tls_mask & TLS_GD
-                        ? 2 * sizeof (Elf64_External_Rela)
-                        : sizeof (Elf64_External_Rela));
+       allocate_got (h, info, gent);
       }
-    else
-      gent->got.offset = (bfd_vma) -1;
 
   if (eh->dyn_relocs == NULL
       || (!htab->elf.dynamic_sections_created
@@ -8346,7 +8932,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
         then they should avoid writing weird assembly.  */
       if (SYMBOL_CALLS_LOCAL (info, h))
        {
-         struct ppc_dyn_relocs **pp;
+         struct elf_dyn_relocs **pp;
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
            {
@@ -8429,10 +9015,7 @@ static bfd_boolean
 readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
 {
   struct ppc_link_hash_entry *eh;
-  struct ppc_dyn_relocs *p;
-
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
+  struct elf_dyn_relocs *p;
 
   eh = (struct ppc_link_hash_entry *) h;
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
@@ -8463,8 +9046,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   asection *s;
   bfd_boolean relocs;
   bfd *ibfd;
+  struct got_entry *first_tlsld;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     abort ();
@@ -8490,7 +9077,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       struct got_entry **end_lgot_ents;
       struct plt_entry **local_plt;
       struct plt_entry **end_local_plt;
-      char *lgot_masks;
+      unsigned char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -8500,7 +9087,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct ppc_dyn_relocs *p;
+         struct elf_dyn_relocs *p;
 
          for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
@@ -8533,20 +9120,21 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       end_lgot_ents = lgot_ents + locsymcount;
       local_plt = (struct plt_entry **) end_lgot_ents;
       end_local_plt = local_plt + locsymcount;
-      lgot_masks = (char *) end_local_plt;
+      lgot_masks = (unsigned char *) end_local_plt;
       s = ppc64_elf_tdata (ibfd)->got;
       srel = ppc64_elf_tdata (ibfd)->relgot;
       for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
        {
-         struct got_entry *ent;
+         struct got_entry **pent, *ent;
 
-         for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+         pent = lgot_ents;
+         while ((ent = *pent) != NULL)
            if (ent->got.refcount > 0)
              {
                if ((ent->tls_type & *lgot_masks & TLS_LD) != 0)
                  {
-                   ppc64_tlsld_got (ibfd)->refcount += 1;
-                   ent->got.offset = (bfd_vma) -1;
+                   ppc64_tlsld_got (ibfd)->got.refcount += 1;
+                   *pent = ent->next;
                  }
                else
                  {
@@ -8558,11 +9146,17 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                    if (info->shared)
                      srel->size += num * sizeof (Elf64_External_Rela);
                    else if ((*lgot_masks & PLT_IFUNC) != 0)
-                     htab->reliplt->size += num * sizeof (Elf64_External_Rela);
+                     {
+                       htab->reliplt->size
+                         += num * sizeof (Elf64_External_Rela);
+                       htab->got_reli_size
+                         += num * sizeof (Elf64_External_Rela);
+                     }
+                   pent = &ent->next;
                  }
              }
            else
-             ent->got.offset = (bfd_vma) -1;
+             *pent = ent->next;
        }
 
       /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
@@ -8588,24 +9182,39 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
 
+  first_tlsld = NULL;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
+      struct got_entry *ent;
+
       if (!is_ppc64_elf (ibfd))
        continue;
 
-      if (ppc64_tlsld_got (ibfd)->refcount > 0)
+      ent = ppc64_tlsld_got (ibfd);
+      if (ent->got.refcount > 0)
        {
-         s = ppc64_elf_tdata (ibfd)->got;
-         ppc64_tlsld_got (ibfd)->offset = s->size;
-         s->size += 16;
-         if (info->shared)
+         if (!htab->do_multi_toc && first_tlsld != NULL)
            {
-             asection *srel = ppc64_elf_tdata (ibfd)->relgot;
-             srel->size += sizeof (Elf64_External_Rela);
+             ent->is_indirect = TRUE;
+             ent->got.ent = first_tlsld;
+           }
+         else
+           {
+             if (first_tlsld == NULL)
+               first_tlsld = ent;
+             s = ppc64_elf_tdata (ibfd)->got;
+             ent->got.offset = s->size;
+             ent->owner = ibfd;
+             s->size += 16;
+             if (info->shared)
+               {
+                 asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+                 srel->size += sizeof (Elf64_External_Rela);
+               }
            }
        }
       else
-       ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
+       ent->got.offset = (bfd_vma) -1;
     }
 
   /* We now have determined the sizes of the various dynamic sections.
@@ -8628,7 +9237,13 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
+      else if (s == htab->glink_eh_frame)
+       {
+         if (!bfd_is_abs_section (s->output_section))
+           /* Not sized yet.  */
+           continue;
+       }
+      else if (CONST_STRNEQ (s->name, ".rela"))
        {
          if (s->size != 0)
            {
@@ -8793,13 +9408,15 @@ ppc_type_of_stub (asection *input_sec,
       struct ppc_link_hash_entry *fdh = h;
       if (h->oh != NULL
          && h->oh->is_func_descriptor)
-       fdh = ppc_follow_link (h->oh);
+       {
+         fdh = ppc_follow_link (h->oh);
+         *hash = fdh;
+       }
 
       for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
        if (ent->addend == rel->r_addend
            && ent->plt.offset != (bfd_vma) -1)
          {
-           *hash = fdh;
            *plt_ent = ent;
            return ppc_stub_plt_call;
          }
@@ -8808,12 +9425,8 @@ ppc_type_of_stub (asection *input_sec,
         either a defined function descriptor or a defined entry symbol
         in a regular object file, then it is pointless trying to make
         any other type of stub.  */
-      if (!((fdh->elf.root.type == bfd_link_hash_defined
-           || fdh->elf.root.type == bfd_link_hash_defweak)
-           && fdh->elf.root.u.def.section->output_section != NULL)
-         && !((h->elf.root.type == bfd_link_hash_defined
-               || h->elf.root.type == bfd_link_hash_defweak)
-              && h->elf.root.u.def.section->output_section != NULL))
+      if (!is_static_defined (&fdh->elf)
+         && !is_static_defined (&h->elf))
        return ppc_stub_none;
     }
   else if (elf_local_got_ents (input_sec->owner) != NULL)
@@ -8861,7 +9474,8 @@ ppc_type_of_stub (asection *input_sec,
 /* Build a .plt call stub.  */
 
 static inline bfd_byte *
-build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
+build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r,
+               bfd_boolean plt_static_chain)
 {
 #define PPC_LO(v) ((v) & 0xffff)
 #define PPC_HI(v) (((v) >> 16) & 0xffff)
@@ -8871,11 +9485,12 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
     {
       if (r != NULL)
        {
+         r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
-         r[1].r_offset = r[0].r_offset + 8;
+         r[1].r_offset = r[0].r_offset + 4;
          r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
          r[1].r_addend = r[0].r_addend;
-         if (PPC_HA (offset + 16) != PPC_HA (offset))
+         if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
            {
              r[2].r_offset = r[1].r_offset + 4;
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
@@ -8886,22 +9501,26 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
              r[2].r_offset = r[1].r_offset + 8;
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
              r[2].r_addend = r[0].r_addend + 8;
-             r[3].r_offset = r[2].r_offset + 4;
-             r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
-             r[3].r_addend = r[0].r_addend + 16;
+             if (plt_static_chain)
+               {
+                 r[3].r_offset = r[2].r_offset + 4;
+                 r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
+                 r[3].r_addend = r[0].r_addend + 16;
+               }
            }
        }
-      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),    p += 4;
       bfd_put_32 (obfd, STD_R2_40R1, p),                       p += 4;
+      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),    p += 4;
       bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p),     p += 4;
-      if (PPC_HA (offset + 16) != PPC_HA (offset))
+      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
        {
          bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4;
          offset = 0;
        }
       bfd_put_32 (obfd, MTCTR_R11, p),                         p += 4;
       bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p),  p += 4;
-      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p),        p += 4;
+      if (plt_static_chain)
+       bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4;
       bfd_put_32 (obfd, BCTR, p),                              p += 4;
     }
   else
@@ -8910,7 +9529,7 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
        {
          r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-         if (PPC_HA (offset + 16) != PPC_HA (offset))
+         if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
            {
              r[1].r_offset = r[0].r_offset + 4;
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
@@ -8920,21 +9539,25 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
            {
              r[1].r_offset = r[0].r_offset + 8;
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-             r[1].r_addend = r[0].r_addend + 16;
-             r[2].r_offset = r[1].r_offset + 4;
-             r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-             r[2].r_addend = r[0].r_addend + 8;
+             r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
+             if (plt_static_chain)
+               {
+                 r[2].r_offset = r[1].r_offset + 4;
+                 r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
+                 r[2].r_addend = r[0].r_addend + 8;
+               }
            }
        }
       bfd_put_32 (obfd, STD_R2_40R1, p),                       p += 4;
       bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p),      p += 4;
-      if (PPC_HA (offset + 16) != PPC_HA (offset))
+      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
        {
          bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),   p += 4;
          offset = 0;
        }
       bfd_put_32 (obfd, MTCTR_R11, p),                         p += 4;
-      bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
+      if (plt_static_chain)
+       bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
       bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),   p += 4;
       bfd_put_32 (obfd, BCTR, p),                              p += 4;
     }
@@ -8959,7 +9582,7 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
 
 static inline bfd_byte *
 build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
-                        Elf_Internal_Rela *r)
+                        Elf_Internal_Rela *r, bfd_boolean plt_static_chain)
 {
   bfd_put_32 (obfd, LD_R11_0R3 + 0, p),                p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
@@ -8973,7 +9596,7 @@ build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
 
   if (r != NULL)
     r[0].r_offset += 9 * 4;
-  p = build_plt_stub (obfd, p, offset, r);
+  p = build_plt_stub (obfd, p, offset, r, plt_static_chain);
   bfd_put_32 (obfd, BCTRL, p - 4);
 
   bfd_put_32 (obfd, LD_R11_0R1 + 32, p),       p += 4;
@@ -9000,9 +9623,13 @@ get_relocs (asection *sec, int count)
       if (relocs == NULL)
        return NULL;
       elfsec_data->relocs = relocs;
-      elfsec_data->rel_hdr.sh_size = (sec->reloc_count
-                                     * sizeof (Elf64_External_Rela));
-      elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela);
+      elfsec_data->rela.hdr = bfd_zalloc (sec->owner,
+                                         sizeof (Elf_Internal_Shdr));
+      if (elfsec_data->rela.hdr == NULL)
+       return NULL;
+      elfsec_data->rela.hdr->sh_size = (sec->reloc_count
+                                       * sizeof (Elf64_External_Rela));
+      elfsec_data->rela.hdr->sh_entsize = sizeof (Elf64_External_Rela);
       sec->reloc_count = 0;
     }
   relocs += sec->reloc_count;
@@ -9010,6 +9637,38 @@ get_relocs (asection *sec, int count)
   return relocs;
 }
 
+static bfd_vma
+get_r2off (struct bfd_link_info *info,
+          struct ppc_stub_hash_entry *stub_entry)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd_vma r2off = htab->stub_group[stub_entry->target_section->id].toc_off;
+
+  if (r2off == 0)
+    {
+      /* Support linking -R objects.  Get the toc pointer from the
+        opd entry.  */
+      char buf[8];
+      asection *opd = stub_entry->h->elf.root.u.def.section;
+      bfd_vma opd_off = stub_entry->h->elf.root.u.def.value;
+
+      if (strcmp (opd->name, ".opd") != 0
+         || opd->reloc_count != 0)
+       {
+         info->callbacks->einfo (_("%P: cannot find opd entry toc for %s\n"),
+                                 stub_entry->h->elf.root.root.string);
+         bfd_set_error (bfd_error_bad_value);
+         return 0;
+       }
+      if (!bfd_get_section_contents (opd->owner, opd, buf, opd_off + 8, 8))
+       return 0;
+      r2off = bfd_get_64 (opd->owner, buf);
+      r2off -= elf_gp (info->output_bfd);
+    }
+  r2off -= htab->stub_group[stub_entry->id_sec->id].toc_off;
+  return r2off;
+}
+
 static bfd_boolean
 ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 {
@@ -9029,6 +9688,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   info = in_arg;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Make a note of the offset within the stubs for this entry.  */
   stub_entry->stub_offset = stub_entry->stub_sec->size;
@@ -9052,10 +9713,13 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       size = 4;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
-         bfd_vma r2off;
+         bfd_vma r2off = get_r2off (info, stub_entry);
 
-         r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
-                  - htab->stub_group[stub_entry->id_sec->id].toc_off);
+         if (r2off == 0)
+           {
+             htab->stub_error = TRUE;
+             return FALSE;
+           }
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
          size = 12;
@@ -9073,8 +9737,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
-         (*_bfd_error_handler) (_("long branch stub `%s' offset overflow"),
-                                stub_entry->root.string);
+         info->callbacks->einfo (_("%P: long branch stub `%s' offset overflow\n"),
+                                 stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -9132,8 +9796,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                                         FALSE, FALSE);
       if (br_entry == NULL)
        {
-         (*_bfd_error_handler) (_("can't find branch stub `%s'"),
-                                stub_entry->root.string);
+         info->callbacks->einfo (_("%P: can't find branch stub `%s'\n"),
+                                 stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -9193,8 +9857,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
-         (*_bfd_error_handler)
-           (_("linkage table error against `%s'"),
+         info->callbacks->einfo
+           (_("%P: linkage table error against `%s'\n"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
@@ -9239,10 +9903,14 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
       else
        {
-         bfd_vma r2off;
+         bfd_vma r2off = get_r2off (info, stub_entry);
+
+         if (r2off == 0)
+           {
+             htab->stub_error = TRUE;
+             return FALSE;
+           }
 
-         r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
-                  - htab->stub_group[stub_entry->id_sec->id].toc_off);
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
          size = 20;
@@ -9289,6 +9957,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
             these checks could now disappear.  */
          if (fh->elf.root.type == bfd_link_hash_undefined)
            fh->elf.root.type = bfd_link_hash_undefweak;
+         /* Stop undo_symbol_twiddle changing it back to undefined.  */
+         fh->was_undefined = 0;
        }
 
       /* Now build the stub.  */
@@ -9329,8 +9999,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
-         (*_bfd_error_handler)
-           (_("linkage table error against `%s'"),
+         info->callbacks->einfo
+           (_("%P: linkage table error against `%s'\n"),
             stub_entry->h != NULL
             ? stub_entry->h->elf.root.root.string
             : "<local sym>");
@@ -9343,8 +10013,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
        {
          r = get_relocs (stub_entry->stub_sec,
-                         (2 + (PPC_HA (off) != 0)
-                          + (PPC_HA (off + 16) == PPC_HA (off))));
+                         (2
+                          + (PPC_HA (off) != 0)
+                          + (htab->plt_static_chain
+                             && PPC_HA (off + 16) == PPC_HA (off))));
          if (r == NULL)
            return FALSE;
          r[0].r_offset = loc - stub_entry->stub_sec->contents;
@@ -9356,9 +10028,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          && (stub_entry->h == htab->tls_get_addr_fd
              || stub_entry->h == htab->tls_get_addr)
          && !htab->no_tls_get_addr_opt)
-       p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r);
+       p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r,
+                                    htab->plt_static_chain);
       else
-       p = build_plt_stub (htab->stub_bfd, loc, off, r);
+       p = build_plt_stub (htab->stub_bfd, loc, off, r,
+                           htab->plt_static_chain);
       size = p - loc;
       break;
 
@@ -9425,6 +10099,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   info = in_arg;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (stub_entry->stub_type == ppc_stub_plt_call)
     {
@@ -9443,9 +10119,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       size = PLT_CALL_STUB_SIZE;
+      if (!htab->plt_static_chain)
+       size -= 4;
       if (PPC_HA (off) == 0)
        size -= 4;
-      if (PPC_HA (off + 16) != PPC_HA (off))
+      if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
        size += 4;
       if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
@@ -9455,7 +10133,10 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (info->emitrelocations)
        {
          stub_entry->stub_sec->reloc_count
-           += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off));
+           += (2
+               + (PPC_HA (off) != 0)
+               + (htab->plt_static_chain
+                  && PPC_HA (off + 16) == PPC_HA (off)));
          stub_entry->stub_sec->flags |= SEC_RELOC;
        }
     }
@@ -9480,8 +10161,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       size = 4;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
        {
-         r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
-                  - htab->stub_group[stub_entry->id_sec->id].toc_off);
+         r2off = get_r2off (info, stub_entry);
+         if (r2off == 0)
+           {
+             htab->stub_error = TRUE;
+             return FALSE;
+           }
          size = 12;
          if (PPC_HA (r2off) != 0)
            size = 16;
@@ -9498,8 +10183,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                                             TRUE, FALSE);
          if (br_entry == NULL)
            {
-             (*_bfd_error_handler) (_("can't build branch stub `%s'"),
-                                    stub_entry->root.string);
+             info->callbacks->einfo (_("%P: can't build branch stub `%s'\n"),
+                                     stub_entry->root.string);
              htab->stub_error = TRUE;
              return FALSE;
            }
@@ -9564,9 +10249,10 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
    0 when no stubs will be needed, and 1 on success.  */
 
 int
-ppc64_elf_setup_section_lists (bfd *output_bfd,
-                              struct bfd_link_info *info,
-                              int no_multi_toc)
+ppc64_elf_setup_section_lists
+  (struct bfd_link_info *info,
+   asection *(*add_stub_section) (const char *, asection *),
+   void (*layout_sections_again) (void))
 {
   bfd *input_bfd;
   int top_id, top_index, id;
@@ -9575,7 +10261,11 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  htab->no_multi_toc = no_multi_toc;
+  if (htab == NULL)
+    return -1;
+  /* Stash our params away.  */
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
 
   if (htab->brlt == NULL)
     return 0;
@@ -9604,12 +10294,10 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   for (id = 0; id < 3; id++)
     htab->stub_group[id].toc_off = TOC_BASE_OFF;
 
-  elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd);
-
   /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
      strip_excluded_output_sections doesn't renumber the indices.  */
-  for (section = output_bfd->sections, top_index = 0;
+  for (section = info->output_bfd->sections, top_index = 0;
        section != NULL;
        section = section->next)
     {
@@ -9627,41 +10315,308 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   return 1;
 }
 
+/* Set up for first pass at multitoc partitioning.  */
+
+void
+ppc64_elf_start_multitoc_partition (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  elf_gp (info->output_bfd) = ppc64_elf_toc (info->output_bfd);
+  htab->toc_curr = elf_gp (info->output_bfd);
+  htab->toc_bfd = NULL;
+  htab->toc_first_sec = NULL;
+}
+
 /* The linker repeatedly calls this function for each TOC input section
    and linker generated GOT section.  Group input bfds such that the toc
-   within a group is less than 64k in size.  Will break with cute linker
-   scripts that play games with dot in the output toc section.  */
+   within a group is less than 64k in size.  */
 
-void
+bfd_boolean
 ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd_vma addr, off, limit;
+
+  if (htab == NULL)
+    return FALSE;
+
+  if (!htab->second_toc_pass)
+    {
+      /* Keep track of the first .toc or .got section for this input bfd.  */
+      if (htab->toc_bfd != isec->owner)
+       {
+         htab->toc_bfd = isec->owner;
+         htab->toc_first_sec = isec;
+       }
+
+      addr = isec->output_offset + isec->output_section->vma;
+      off = addr - htab->toc_curr;
+      limit = 0x80008000;
+      if (ppc64_elf_tdata (isec->owner)->has_small_toc_reloc)
+       limit = 0x10000;
+      if (off + isec->size > limit)
+       {
+         addr = (htab->toc_first_sec->output_offset
+                 + htab->toc_first_sec->output_section->vma);
+         htab->toc_curr = addr;
+       }
+
+      /* toc_curr is the base address of this toc group.  Set elf_gp
+        for the input section to be the offset relative to the
+        output toc base plus 0x8000.  Making the input elf_gp an
+        offset allows us to move the toc as a whole without
+        recalculating input elf_gp.  */
+      off = htab->toc_curr - elf_gp (isec->output_section->owner);
+      off += TOC_BASE_OFF;
+
+      /* Die if someone uses a linker script that doesn't keep input
+        file .toc and .got together.  */
+      if (elf_gp (isec->owner) != 0
+         && elf_gp (isec->owner) != off)
+       return FALSE;
+
+      elf_gp (isec->owner) = off;
+      return TRUE;
+    }
+
+  /* During the second pass toc_first_sec points to the start of
+     a toc group, and toc_curr is used to track the old elf_gp.
+     We use toc_bfd to ensure we only look at each bfd once.  */
+  if (htab->toc_bfd == isec->owner)
+    return TRUE;
+  htab->toc_bfd = isec->owner;
+
+  if (htab->toc_first_sec == NULL
+      || htab->toc_curr != elf_gp (isec->owner))
+    {
+      htab->toc_curr = elf_gp (isec->owner);
+      htab->toc_first_sec = isec;
+    }
+  addr = (htab->toc_first_sec->output_offset
+         + htab->toc_first_sec->output_section->vma);
+  off = addr - elf_gp (isec->output_section->owner) + TOC_BASE_OFF;
+  elf_gp (isec->owner) = off;
+
+  return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to merge GOT entries for global
+   symbol H.  */
+
+static bfd_boolean
+merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  merge_got_entries (&h->got.glist);
+
+  return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to allocate GOT entries for global
+   symbol H.  */
+
+static bfd_boolean
+reallocate_got (struct elf_link_hash_entry *h, void *inf)
+{
+  struct got_entry *gent;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (!gent->is_indirect)
+      allocate_got (h, (struct bfd_link_info *) inf, gent);
+  return TRUE;
+}
+
+/* Called on the first multitoc pass after the last call to
+   ppc64_elf_next_toc_section.  This function removes duplicate GOT
+   entries.  */
+
+bfd_boolean
+ppc64_elf_layout_multitoc (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  struct bfd *ibfd, *ibfd2;
+  bfd_boolean done_something;
 
-  if (!htab->no_multi_toc)
+  htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd);
+
+  if (!htab->do_multi_toc)
+    return FALSE;
+
+  /* Merge global sym got entries within a toc group.  */
+  elf_link_hash_traverse (&htab->elf, merge_global_got, info);
+
+  /* And tlsld_got.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry *ent, *ent2;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      ent = ppc64_tlsld_got (ibfd);
+      if (!ent->is_indirect
+         && ent->got.offset != (bfd_vma) -1)
+       {
+         for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next)
+           {
+             if (!is_ppc64_elf (ibfd2))
+               continue;
+
+             ent2 = ppc64_tlsld_got (ibfd2);
+             if (!ent2->is_indirect
+                 && ent2->got.offset != (bfd_vma) -1
+                 && elf_gp (ibfd2) == elf_gp (ibfd))
+               {
+                 ent2->is_indirect = TRUE;
+                 ent2->got.ent = ent;
+               }
+           }
+       }
+    }
+
+  /* Zap sizes of got sections.  */
+  htab->reliplt->rawsize = htab->reliplt->size;
+  htab->reliplt->size -= htab->got_reli_size;
+  htab->got_reli_size = 0;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
-      bfd_vma addr = isec->output_offset + isec->output_section->vma;
-      bfd_vma off = addr - htab->toc_curr;
+      asection *got, *relgot;
 
-      if (off + isec->size > 0x10000)
-       htab->toc_curr = addr;
+      if (!is_ppc64_elf (ibfd))
+       continue;
 
-      elf_gp (isec->owner) = (htab->toc_curr
-                             - elf_gp (isec->output_section->owner)
-                             + TOC_BASE_OFF);
+      got = ppc64_elf_tdata (ibfd)->got;
+      if (got != NULL)
+       {
+         got->rawsize = got->size;
+         got->size = 0;
+         relgot = ppc64_elf_tdata (ibfd)->relgot;
+         relgot->rawsize = relgot->size;
+         relgot->size = 0;
+       }
     }
+
+  /* Now reallocate the got, local syms first.  We don't need to
+     allocate section contents again since we never increase size.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry **lgot_ents;
+      struct got_entry **end_lgot_ents;
+      struct plt_entry **local_plt;
+      struct plt_entry **end_local_plt;
+      unsigned char *lgot_masks;
+      bfd_size_type locsymcount;
+      Elf_Internal_Shdr *symtab_hdr;
+      asection *s, *srel;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      lgot_masks = (unsigned char *) end_local_plt;
+      s = ppc64_elf_tdata (ibfd)->got;
+      srel = ppc64_elf_tdata (ibfd)->relgot;
+      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+       {
+         struct got_entry *ent;
+
+         for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+           {
+             unsigned int num = 1;
+             ent->got.offset = s->size;
+             if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
+               num = 2;
+             s->size += num * 8;
+             if (info->shared)
+               srel->size += num * sizeof (Elf64_External_Rela);
+             else if ((*lgot_masks & PLT_IFUNC) != 0)
+               {
+                 htab->reliplt->size
+                   += num * sizeof (Elf64_External_Rela);
+                 htab->got_reli_size
+                   += num * sizeof (Elf64_External_Rela);
+               }
+           }
+       }
+    }
+
+  elf_link_hash_traverse (&htab->elf, reallocate_got, info);
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry *ent;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      ent = ppc64_tlsld_got (ibfd);
+      if (!ent->is_indirect
+         && ent->got.offset != (bfd_vma) -1)
+       {
+         asection *s = ppc64_elf_tdata (ibfd)->got;
+         ent->got.offset = s->size;
+         s->size += 16;
+         if (info->shared)
+           {
+             asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+             srel->size += sizeof (Elf64_External_Rela);
+           }
+       }
+    }
+
+  done_something = htab->reliplt->rawsize != htab->reliplt->size;
+  if (!done_something)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+      {
+       asection *got;
+
+       if (!is_ppc64_elf (ibfd))
+         continue;
+
+       got = ppc64_elf_tdata (ibfd)->got;
+       if (got != NULL)
+         {
+           done_something = got->rawsize != got->size;
+           if (done_something)
+             break;
+         }
+      }
+
+  if (done_something)
+    (*htab->layout_sections_again) ();
+
+  /* Set up for second pass over toc sections to recalculate elf_gp
+     on input sections.  */
+  htab->toc_bfd = NULL;
+  htab->toc_first_sec = NULL;
+  htab->second_toc_pass = TRUE;
+  return done_something;
 }
 
-/* Called after the last call to the above function.  */
+/* Called after second pass of multitoc partitioning.  */
 
 void
-ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info)
+ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd);
-
-  /* toc_curr tracks the TOC offset used for code sections below in
-     ppc64_elf_next_input_section.  Start off at 0x8000.  */
+  /* After the second pass, toc_curr tracks the TOC offset used
+     for code sections below in ppc64_elf_next_input_section.  */
   htab->toc_curr = TOC_BASE_OFF;
 }
 
@@ -9676,10 +10631,10 @@ ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info)
 static int
 toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
 {
-  Elf_Internal_Rela *relstart, *rel;
-  Elf_Internal_Sym *local_syms;
   int ret;
-  struct ppc_link_hash_table *htab;
+
+  /* Mark this section as checked.  */
+  isec->call_check_done = 1;
 
   /* We know none of our code bearing sections will need toc stubs.  */
   if ((isec->flags & SEC_LINKER_CREATED) != 0)
@@ -9691,176 +10646,189 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
   if (isec->output_section == NULL)
     return 0;
 
-  if (isec->reloc_count == 0)
-    return 0;
-
-  relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
-                                       info->keep_memory);
-  if (relstart == NULL)
-    return -1;
-
-  /* Look for branches to outside of this section.  */
-  local_syms = NULL;
   ret = 0;
-  htab = ppc_hash_table (info);
-  for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
+  if (isec->reloc_count != 0)
     {
-      enum elf_ppc64_reloc_type r_type;
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
-      struct ppc_link_hash_entry *eh;
-      Elf_Internal_Sym *sym;
-      asection *sym_sec;
-      struct _opd_sec_data *opd;
-      bfd_vma sym_value;
-      bfd_vma dest;
-
-      r_type = ELF64_R_TYPE (rel->r_info);
-      if (r_type != R_PPC64_REL24
-         && r_type != R_PPC64_REL14
-         && r_type != R_PPC64_REL14_BRTAKEN
-         && r_type != R_PPC64_REL14_BRNTAKEN)
-       continue;
-
-      r_symndx = ELF64_R_SYM (rel->r_info);
-      if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx,
-                     isec->owner))
-       {
-         ret = -1;
-         break;
-       }
-
-      /* Calls to dynamic lib functions go through a plt call stub
-        that uses r2.  */
-      eh = (struct ppc_link_hash_entry *) h;
-      if (eh != NULL
-         && (eh->elf.plt.plist != NULL
-             || (eh->oh != NULL
-                 && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
-       {
-         ret = 1;
-         break;
-       }
-
-      if (sym_sec == NULL)
-       /* Ignore other undefined symbols.  */
-       continue;
+      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Sym *local_syms;
+      struct ppc_link_hash_table *htab;
 
-      /* Assume branches to other sections not included in the link need
-        stubs too, to cover -R and absolute syms.  */
-      if (sym_sec->output_section == NULL)
-       {
-         ret = 1;
-         break;
-       }
+      relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
+                                           info->keep_memory);
+      if (relstart == NULL)
+       return -1;
 
-      if (h == NULL)
-       sym_value = sym->st_value;
-      else
-       {
-         if (h->root.type != bfd_link_hash_defined
-             && h->root.type != bfd_link_hash_defweak)
-           abort ();
-         sym_value = h->root.u.def.value;
-       }
-      sym_value += rel->r_addend;
+      /* Look for branches to outside of this section.  */
+      local_syms = NULL;
+      htab = ppc_hash_table (info);
+      if (htab == NULL)
+       return -1;
 
-      /* If this branch reloc uses an opd sym, find the code section.  */
-      opd = get_opd_info (sym_sec);
-      if (opd != NULL)
+      for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
        {
-         if (h == NULL && opd->adjust != NULL)
+         enum elf_ppc64_reloc_type r_type;
+         unsigned long r_symndx;
+         struct elf_link_hash_entry *h;
+         struct ppc_link_hash_entry *eh;
+         Elf_Internal_Sym *sym;
+         asection *sym_sec;
+         struct _opd_sec_data *opd;
+         bfd_vma sym_value;
+         bfd_vma dest;
+
+         r_type = ELF64_R_TYPE (rel->r_info);
+         if (r_type != R_PPC64_REL24
+             && r_type != R_PPC64_REL14
+             && r_type != R_PPC64_REL14_BRTAKEN
+             && r_type != R_PPC64_REL14_BRNTAKEN)
+           continue;
+
+         r_symndx = ELF64_R_SYM (rel->r_info);
+         if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx,
+                         isec->owner))
            {
-             long adjust;
+             ret = -1;
+             break;
+           }
 
-             adjust = opd->adjust[sym->st_value / 8];
-             if (adjust == -1)
-               /* Assume deleted functions won't ever be called.  */
-               continue;
-             sym_value += adjust;
+         /* Calls to dynamic lib functions go through a plt call stub
+            that uses r2.  */
+         eh = (struct ppc_link_hash_entry *) h;
+         if (eh != NULL
+             && (eh->elf.plt.plist != NULL
+                 || (eh->oh != NULL
+                     && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
+           {
+             ret = 1;
+             break;
            }
 
-         dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
-         if (dest == (bfd_vma) -1)
+         if (sym_sec == NULL)
+           /* Ignore other undefined symbols.  */
            continue;
-       }
-      else
-       dest = (sym_value
-               + sym_sec->output_offset
-               + sym_sec->output_section->vma);
 
-      /* Ignore branch to self.  */
-      if (sym_sec == isec)
-       continue;
+         /* Assume branches to other sections not included in the
+            link need stubs too, to cover -R and absolute syms.  */
+         if (sym_sec->output_section == NULL)
+           {
+             ret = 1;
+             break;
+           }
 
-      /* If the called function uses the toc, we need a stub.  */
-      if (sym_sec->has_toc_reloc
-         || sym_sec->makes_toc_func_call)
-       {
-         ret = 1;
-         break;
-       }
+         if (h == NULL)
+           sym_value = sym->st_value;
+         else
+           {
+             if (h->root.type != bfd_link_hash_defined
+                 && h->root.type != bfd_link_hash_defweak)
+               abort ();
+             sym_value = h->root.u.def.value;
+           }
+         sym_value += rel->r_addend;
 
-      /* Assume any branch that needs a long branch stub might in fact
-        need a plt_branch stub.  A plt_branch stub uses r2.  */
-      else if (dest - (isec->output_offset
-                      + isec->output_section->vma
-                      + rel->r_offset) + (1 << 25) >= (2 << 25))
-       {
-         ret = 1;
-         break;
-       }
+         /* If this branch reloc uses an opd sym, find the code section.  */
+         opd = get_opd_info (sym_sec);
+         if (opd != NULL)
+           {
+             if (h == NULL && opd->adjust != NULL)
+               {
+                 long adjust;
 
-      /* If calling back to a section in the process of being tested, we
-        can't say for sure that no toc adjusting stubs are needed, so
-        don't return zero.  */
-      else if (sym_sec->call_check_in_progress)
-       ret = 2;
+                 adjust = opd->adjust[sym->st_value / 8];
+                 if (adjust == -1)
+                   /* Assume deleted functions won't ever be called.  */
+                   continue;
+                 sym_value += adjust;
+               }
 
-      /* Branches to another section that itself doesn't have any TOC
-        references are OK.  Recursively call ourselves to check.  */
-      else if (sym_sec->id <= htab->top_id
-              && htab->stub_group[sym_sec->id].toc_off == 0)
-       {
-         int recur;
+             dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
+             if (dest == (bfd_vma) -1)
+               continue;
+           }
+         else
+           dest = (sym_value
+                   + sym_sec->output_offset
+                   + sym_sec->output_section->vma);
 
-         /* Mark current section as indeterminate, so that other
-            sections that call back to current won't be marked as
-            known.  */
-         isec->call_check_in_progress = 1;
-         recur = toc_adjusting_stub_needed (info, sym_sec);
-         isec->call_check_in_progress = 0;
+         /* Ignore branch to self.  */
+         if (sym_sec == isec)
+           continue;
 
-         if (recur < 0)
+         /* If the called function uses the toc, we need a stub.  */
+         if (sym_sec->has_toc_reloc
+             || sym_sec->makes_toc_func_call)
            {
-             /* An error.  Exit.  */
-             ret = -1;
+             ret = 1;
              break;
            }
-         else if (recur <= 1)
+
+         /* Assume any branch that needs a long branch stub might in fact
+            need a plt_branch stub.  A plt_branch stub uses r2.  */
+         else if (dest - (isec->output_offset
+                          + isec->output_section->vma
+                          + rel->r_offset) + (1 << 25) >= (2 << 25))
+           {
+             ret = 1;
+             break;
+           }
+
+         /* If calling back to a section in the process of being
+            tested, we can't say for sure that no toc adjusting stubs
+            are needed, so don't return zero.  */
+         else if (sym_sec->call_check_in_progress)
+           ret = 2;
+
+         /* Branches to another section that itself doesn't have any TOC
+            references are OK.  Recursively call ourselves to check.  */
+         else if (!sym_sec->call_check_done)
            {
-             /* Known result.  Mark as checked and set section flag.  */
-             htab->stub_group[sym_sec->id].toc_off = 1;
+             int recur;
+
+             /* Mark current section as indeterminate, so that other
+                sections that call back to current won't be marked as
+                known.  */
+             isec->call_check_in_progress = 1;
+             recur = toc_adjusting_stub_needed (info, sym_sec);
+             isec->call_check_in_progress = 0;
+
              if (recur != 0)
                {
-                 sym_sec->makes_toc_func_call = 1;
-                 ret = 1;
-                 break;
+                 ret = recur;
+                 if (recur != 2)
+                   break;
                }
            }
-         else
-           {
-             /* Unknown result.  Continue checking.  */
-             ret = 2;
-           }
+       }
+
+      if (local_syms != NULL
+         && (elf_symtab_hdr (isec->owner).contents
+             != (unsigned char *) local_syms))
+       free (local_syms);
+      if (elf_section_data (isec)->relocs != relstart)
+       free (relstart);
+    }
+
+  if ((ret & 1) == 0
+      && isec->map_head.s != NULL
+      && (strcmp (isec->output_section->name, ".init") == 0
+         || strcmp (isec->output_section->name, ".fini") == 0))
+    {
+      if (isec->map_head.s->has_toc_reloc
+         || isec->map_head.s->makes_toc_func_call)
+       ret = 1;
+      else if (!isec->map_head.s->call_check_done)
+       {
+         int recur;
+         isec->call_check_in_progress = 1;
+         recur = toc_adjusting_stub_needed (info, isec->map_head.s);
+         isec->call_check_in_progress = 0;
+         if (recur != 0)
+           ret = recur;
        }
     }
 
-  if (local_syms != NULL
-      && (elf_symtab_hdr (isec->owner).contents != (unsigned char *) local_syms))
-    free (local_syms);
-  if (elf_section_data (isec)->relocs != relstart)
-    free (relstart);
+  if (ret == 1)
+    isec->makes_toc_func_call = 1;
 
   return ret;
 }
@@ -9875,6 +10843,9 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
+  if (htab == NULL)
+    return FALSE;
+
   if ((isec->output_section->flags & SEC_CODE) != 0
       && isec->output_section->index <= htab->top_index)
     {
@@ -9903,23 +10874,78 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
          if (elf_gp (isec->owner) != 0)
            htab->toc_curr = elf_gp (isec->owner);
        }
-      else if (htab->stub_group[isec->id].toc_off == 0)
+      else
        {
-         int ret = toc_adjusting_stub_needed (info, isec);
-         if (ret < 0)
+         if (!isec->call_check_done
+             && toc_adjusting_stub_needed (info, isec) < 0)
            return FALSE;
-         else
-           isec->makes_toc_func_call = ret & 1;
+         /* If we make a local call from this section, ie. a branch
+            without a following nop, then we have no place to put a
+            toc restoring insn.  We must use the same toc group as
+            the callee.
+            Testing makes_toc_func_call actually tests for *any*
+            calls to functions that need a good toc pointer.  A more
+            precise test would be better, as this one will set
+            incorrect values for pasted .init/.fini fragments.
+            (Fixed later in check_pasted_section.)  */
+         if (isec->makes_toc_func_call
+             && elf_gp (isec->owner) != 0)
+           htab->toc_curr = elf_gp (isec->owner);
        }
     }
 
   /* Functions that don't use the TOC can belong in any TOC group.
-     Use the last TOC base.  This happens to make _init and _fini
-     pasting work.  */
+     Use the last TOC base.  */
   htab->stub_group[isec->id].toc_off = htab->toc_curr;
   return TRUE;
 }
 
+/* Check that all .init and .fini sections use the same toc, if they
+   have toc relocs.  */
+
+static bfd_boolean
+check_pasted_section (struct bfd_link_info *info, const char *name)
+{
+  asection *o = bfd_get_section_by_name (info->output_bfd, name);
+
+  if (o != NULL)
+    {
+      struct ppc_link_hash_table *htab = ppc_hash_table (info);
+      bfd_vma toc_off = 0;
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+       if (i->has_toc_reloc)
+         {
+           if (toc_off == 0)
+             toc_off = htab->stub_group[i->id].toc_off;
+           else if (toc_off != htab->stub_group[i->id].toc_off)
+             return FALSE;
+         }
+
+      if (toc_off == 0)
+       for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+         if (i->makes_toc_func_call)
+           {
+             toc_off = htab->stub_group[i->id].toc_off;
+             break;
+           }
+
+      /* Make sure the whole pasted function uses the same toc offset.  */
+      if (toc_off != 0)
+       for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+         htab->stub_group[i->id].toc_off = toc_off;
+    }
+  return TRUE;
+}
+
+bfd_boolean
+ppc64_elf_check_init_fini (struct bfd_link_info *info)
+{
+  return (check_pasted_section (info, ".init")
+         & check_pasted_section (info, ".fini"));
+}
+
 /* See whether we can group stub sections together.  Grouping stub
    sections may result in fewer stubs.  More importantly, we need to
    put all .init* and .fini* stubs at the beginning of the .init or
@@ -9968,7 +10994,8 @@ group_sections (struct ppc_link_hash_table *htab,
 
          curr = tail;
          total = tail->size;
-         big_sec = total > (ppc64_elf_section_data (tail)->has_14bit_branch
+         big_sec = total > (ppc64_elf_section_data (tail) != NULL
+                            && ppc64_elf_section_data (tail)->has_14bit_branch
                             ? stub14_group_size : stub_group_size);
          if (big_sec && !suppress_size_errors)
            (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
@@ -9977,7 +11004,8 @@ group_sections (struct ppc_link_hash_table *htab,
 
          while ((prev = PREV_SEC (curr)) != NULL
                 && ((total += curr->output_offset - prev->output_offset)
-                    < (ppc64_elf_section_data (prev)->has_14bit_branch
+                    < (ppc64_elf_section_data (prev) != NULL
+                       && ppc64_elf_section_data (prev)->has_14bit_branch
                        ? stub14_group_size : stub_group_size))
                 && htab->stub_group[prev->id].toc_off == curr_toc)
            curr = prev;
@@ -10010,7 +11038,8 @@ group_sections (struct ppc_link_hash_table *htab,
              total = 0;
              while (prev != NULL
                     && ((total += tail->output_offset - prev->output_offset)
-                        < (ppc64_elf_section_data (prev)->has_14bit_branch
+                        < (ppc64_elf_section_data (prev) != NULL
+                           && ppc64_elf_section_data (prev)->has_14bit_branch
                            ? stub14_group_size : stub_group_size))
                     && htab->stub_group[prev->id].toc_off == curr_toc)
                {
@@ -10027,6 +11056,40 @@ group_sections (struct ppc_link_hash_table *htab,
 #undef PREV_SEC
 }
 
+static const unsigned char glink_eh_frame_cie[] =
+{
+  0, 0, 0, 16,                         /* length.  */
+  0, 0, 0, 0,                          /* id.  */
+  1,                                   /* CIE version.  */
+  'z', 'R', 0,                         /* Augmentation string.  */
+  4,                                   /* Code alignment.  */
+  0x78,                                        /* Data alignment.  */
+  65,                                  /* RA reg.  */
+  1,                                   /* Augmentation size.  */
+  DW_EH_PE_pcrel | DW_EH_PE_sdata4,    /* FDE encoding.  */
+  DW_CFA_def_cfa, 1, 0                 /* def_cfa: r1 offset 0.  */
+};
+
+/* Stripping output sections is normally done before dynamic section
+   symbols have been allocated.  This function is called later, and
+   handles cases like htab->brlt which is mapped to its own output
+   section.  */
+
+static void
+maybe_strip_output (struct bfd_link_info *info, asection *isec)
+{
+  if (isec->size == 0
+      && isec->output_section->size == 0
+      && !bfd_section_removed_from_list (info->output_bfd,
+                                        isec->output_section)
+      && elf_section_data (isec->output_section)->dynindx == 0)
+    {
+      isec->output_section->flags |= SEC_EXCLUDE;
+      bfd_section_list_remove (info->output_bfd, isec->output_section);
+      info->output_bfd->section_count--;
+    }
+}
+
 /* 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
@@ -10034,19 +11097,17 @@ group_sections (struct ppc_link_hash_table *htab,
    instruction.  */
 
 bfd_boolean
-ppc64_elf_size_stubs (bfd *output_bfd,
-                     struct bfd_link_info *info,
-                     bfd_signed_vma group_size,
-                     asection *(*add_stub_section) (const char *, asection *),
-                     void (*layout_sections_again) (void))
+ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
+                     bfd_boolean plt_static_chain)
 {
   bfd_size_type stub_group_size;
   bfd_boolean stubs_always_before_branch;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  /* Stash our params away.  */
-  htab->add_stub_section = add_stub_section;
-  htab->layout_sections_again = layout_sections_again;
+  if (htab == NULL)
+    return FALSE;
+
+  htab->plt_static_chain = plt_static_chain;
   stubs_always_before_branch = group_size < 0;
   if (group_size < 0)
     stub_group_size = -group_size;
@@ -10098,7 +11159,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
              /* If this section is a link-once section that will be
                 discarded, then don't create any stubs.  */
              if (section->output_section == NULL
-                 || section->output_section->owner != output_bfd)
+                 || section->output_section->owner != info->output_bfd)
                continue;
 
              /* Get the relocs.  */
@@ -10269,7 +11330,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      && irela != internal_relocs)
                    {
                      /* Get tls info.  */
-                     char *tls_mask;
+                     unsigned char *tls_mask;
 
                      if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
                                         irela - 1, input_bfd))
@@ -10278,6 +11339,14 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                        continue;
                    }
 
+                 if (stub_type == ppc_stub_plt_call
+                     && irela + 1 < irelaend
+                     && irela[1].r_offset == irela->r_offset + 4
+                     && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE
+                     && !tocsave_find (htab, INSERT,
+                                       &local_syms, irela + 1, input_bfd))
+                   goto error_ret_free_internal;
+
                  /* Support for grouping stub sections.  */
                  id_sec = htab->stub_group[section->id].link_sec;
 
@@ -10295,7 +11364,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      continue;
                    }
 
-                 stub_entry = ppc_add_stub (stub_name, section, htab);
+                 stub_entry = ppc_add_stub (stub_name, section, info);
                  if (stub_entry == NULL)
                    {
                      free (stub_name);
@@ -10372,6 +11441,25 @@ ppc64_elf_size_stubs (bfd *output_bfd,
          htab->glink->flags |= SEC_RELOC;
        }
 
+      if (htab->glink_eh_frame != NULL
+         && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
+         && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0)
+       {
+         bfd_size_type size = 0;
+
+         for (stub_sec = htab->stub_bfd->sections;
+              stub_sec != NULL;
+              stub_sec = stub_sec->next)
+           if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+             size += 20;
+         if (htab->glink != NULL && htab->glink->size != 0)
+           size += 24;
+         if (size != 0)
+           size += sizeof (glink_eh_frame_cie);
+         htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+         htab->glink_eh_frame->size = size;
+       }
+
       for (stub_sec = htab->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
@@ -10381,17 +11469,18 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 
       /* Exit from this loop when no stubs have been added, and no stubs
         have changed size.  */
-      if (stub_sec == NULL)
+      if (stub_sec == NULL
+         && (htab->glink_eh_frame == NULL
+             || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
        break;
 
       /* Ask the linker to do its stuff.  */
       (*htab->layout_sections_again) ();
     }
 
-  /* It would be nice to strip htab->brlt from the output if the
-     section is empty, but it's too late.  If we strip sections here,
-     the dynamic symbol table is corrupted since the section symbol
-     for the stripped section isn't written.  */
+  maybe_strip_output (info, htab->brlt);
+  if (htab->glink_eh_frame != NULL)
+    maybe_strip_output (info, htab->glink_eh_frame);
 
   return TRUE;
 }
@@ -10468,6 +11557,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
   bfd_byte *p;
   int stub_sec_count = 0;
 
+  if (htab == NULL)
+    return FALSE;
+
   htab->emit_stub_syms = emit_stub_syms;
 
   /* Allocate memory to hold the linker stubs.  */
@@ -10593,6 +11685,100 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
        return FALSE;
     }
 
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0)
+    {
+      bfd_vma val;
+
+      p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
+      if (p == NULL)
+       return FALSE;
+      htab->glink_eh_frame->contents = p;
+
+      htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+
+      memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
+      /* CIE length (rewrite in case little-endian).  */
+      bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
+      p += sizeof (glink_eh_frame_cie);
+
+      for (stub_sec = htab->stub_bfd->sections;
+          stub_sec != NULL;
+          stub_sec = stub_sec->next)
+       if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+         {
+           /* FDE length.  */
+           bfd_put_32 (htab->elf.dynobj, 16, p);
+           p += 4;
+           /* CIE pointer.  */
+           val = p - htab->glink_eh_frame->contents;
+           bfd_put_32 (htab->elf.dynobj, val, p);
+           p += 4;
+           /* Offset to stub section.  */
+           val = (stub_sec->output_section->vma
+                  + stub_sec->output_offset);
+           val -= (htab->glink_eh_frame->output_section->vma
+                   + htab->glink_eh_frame->output_offset);
+           val -= p - htab->glink_eh_frame->contents;
+           if (val + 0x80000000 > 0xffffffff)
+             {
+               info->callbacks->einfo
+                 (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
+                  stub_sec->name);
+               return FALSE;
+             }
+           bfd_put_32 (htab->elf.dynobj, val, p);
+           p += 4;
+           /* stub section size.  */
+           bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p);
+           p += 4;
+           /* Augmentation.  */
+           p += 1;
+           /* Pad.  */
+           p += 3;
+         }
+      if (htab->glink != NULL && htab->glink->size != 0)
+       {
+         /* FDE length.  */
+         bfd_put_32 (htab->elf.dynobj, 20, p);
+         p += 4;
+         /* CIE pointer.  */
+         val = p - htab->glink_eh_frame->contents;
+         bfd_put_32 (htab->elf.dynobj, val, p);
+         p += 4;
+         /* Offset to .glink.  */
+         val = (htab->glink->output_section->vma
+                + htab->glink->output_offset
+                + 8);
+         val -= (htab->glink_eh_frame->output_section->vma
+                 + htab->glink_eh_frame->output_offset);
+         val -= p - htab->glink_eh_frame->contents;
+         if (val + 0x80000000 > 0xffffffff)
+           {
+             info->callbacks->einfo
+               (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
+                htab->glink->name);
+             return FALSE;
+           }
+         bfd_put_32 (htab->elf.dynobj, val, p);
+         p += 4;
+         /* .glink size.  */
+         bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p);
+         p += 4;
+         /* Augmentation.  */
+         p += 1;
+
+         *p++ = DW_CFA_advance_loc + 1;
+         *p++ = DW_CFA_register;
+         *p++ = 65;
+         *p++ = 12;
+         *p++ = DW_CFA_advance_loc + 4;
+         *p++ = DW_CFA_restore_extended;
+         *p++ = 65;
+       }
+      htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents;
+    }
+
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
@@ -10610,10 +11796,12 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       }
 
   if (stub_sec != NULL
-      || htab->glink->rawsize != htab->glink->size)
+      || htab->glink->rawsize != htab->glink->size
+      || (htab->glink_eh_frame != NULL
+         && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
     {
       htab->stub_error = TRUE;
-      (*_bfd_error_handler) (_("stubs don't match calculated size"));
+      info->callbacks->einfo (_("%P: stubs don't match calculated size\n"));
     }
 
   if (htab->stub_error)
@@ -10652,9 +11840,6 @@ undo_symbol_twiddle (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
   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;
-
   eh = (struct ppc_link_hash_entry *) h;
   if (eh->elf.root.type != bfd_link_hash_undefweak || !eh->was_undefined)
     return TRUE;
@@ -10667,7 +11852,9 @@ void
 ppc64_elf_restore_symbols (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
-  elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
+
+  if (htab != NULL)
+    elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
 }
 
 /* What to do when ld finds relocations against symbols defined in
@@ -10747,6 +11934,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
     ppc_howto_init ();
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Don't relocate stub sections.  */
   if (input_section->owner == htab->stub_bfd)
@@ -10775,12 +11964,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       const char *sym_name;
       unsigned long r_symndx, toc_symndx;
       bfd_vma toc_addend;
-      char tls_mask, tls_gd, tls_type;
-      char sym_type;
+      unsigned char tls_mask, tls_gd, tls_type;
+      unsigned char sym_type;
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
-      unsigned long insn, mask;
+      unsigned int insn;
+      unsigned int mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
@@ -10847,16 +12037,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       h = (struct ppc_link_hash_entry *) h_elf;
 
       if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd,
-                              contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend,
+                                        ppc64_elf_howto_table[r_type],
+                                        contents);
 
       if (info->relocatable)
        continue;
@@ -10874,7 +12058,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        {
          struct plt_entry **local_plt = (struct plt_entry **)
            (local_got_ents + symtab_hdr->sh_info);
-         char *lgot_masks = (char *)
+         unsigned char *lgot_masks = (unsigned char *)
            (local_plt + symtab_hdr->sh_info);
          tls_mask = lgot_masks[r_symndx];
        }
@@ -10884,7 +12068,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              || r_type == R_PPC64_TLSLD))
        {
          /* Check for toc tls entries.  */
-         char *toc_tls;
+         unsigned char *toc_tls;
 
          if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
                             &local_syms, rel, input_bfd))
@@ -10896,7 +12080,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
       /* Check that tls relocs are used with tls syms, and non-tls
         relocs are used with non-tls syms.  */
-      if (r_symndx != 0
+      if (r_symndx != STN_UNDEF
          && r_type != R_PPC64_NONE
          && (h == NULL
              || h->elf.root.type == bfd_link_hash_defined
@@ -10913,13 +12097,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            /* R_PPC64_TLS is OK against a symbol in the TOC.  */
            ;
          else
-           (*_bfd_error_handler)
+           info->callbacks->einfo
              (!IS_PPC64_TLS_RELOC (r_type)
-              ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
-              : _("%B(%A+0x%lx): %s used with non-TLS symbol %s"),
-              input_bfd,
-              input_section,
-              (long) rel->r_offset,
+              ? _("%P: %H: %s used with TLS symbol %s\n")
+              : _("%P: %H: %s used with non-TLS symbol %s\n"),
+              input_bfd, input_section, rel->r_offset,
               ppc64_elf_howto_table[r_type]->name,
               sym_name);
        }
@@ -10942,13 +12124,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        default:
          break;
 
+       case R_PPC64_LO_DS_OPT:
+         insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+         if ((insn & (0x3f << 26)) != 58u << 26)
+           abort ();
+         insn += (14u << 26) - (58u << 26);
+         bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+         r_type = R_PPC64_TOC16_LO;
+         rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+         break;
+
        case R_PPC64_TOC16:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_DS:
        case R_PPC64_TOC16_LO_DS:
          {
            /* Check for toc tls entries.  */
-           char *toc_tls;
+           unsigned char *toc_tls;
            int retval;
 
            retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
@@ -10986,6 +12178,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          }
          break;
 
+       case R_PPC64_GOT_TPREL16_HI:
+       case R_PPC64_GOT_TPREL16_HA:
+         if (tls_mask != 0
+             && (tls_mask & TLS_TPREL) == 0)
+           {
+             rel->r_offset -= d_offset;
+             bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
+             r_type = R_PPC64_NONE;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+           }
+         break;
+
        case R_PPC64_GOT_TPREL16_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
          if (tls_mask != 0
@@ -11055,8 +12259,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          + R_PPC64_GOT_TPREL16_DS);
              else
                {
-                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  rel->r_offset -= d_offset;
+                 bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
                  r_type = R_PPC64_NONE;
                }
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
@@ -11123,9 +12327,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        if (local_sections[r_symndx] == sec)
                          break;
                      if (r_symndx >= symtab_hdr->sh_info)
-                       r_symndx = 0;
+                       r_symndx = STN_UNDEF;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-                     if (r_symndx != 0)
+                     if (r_symndx != STN_UNDEF)
                        rel->r_addend -= (local_syms[r_symndx].st_value
                                          + sec->output_offset
                                          + sec->output_section->vma);
@@ -11231,9 +12435,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (local_sections[r_symndx] == sec)
                  break;
              if (r_symndx >= symtab_hdr->sh_info)
-               r_symndx = 0;
+               r_symndx = STN_UNDEF;
              rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
-             if (r_symndx != 0)
+             if (r_symndx != STN_UNDEF)
                rel->r_addend -= (local_syms[r_symndx].st_value
                                  + sec->output_offset
                                  + sec->output_section->vma);
@@ -11307,6 +12511,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        default:
          break;
 
+       case R_PPC64_TOCSAVE:
+         if (relocation + addend == (rel->r_offset
+                                     + input_section->output_offset
+                                     + input_section->output_section->vma)
+             && tocsave_find (htab, NO_INSERT,
+                              &local_syms, rel, input_bfd))
+           {
+             insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+             if (insn == NOP
+                 || insn == CROR_151515 || insn == CROR_313131)
+               bfd_put_32 (input_bfd, STD_R2_40R1,
+                           contents + rel->r_offset);
+           }
+         break;
+
          /* Branch taken prediction relocations.  */
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
@@ -11331,23 +12550,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             linkage stubs needs to be followed by a nop, as the nop
             will be replaced with an instruction to restore the TOC
             base pointer.  */
-         stub_entry = NULL;
          fdh = h;
          if (h != NULL
              && h->oh != NULL
              && h->oh->is_func_descriptor)
            fdh = ppc_follow_link (h->oh);
-         if (((fdh != NULL
-               && fdh->elf.plt.plist != NULL)
-              || (sec != NULL
-                  && sec->output_section != NULL
-                  && sec->id <= htab->top_id
-                  && (htab->stub_group[sec->id].toc_off
-                      != htab->stub_group[input_section->id].toc_off))
-              || (h == NULL
-                  && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
-             && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
-                                                  rel, htab)) != NULL
+         stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
+         if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
                  || stub_entry->stub_type == ppc_stub_long_branch_r2off))
@@ -11403,23 +12612,19 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                  ".init") == 0
                          || strcmp (input_section->output_section->name,
                                     ".fini") == 0)
-                       (*_bfd_error_handler)
-                         (_("%B(%A+0x%lx): automatic multiple TOCs "
+                       info->callbacks->einfo
+                         (_("%P: %H: automatic multiple TOCs "
                             "not supported using your crt files; "
-                            "recompile with -mminimal-toc or upgrade gcc"),
-                          input_bfd,
-                          input_section,
-                          (long) rel->r_offset);
+                            "recompile with -mminimal-toc or upgrade gcc\n"),
+                          input_bfd, input_section, rel->r_offset);
                      else
-                       (*_bfd_error_handler)
-                         (_("%B(%A+0x%lx): sibling call optimization to `%s' "
+                       info->callbacks->einfo
+                         (_("%P: %H: sibling call optimization to `%s' "
                             "does not allow automatic multiple TOCs; "
                             "recompile with -mminimal-toc or "
                             "-fno-optimize-sibling-calls, "
-                            "or make `%s' extern"),
-                          input_bfd,
-                          input_section,
-                          (long) rel->r_offset,
+                            "or make `%s' extern\n"),
+                          input_bfd, input_section, rel->r_offset,
                           sym_name,
                           sym_name);
                      bfd_set_error (bfd_error_bad_value);
@@ -11432,7 +12637,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                unresolved_reloc = FALSE;
            }
 
-         if (stub_entry == NULL
+         if ((stub_entry == NULL
+              || stub_entry->stub_type == ppc_stub_long_branch
+              || stub_entry->stub_type == ppc_stub_plt_branch)
              && get_opd_info (sec) != NULL)
            {
              /* The branch destination is the value of the opd entry. */
@@ -11453,13 +12660,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  + input_section->output_offset
                  + input_section->output_section->vma);
 
-         if (stub_entry == NULL
-             && (relocation + addend - from + max_br_offset
-                 >= 2 * max_br_offset)
-             && r_type != R_PPC64_ADDR14_BRTAKEN
-             && r_type != R_PPC64_ADDR14_BRNTAKEN)
-           stub_entry = ppc_get_stub_entry (input_section, sec, h, rel,
-                                            htab);
+         if (stub_entry != NULL
+             && (stub_entry->stub_type == ppc_stub_long_branch
+                 || stub_entry->stub_type == ppc_stub_plt_branch)
+             && (r_type == R_PPC64_ADDR14_BRTAKEN
+                 || r_type == R_PPC64_ADDR14_BRNTAKEN
+                 || (relocation + addend - from + max_br_offset
+                     < 2 * max_br_offset)))
+           /* Don't use the stub if this branch is in range.  */
+           stub_entry = NULL;
 
          if (stub_entry != NULL)
            {
@@ -11469,6 +12678,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                            + stub_entry->stub_sec->output_offset
                            + stub_entry->stub_sec->output_section->vma);
              addend = 0;
+
+             if (stub_entry->stub_type == ppc_stub_plt_call
+                 && rel + 1 < relend
+                 && rel[1].r_offset == rel->r_offset + 4
+                 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
+               relocation += 4;
            }
 
          if (insn != 0)
@@ -11500,6 +12715,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             checking whether the function is defined.  */
          else if (h != NULL
                   && h->elf.root.type == bfd_link_hash_undefweak
+                  && h->elf.dynindx == -1
                   && r_type == R_PPC64_REL24
                   && relocation == 0
                   && addend == 0)
@@ -11515,8 +12731,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       switch (r_type)
        {
        default:
-         (*_bfd_error_handler)
-           (_("%B: unknown relocation type %d for symbol %s"),
+         info->callbacks->einfo
+           (_("%P: %B: unknown relocation type %d for symbol %s\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
@@ -11527,6 +12743,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TLS:
        case R_PPC64_TLSGD:
        case R_PPC64_TLSLD:
+       case R_PPC64_TOCSAVE:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
          continue;
@@ -11577,14 +12794,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            bfd_vma *offp;
            bfd_vma off;
            unsigned long indx = 0;
+           struct got_entry *ent;
 
            if (tls_type == (TLS_TLS | TLS_LD)
                && (h == NULL
                    || !h->elf.def_dynamic))
-             offp = &ppc64_tlsld_got (input_bfd)->offset;
+             ent = ppc64_tlsld_got (input_bfd);
            else
              {
-               struct got_entry *ent;
 
                if (h != NULL)
                  {
@@ -11592,7 +12809,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
                                                          &h->elf)
                        || (info->shared
-                           && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
+                           && SYMBOL_CALLS_LOCAL (info, &h->elf)))
                      /* 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
@@ -11617,12 +12834,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      && ent->owner == input_bfd
                      && ent->tls_type == tls_type)
                    break;
-               if (ent == NULL)
-                 abort ();
-               offp = &ent->got.offset;
              }
 
-           got = ppc64_elf_tdata (input_bfd)->got;
+           if (ent == NULL)
+             abort ();
+           if (ent->is_indirect)
+             ent = ent->got.ent;
+           offp = &ent->got.offset;
+           got = ppc64_elf_tdata (ent->owner)->got;
            if (got == NULL)
              abort ();
 
@@ -11646,11 +12865,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                         ? h->elf.type == STT_GNU_IFUNC
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if ((info->shared || indx != 0)
-                   && (offp == &ppc64_tlsld_got (input_bfd)->offset
-                       || h == NULL
+                   && (h == NULL
+                       || (tls_type == (TLS_TLS | TLS_LD)
+                           && !h->elf.def_dynamic)
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || h->elf.root.type != bfd_link_hash_undefweak))
-                 relgot = ppc64_elf_tdata (input_bfd)->relgot;
+                 relgot = ppc64_elf_tdata (ent->owner)->relgot;
                else if (ifunc)
                  relgot = htab->reliplt;
                if (relgot != NULL)
@@ -11737,10 +12957,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            if (off >= (bfd_vma) -2)
              abort ();
 
-           relocation = got->output_offset + off;
-
-           /* TOC base (r2) is TOC start plus 0x8000.  */
-           addend = -TOC_BASE_OFF;
+           relocation = got->output_section->vma + got->output_offset + off;
+           addend = -(TOCstart + htab->stub_group[input_section->id].toc_off);
          }
          break;
 
@@ -11779,7 +12997,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TOC:
          /* Relocation value is TOC base.  */
          relocation = TOCstart;
-         if (r_symndx == 0)
+         if (r_symndx == STN_UNDEF)
            relocation += htab->stub_group[input_section->id].toc_off;
          else if (unresolved_reloc)
            ;
@@ -11835,6 +13053,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
+         if (h != NULL
+             && h->elf.root.type == bfd_link_hash_undefweak
+             && h->elf.dynindx == -1)
+           {
+             /* Make this relocation against an undefined weak symbol
+                resolve to zero.  This is really just a tweak, since
+                code using weak externs ought to check that they are
+                defined before using them.  */
+             bfd_byte *p = contents + rel->r_offset - d_offset;
+
+             insn = bfd_get_32 (output_bfd, p);
+             insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
+             if (insn != 0)
+               bfd_put_32 (output_bfd, insn, p);
+             break;
+           }
          addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          if (info->shared)
            /* The TPREL16 relocs shouldn't really be used in shared
@@ -11952,7 +13186,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
+             else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
@@ -12003,17 +13237,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          ? h->elf.type == STT_GNU_IFUNC
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                        {
-                         (*_bfd_error_handler)
-                           (_("%B(%A+0x%lx): relocation %s for indirect "
-                              "function %s unsupported"),
-                            input_bfd,
-                            input_section,
-                            (long) rel->r_offset,
+                         info->callbacks->einfo
+                           (_("%P: %H: relocation %s for indirect "
+                              "function %s unsupported\n"),
+                            input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
                             sym_name);
                          ret = FALSE;
                        }
-                     else if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -12110,8 +13342,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLTREL64:
          /* These ones haven't been implemented yet.  */
 
-         (*_bfd_error_handler)
-           (_("%B: relocation %s is not supported for symbol %s."),
+         info->callbacks->einfo
+           (_("%P: %B: relocation %s is not supported for symbol %s\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
@@ -12120,6 +13352,72 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          continue;
        }
 
+      /* Multi-instruction sequences that access the TOC can be
+        optimized, eg. addis ra,r2,0; addi rb,ra,x;
+        to             nop;           addi rb,r2,x;  */
+      switch (r_type)
+       {
+       default:
+         break;
+
+       case R_PPC64_GOT_TLSLD16_HI:
+       case R_PPC64_GOT_TLSGD16_HI:
+       case R_PPC64_GOT_TPREL16_HI:
+       case R_PPC64_GOT_DTPREL16_HI:
+       case R_PPC64_GOT16_HI:
+       case R_PPC64_TOC16_HI:
+         /* These relocs would only be useful if building up an
+            offset to later add to r2, perhaps in an indexed
+            addressing mode instruction.  Don't try to optimize.
+            Unfortunately, the possibility of someone building up an
+            offset like this or even with the HA relocs, means that
+            we need to check the high insn when optimizing the low
+            insn.  */
+         break;
+
+       case R_PPC64_GOT_TLSLD16_HA:
+       case R_PPC64_GOT_TLSGD16_HA:
+       case R_PPC64_GOT_TPREL16_HA:
+       case R_PPC64_GOT_DTPREL16_HA:
+       case R_PPC64_GOT16_HA:
+       case R_PPC64_TOC16_HA:
+         if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
+           {
+             bfd_byte *p = contents + (rel->r_offset & ~3);
+             bfd_put_32 (input_bfd, NOP, p);
+           }
+         break;
+
+       case R_PPC64_GOT_TLSLD16_LO:
+       case R_PPC64_GOT_TLSGD16_LO:
+       case R_PPC64_GOT_TPREL16_LO_DS:
+       case R_PPC64_GOT_DTPREL16_LO_DS:
+       case R_PPC64_GOT16_LO:
+       case R_PPC64_GOT16_LO_DS:
+       case R_PPC64_TOC16_LO:
+       case R_PPC64_TOC16_LO_DS:
+         if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
+             && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
+           {
+             bfd_byte *p = contents + (rel->r_offset & ~3);
+             insn = bfd_get_32 (input_bfd, p);
+             if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
+               {
+                 /* Transform addic to addi when we change reg.  */
+                 insn &= ~((0x3f << 26) | (0x1f << 16));
+                 insn |= (14u << 26) | (2 << 16);
+               }
+             else
+               {
+                 insn &= ~(0x1f << 16);
+                 insn |= 2 << 16;
+               }
+             bfd_put_32 (input_bfd, insn, p);
+           }
+         break;
+       }
+
       /* Do any further special processing.  */
       switch (r_type)
        {
@@ -12193,9 +13491,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            mask = 15;
          if (((relocation + addend) & mask) != 0)
            {
-             (*_bfd_error_handler)
-               (_("%B: error: relocation %s not a multiple of %d"),
-                input_bfd,
+             info->callbacks->einfo
+               (_("%P: %H: error: %s not a multiple of %u\n"),
+                input_bfd, input_section, rel->r_offset,
                 ppc64_elf_howto_table[r_type]->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
@@ -12210,13 +13508,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
         not process them.  */
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
-              && h->elf.def_dynamic))
+              && h->elf.def_dynamic)
+         && _bfd_elf_section_offset (output_bfd, info, input_section,
+                                     rel->r_offset) != (bfd_vma) -1)
        {
-         (*_bfd_error_handler)
-           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
-            input_bfd,
-            input_section,
-            (long) rel->r_offset,
+         info->callbacks->einfo
+           (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
+            input_bfd, input_section, rel->r_offset,
             ppc64_elf_howto_table[(int) r_type]->name,
             h->elf.root.root.string);
          ret = FALSE;
@@ -12259,11 +13557,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          else
            {
-             (*_bfd_error_handler)
-               (_("%B(%A+0x%lx): %s reloc against `%s': error %d"),
-                input_bfd,
-                input_section,
-                (long) rel->r_offset,
+             info->callbacks->einfo
+               (_("%P: %H: %s reloc against `%s': error %d\n"),
+                input_bfd, input_section, rel->r_offset,
                 ppc64_elf_howto_table[r_type]->name,
                 sym_name,
                 (int) r);
@@ -12338,6 +13634,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
   bfd_byte *loc;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
@@ -12437,6 +13735,9 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
   asection *sdyn;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   dynobj = htab->elf.dynobj;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
@@ -12550,7 +13851,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
       && htab->brlt->reloc_count != 0
       && !_bfd_elf_link_output_relocs (output_bfd,
                                       htab->brlt,
-                                      &elf_section_data (htab->brlt)->rel_hdr,
+                                      elf_section_data (htab->brlt)->rela.hdr,
                                       elf_section_data (htab->brlt)->relocs,
                                       NULL))
     return FALSE;
@@ -12559,11 +13860,19 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
       && htab->glink->reloc_count != 0
       && !_bfd_elf_link_output_relocs (output_bfd,
                                       htab->glink,
-                                      &elf_section_data (htab->glink)->rel_hdr,
+                                      elf_section_data (htab->glink)->rela.hdr,
                                       elf_section_data (htab->glink)->relocs,
                                       NULL))
     return FALSE;
 
+
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME
+      && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+                                          htab->glink_eh_frame,
+                                          htab->glink_eh_frame->contents))
+    return FALSE;
+
   /* We need to handle writing out multiple GOT sections ourselves,
      since we didn't add them to DYNOBJ.  We know dynobj is the first
      bfd.  */
@@ -12596,3 +13905,22 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
 }
 
 #include "elf64-target.h"
+
+/* FreeBSD support */
+
+#undef  TARGET_LITTLE_SYM
+#undef  TARGET_LITTLE_NAME
+
+#undef  TARGET_BIG_SYM
+#define TARGET_BIG_SYM bfd_elf64_powerpc_freebsd_vec
+#undef  TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elf64-powerpc-freebsd"
+
+#undef  ELF_OSABI
+#define        ELF_OSABI       ELFOSABI_FREEBSD
+
+#undef  elf64_bed
+#define elf64_bed      elf64_powerpc_fbsd_bed
+
+#include "elf64-target.h"
+