Remove trailing white spaces in bfd
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 5696838502ad1fa42ddec02e56a12e8ffe160732..151c0ceb2932741a46e3dee695da14f37e9435d1 100644 (file)
@@ -1,6 +1,6 @@
 /* PowerPC64-specific support for 64-bit ELF.
    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010 Free Software Foundation, Inc.
+   2009, 2010, 2011, 2012 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.
@@ -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 **);
@@ -54,13 +55,14 @@ static bfd_reloc_status_type ppc64_elf_toc64_reloc
 static bfd_reloc_status_type ppc64_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_vma opd_entry_value
-  (asection *, bfd_vma, asection **, bfd_vma *);
+  (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
 
 #define TARGET_LITTLE_SYM      bfd_elf64_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf64-powerpcle"
 #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
@@ -102,6 +105,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_gc_sweep_hook            ppc64_elf_gc_sweep_hook
 #define elf_backend_adjust_dynamic_symbol     ppc64_elf_adjust_dynamic_symbol
 #define elf_backend_hide_symbol                      ppc64_elf_hide_symbol
+#define elf_backend_maybe_function_sym       ppc64_elf_maybe_function_sym
 #define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
 #define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
 #define elf_backend_init_index_section       _bfd_elf_init_2_index_sections
@@ -149,6 +153,13 @@ static bfd_vma opd_entry_value
 #define ADDIS_R2_R2    0x3c420000      /* addis %r2,%r2,off@ha  */
 #define ADDI_R2_R2     0x38420000      /* addi  %r2,%r2,off@l   */
 
+#define XOR_R11_R11_R11        0x7d6b5a78      /* xor   %r11,%r11,%r11  */
+#define ADD_R12_R12_R11        0x7d8c5a14      /* add   %r12,%r12,%r11  */
+#define ADD_R2_R2_R11  0x7c425a14      /* add   %r2,%r2,%r11    */
+#define CMPLDI_R2_0    0x28220000      /* cmpldi %r2,0          */
+#define BNECTR         0x4ca20420      /* bnectr+               */
+#define BNECTR_P4      0x4ce20420      /* bnectr+               */
+
 #define LD_R11_0R2     0xe9620000      /* ld    %r11,xxx+0(%r2) */
 #define LD_R2_0R2      0xe8420000      /* ld    %r2,xxx+0(%r2)  */
 
@@ -1279,6 +1290,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,
@@ -2322,7 +2347,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     {
       bfd_vma dest = opd_entry_value (symbol->section,
                                      symbol->value + reloc_entry->addend,
-                                     NULL, NULL);
+                                     NULL, NULL, FALSE);
       if (dest != (bfd_vma) -1)
        reloc_entry->addend = dest - (symbol->value
                                      + symbol->section->output_section->vma
@@ -2339,8 +2364,8 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   long insn;
   enum elf_ppc64_reloc_type r_type;
   bfd_size_type octets;
-  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
-  bfd_boolean is_power4 = FALSE;
+  /* Assume 'at' branch hints.  */
+  bfd_boolean is_isa_v2 = TRUE;
 
   /* If this is a relocatable link (output_bfd test tells us), just
      call the generic function.  Any adjustment will be done at final
@@ -2357,7 +2382,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
       || r_type == R_PPC64_REL14_BRTAKEN)
     insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
 
-  if (is_power4)
+  if (is_isa_v2)
     {
       /* Set 'a' bit.  This is 0b00010 in BO field for branch
         on CR(BI) insns (BO == 001at or 011at), and 0b01000
@@ -2595,7 +2620,11 @@ struct ppc64_elf_obj_tdata
 
   /* 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;
+  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) \
@@ -2651,7 +2680,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;
@@ -2668,6 +2697,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
@@ -2691,7 +2722,7 @@ ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
        va_list ap;
 
        va_start (ap, note_type);
-       memset (data, 0, 40);
+       memset (data, 0, sizeof (data));
        strncpy (data + 40, va_arg (ap, const char *), 16);
        strncpy (data + 56, va_arg (ap, const char *), 80);
        va_end (ap);
@@ -2723,35 +2754,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[]=
@@ -3257,7 +3259,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
              if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
                goto free_contents_and_exit;
-       
+
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
              size += plt_count * sizeof (asymbol);
 
@@ -3315,8 +3317,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;
@@ -3482,26 +3485,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;
-};
-
 /* 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.  */
@@ -3609,7 +3592,8 @@ enum ppc_stub_type {
   ppc_stub_long_branch_r2off,
   ppc_stub_plt_branch,
   ppc_stub_plt_branch_r2off,
-  ppc_stub_plt_call
+  ppc_stub_plt_call,
+  ppc_stub_plt_call_r2save
 };
 
 struct ppc_stub_hash_entry {
@@ -3668,7 +3652,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;
@@ -3717,6 +3701,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;
 
@@ -3764,20 +3751,33 @@ 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 special .TOC. symbol.  */
+  struct ppc_link_hash_entry *dot_toc_dot;
+
   /* The size of reliplt used by got entry relocs.  */
   bfd_size_type got_reli_size;
 
   /* Statistics.  */
-  unsigned long stub_count[ppc_stub_plt_call];
+  unsigned long stub_count[ppc_stub_plt_call_r2save];
 
   /* Number of stubs against global syms.  */
   unsigned long stub_globals;
 
+  /* Alignment of PLT call stubs.  */
+  unsigned int plt_stub_align:4;
+
+  /* Set if PLT call stubs should load r11.  */
+  unsigned int plt_static_chain:1;
+
+  /* Set if PLT call stubs need a read-read barrier.  */
+  unsigned int plt_thread_safe:1;
+
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
@@ -3788,6 +3788,7 @@ struct ppc_link_hash_table
   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;
@@ -3820,6 +3821,7 @@ struct ppc_link_hash_table
 
 /* 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.  */
 
@@ -3957,6 +3959,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 *
@@ -3987,6 +4009,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
@@ -4008,10 +4037,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);
 }
 
@@ -4131,8 +4162,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;
@@ -4169,8 +4201,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;
     }
 
@@ -4208,6 +4240,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 (dynobj, 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
@@ -4267,7 +4311,7 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
       if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
        return FALSE;
 
-      htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got");
+      htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got");
       if (!htab->got)
        abort ();
     }
@@ -4306,12 +4350,12 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   if (!htab->got)
-    htab->got = bfd_get_section_by_name (dynobj, ".got");
-  htab->plt = bfd_get_section_by_name (dynobj, ".plt");
-  htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt");
-  htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+    htab->got = bfd_get_linker_section (dynobj, ".got");
+  htab->plt = bfd_get_linker_section (dynobj, ".plt");
+  htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt");
+  htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
   if (!info->shared)
-    htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+    htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
 
   if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
       || (!info->shared && !htab->relbss))
@@ -4390,19 +4434,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)
@@ -4422,26 +4485,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;
 
@@ -4565,15 +4615,19 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
                           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)
     {
       if ((ibfd->flags & DYNAMIC) == 0)
-       elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+       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;
@@ -4742,6 +4796,25 @@ ppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED,
   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)
@@ -4842,7 +4915,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;
@@ -4872,15 +4945,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   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
@@ -5380,8 +5448,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
@@ -5420,7 +5488,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;
@@ -5457,27 +5525,43 @@ static bfd_vma
 opd_entry_value (asection *opd_sec,
                 bfd_vma offset,
                 asection **code_sec,
-                bfd_vma *code_off)
+                bfd_vma *code_off,
+                bfd_boolean in_code_sec)
 {
   bfd *opd_bfd = opd_sec->owner;
   Elf_Internal_Rela *relocs;
   Elf_Internal_Rela *lo, *hi, *look;
   bfd_vma val;
 
-  /* No relocs implies we are linking a --just-symbols object.  */
+  /* No relocs implies we are linking a --just-symbols object, or looking
+     at a final linked executable with addr2line or somesuch.  */
   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;
-         for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
-           if (sec->vma <= val
-               && (sec->flags & SEC_LOAD) != 0
-               && (sec->flags & SEC_ALLOC) != 0)
-             likely = sec;
+
+         if (in_code_sec)
+           {
+             sec = *code_sec;
+             if (sec->vma <= val
+                 && val < sec->vma + sec->size)
+               likely = sec;
+             else
+               val = -1;
+           }
+         else
+           for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
+             if (sec->vma <= val
+                 && (sec->flags & SEC_LOAD) != 0
+                 && (sec->flags & SEC_ALLOC) != 0)
+               likely = sec;
          if (likely != NULL)
            {
              *code_sec = likely;
@@ -5516,15 +5600,18 @@ opd_entry_value (asection *opd_sec,
              unsigned long symndx = ELF64_R_SYM (look->r_info);
              asection *sec;
 
-             if (symndx < symtab_hdr->sh_info)
+             if (symndx < symtab_hdr->sh_info
+                 || elf_sym_hashes (opd_bfd) == NULL)
                {
                  Elf_Internal_Sym *sym;
 
                  sym = (Elf_Internal_Sym *) symtab_hdr->contents;
                  if (sym == NULL)
                    {
-                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr,
-                                                 symtab_hdr->sh_info,
+                     size_t symcnt = symtab_hdr->sh_info;
+                     if (elf_sym_hashes (opd_bfd) == NULL)
+                       symcnt = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
+                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, symcnt,
                                                  0, NULL, NULL, NULL);
                      if (sym == NULL)
                        break;
@@ -5553,7 +5640,12 @@ opd_entry_value (asection *opd_sec,
              if (code_off != NULL)
                *code_off = val;
              if (code_sec != NULL)
-               *code_sec = sec;
+               {
+                 if (in_code_sec && *code_sec != sec)
+                   return -1;
+                 else
+                   *code_sec = sec;
+               }
              if (sec != NULL && sec->output_section != NULL)
                val += sec->output_section->vma + sec->output_offset;
            }
@@ -5564,6 +5656,66 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
+/* If the ELF symbol SYM might be a function in SEC, return the
+   function size and set *CODE_OFF to the function's entry point,
+   otherwise return zero.  */
+
+static bfd_size_type
+ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                             bfd_vma *code_off)
+{
+  bfd_size_type size;
+
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
+    return 0;
+
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+
+  if (strcmp (sym->section->name, ".opd") == 0)
+    {
+      if (opd_entry_value (sym->section, sym->value,
+                          &sec, code_off, TRUE) == (bfd_vma) -1)
+       return 0;
+      /* An old ABI binary with dot-syms has a size of 24 on the .opd
+        symbol.  This size has nothing to do with the code size of the
+        function, which is what we're supposed to return, but the
+        code size isn't available without looking up the dot-sym.
+        However, doing that would be a waste of time particularly
+        since elf_find_function will look at the dot-sym anyway.
+        Now, elf_find_function will keep the largest size of any
+        function sym found at the code address of interest, so return
+        1 here to avoid it incorrectly caching a larger function size
+        for a small function.  This does mean we return the wrong
+        size for a new-ABI function of size 24, but all that does is
+        disable caching for such functions.  */
+      if (size == 24)
+       size = 1;
+    }
+  else
+    {
+      if (sym->section != sec)
+       return 0;
+      *code_off = sym->value;
+    }
+  if (size == 0)
+    size = 1;
+  return size;
+}
+
+/* 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.  */
 
@@ -5630,7 +5782,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &sec, NULL) != (bfd_vma) -1)
+                                  &sec, NULL, FALSE) != (bfd_vma) -1)
        sec->flags |= SEC_KEEP;
 
       sec = eh->elf.root.u.def.section;
@@ -5649,9 +5801,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)
@@ -5663,7 +5812,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;
@@ -5681,7 +5833,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &code_sec, NULL) != (bfd_vma) -1)
+                                  &code_sec, NULL, FALSE) != (bfd_vma) -1)
        code_sec->flags |= SEC_KEEP;
     }
 
@@ -5741,7 +5893,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                       && opd_entry_value (eh->elf.root.u.def.section,
                                           eh->elf.root.u.def.value,
-                                          &rsec, NULL) != (bfd_vma) -1)
+                                          &rsec, NULL, FALSE) != (bfd_vma) -1)
                eh->elf.root.u.def.section->gc_mark = 1;
              else
                rsec = h->root.u.def.section;
@@ -5815,8 +5967,8 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *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);
@@ -6194,9 +6346,6 @@ 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)
@@ -6213,7 +6362,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
                          &fh->elf.root.u.def.section,
-                         &fh->elf.root.u.def.value) != (bfd_vma) -1)
+                         &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1)
     {
       fh->elf.root.type = fdh->elf.root.type;
       fh->elf.forced_local = 1;
@@ -6322,7 +6471,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
 {
   struct ppc_link_hash_table *htab;
   unsigned int i;
-  const struct sfpr_def_parms funcs[] =
+  static const struct sfpr_def_parms funcs[] =
     {
       { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
       { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
@@ -6348,9 +6497,10 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
 
   /* Provide any missing _save* and _rest* functions.  */
   htab->sfpr->size = 0;
-  for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
-    if (!sfpr_define (info, &funcs[i]))
-      return FALSE;
+  if (!info->relocatable)
+    for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
+      if (!sfpr_define (info, &funcs[i]))
+       return FALSE;
 
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
@@ -6434,7 +6584,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)
@@ -6460,22 +6610,15 @@ 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);
     }
 
   /* This is a reference to a symbol defined by a dynamic object which
      is not a function.  */
 
-  if (h->size == 0)
-    {
-      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
-                            h->root.root.string);
-      return TRUE;
-    }
-
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -6490,7 +6633,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      to copy the initial value out of the dynamic object and into the
      runtime process image.  We need to remember the offset into the
      .rela.bss section we are going to use.  */
-  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
     {
       htab->relbss->size += sizeof (Elf64_External_Rela);
       h->needs_copy = 1;
@@ -6681,6 +6824,7 @@ get_tls_mask (unsigned 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;
 
@@ -6702,15 +6846,61 @@ get_tls_mask (unsigned 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.  */
 
@@ -6724,9 +6914,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;
@@ -6747,7 +6934,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
          if (dsec == NULL)
            {
              for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next)
-               if (elf_discarded_section (dsec))
+               if (discarded_section (dsec))
                  {
                    ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec;
                    break;
@@ -6776,8 +6963,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.  */
@@ -6862,12 +7049,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
@@ -6891,8 +7078,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;
 }
@@ -6916,17 +7103,19 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
       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;
 
-      if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+      if (sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
        continue;
 
       if (sec->output_section == bfd_abs_section_ptr)
@@ -6938,7 +7127,6 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 
       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,
@@ -7065,6 +7253,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
       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;
@@ -7244,9 +7433,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 
          /* 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)
@@ -7373,7 +7561,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info,
                      _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;
@@ -7442,6 +7630,7 @@ 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)
@@ -7451,23 +7640,25 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
   if (htab == NULL)
     return FALSE;
 
-  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)
+  /* 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,
@@ -7489,6 +7680,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                  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,
@@ -7503,7 +7695,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                          && (elf_symtab_hdr (ibfd).contents
                              != (unsigned char *) locsyms))
                        free (locsyms);
-                     return FALSE;
+                     return ret;
                    }
 
                  if (h != NULL)
@@ -7514,7 +7706,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      else if (h->root.type == bfd_link_hash_undefweak)
                        value = 0;
                      else
-                       continue;
+                       {
+                         found_tls_get_addr_arg = 0;
+                         continue;
+                       }
                    }
                  else
                    /* Symbols referenced by TLS relocs must be of type
@@ -7541,11 +7736,34 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                    }
 
                  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:
@@ -7565,6 +7783,7 @@ ppc64_elf_tls_optimize (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:
@@ -7593,11 +7812,14 @@ ppc64_elf_tls_optimize (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;
 
@@ -7606,18 +7828,17 @@ ppc64_elf_tls_optimize (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)
@@ -7638,7 +7859,7 @@ ppc64_elf_tls_optimize (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)
                        {
@@ -7653,7 +7874,7 @@ ppc64_elf_tls_optimize (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
@@ -7705,8 +7926,13 @@ ppc64_elf_tls_optimize (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;
                        }
@@ -7717,9 +7943,12 @@ ppc64_elf_tls_optimize (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)
@@ -7805,18 +8034,18 @@ ppc64_elf_tls_optimize (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;
 }
 
@@ -7833,17 +8062,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)
@@ -7855,16 +8081,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)
@@ -7873,6 +8105,32 @@ 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.  */
 
@@ -7881,29 +8139,33 @@ 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
-         || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
-         || elf_discarded_section (toc))
+         || toc->sec_info_type == SEC_INFO_TYPE_JUST_SYMS
+         || 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;
@@ -7911,7 +8173,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
       for (sec = ibfd->sections; sec != NULL; sec = sec->next)
        {
          if (sec->reloc_count == 0
-             || !elf_discarded_section (sec)
+             || !discarded_section (sec)
              || get_opd_info (sec)
              || (sec->flags & SEC_ALLOC) == 0
              || (sec->flags & SEC_DEBUGGING) != 0)
@@ -7971,122 +8233,302 @@ ppc64_elf_edit_toc (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);
        }
 
-      if (skip == NULL)
-       continue;
-
-      used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8);
-      if (used == NULL)
-       {
-       error_ret:
-         if (local_syms != NULL
-             && symtab_hdr->contents != (unsigned char *) local_syms)
-           free (local_syms);
-         if (sec != NULL
-             && relstart != NULL
-             && elf_section_data (sec)->relocs != relstart)
-           free (relstart);
-         if (skip != NULL)
-           free (skip);
-         return FALSE;
-       }
+      /* 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.  */
 
-      /* Now check all kept sections that might reference the toc.
-        Check the toc itself last.  */
-      for (sec = (ibfd->sections == toc && toc->next ? toc->next
-                 : ibfd->sections);
-          sec != NULL;
-          sec = (sec == toc ? NULL
-                 : sec->next == NULL ? toc
-                 : sec->next == toc && toc->next ? toc->next
-                 : sec->next))
+      if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
+         && toc->output_section->rawsize < (bfd_vma) 1 << 31
+         && toc->reloc_count != 0)
        {
-         int repeat;
+         /* Read toc relocs.  */
+         toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                 info->keep_memory);
+         if (toc_relocs == NULL)
+           goto error_ret;
 
-         if (sec->reloc_count == 0
-             || elf_discarded_section (sec)
+         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
+                 || 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;
+
+      used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8);
+      if (used == NULL)
+       {
+       error_ret:
+         if (local_syms != NULL
+             && symtab_hdr->contents != (unsigned char *) local_syms)
+           free (local_syms);
+         if (sec != NULL
+             && 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;
+       }
+
+      /* Now check all kept sections that might reference the toc.
+        Check the toc itself last.  */
+      for (sec = (ibfd->sections == toc && toc->next ? toc->next
+                 : ibfd->sections);
+          sec != NULL;
+          sec = (sec == toc ? NULL
+                 : sec->next == NULL ? toc
+                 : sec->next == toc && toc->next ? toc->next
+                 : sec->next))
+       {
+         int repeat;
+
+         if (sec->reloc_count == 0
+             || discarded_section (sec)
              || get_opd_info (sec)
              || (sec->flags & SEC_ALLOC) == 0
              || (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;
 
          /* Mark toc entries referenced as used.  */
-         repeat = 0;
          do
-           for (rel = relstart; rel < relstart + sec->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;
-
-               r_type = ELF64_R_TYPE (rel->r_info);
-               switch (r_type)
-                 {
-                 case R_PPC64_TOC16:
-                 case R_PPC64_TOC16_LO:
-                 case R_PPC64_TOC16_HI:
-                 case R_PPC64_TOC16_HA:
-                 case R_PPC64_TOC16_DS:
-                 case R_PPC64_TOC16_LO_DS:
-                   /* In case we're taking addresses of toc entries.  */
-                 case R_PPC64_ADDR64:
-                   break;
+           {
+             repeat = 0;
+             for (rel = relstart; rel < relstart + sec->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;
+                 enum {no_check, check_lo, check_ha} insn_check;
 
-                 default:
+                 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:
+                   case R_PPC64_TOC16_HA:
+                   case R_PPC64_TOC16_DS:
+                   case R_PPC64_TOC16_LO_DS:
+                     /* In case we're taking addresses of toc entries.  */
+                   case R_PPC64_ADDR64:
+                     break;
+
+                   default:
+                     continue;
+                   }
+
+                 r_symndx = ELF64_R_SYM (rel->r_info);
+                 if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                                 r_symndx, ibfd))
+                   {
+                     free (used);
+                     goto error_ret;
+                   }
+
+                 if (sym_sec != toc)
                    continue;
-                 }
 
-               r_symndx = ELF64_R_SYM (rel->r_info);
-               if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
-                               r_symndx, ibfd))
-                 {
-                   free (used);
-                   goto error_ret;
-                 }
+                 if (h != NULL)
+                   val = h->root.u.def.value;
+                 else
+                   val = sym->st_value;
+                 val += rel->r_addend;
 
-               if (sym_sec != toc)
-                 continue;
+                 if (val >= toc->size)
+                   continue;
 
-               if (h != NULL)
-                 val = h->root.u.def.value;
-               else
-                 val = sym->st_value;
-               val += rel->r_addend;
+                 if ((skip[val >> 3] & can_optimize) != 0)
+                   {
+                     bfd_vma off;
+                     unsigned char opc;
 
-               if (val >= toc->size)
-                 continue;
+                     switch (r_type)
+                       {
+                       case R_PPC64_TOC16_HA:
+                         break;
 
-               /* 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]))
-                 /* Do all the relocs again, to catch reference
-                    chains.  */
-                 repeat = 1;
-
-               used[val >> 3] = 1;
-             }
+                       case R_PPC64_TOC16_LO_DS:
+                         off = rel->r_offset;
+                         off += (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;
+                       }
+                   }
+
+                 if (sec != toc)
+                   used[val >> 3] = 1;
+                 /* For the toc section, we only mark as used if this
+                    entry itself isn't unused.  */
+                 else if ((used[rel->r_offset >> 3]
+                           || !(skip[rel->r_offset >> 3] & ref_from_discarded))
+                          && !used[val >> 3])
+                   {
+                     /* Do all the relocs again, to catch reference
+                        chains.  */
+                     repeat = 1;
+                     used[val >> 3] = 1;
+                   }
+               }
+           }
          while (repeat);
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
        }
 
       /* Merge the used and skip arrays.  Assume that TOC
@@ -8098,13 +8540,15 @@ ppc64_elf_edit_toc (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;
@@ -8116,6 +8560,8 @@ ppc64_elf_edit_toc (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.  */
@@ -8128,60 +8574,28 @@ ppc64_elf_edit_toc (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
-                 || elf_discarded_section (sec))
+                 || discarded_section (sec))
                continue;
 
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
-                                                   TRUE);
+                                                   info->keep_memory);
              if (relstart == NULL)
                goto error_ret;
 
@@ -8191,7 +8605,7 @@ ppc64_elf_edit_toc (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)
@@ -8214,41 +8628,100 @@ ppc64_elf_edit_toc (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;
+                   }
 
-                 rel->r_addend -= skip[rel->r_addend >> 3];
+                 if (h != NULL || sym->st_value != 0)
+                   continue;
+
+                 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;
+                   }
 
-         /* Finally, adjust any global syms defined in the toc.  */
+                 sym->st_value -= skip[i];
+                 symtab_hdr->contents = (unsigned char *) local_syms;
+               }
+
+         /* Adjust any global syms defined in this toc input section.  */
          if (toc_inf.global_toc_syms)
            {
              toc_inf.toc = toc;
@@ -8257,7 +8730,44 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
              elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
                                      &toc_inf);
            }
+
+         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)
@@ -8273,6 +8783,16 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
   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
@@ -8339,15 +8859,12 @@ 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 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)
@@ -8503,7 +9020,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; )
            {
@@ -8586,10 +9103,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)
@@ -8635,7 +9149,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       /* Set the contents of the .interp section to the interpreter.  */
       if (info->executable)
        {
-         s = bfd_get_section_by_name (dynobj, ".interp");
+         s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
            abort ();
          s->size = sizeof ELF_DYNAMIC_INTERPRETER;
@@ -8661,7 +9175,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)
            {
@@ -8811,7 +9325,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)
            {
@@ -8993,12 +9513,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)
@@ -9043,24 +9559,131 @@ ppc_type_of_stub (asection *input_sec,
   return ppc_stub_none;
 }
 
-/* Build a .plt call stub.  */
+/* With power7 weakly ordered memory model, it is possible for ld.so
+   to update a plt entry in one thread and have another thread see a
+   stale zero toc entry.  To avoid this we need some sort of acquire
+   barrier in the call stub.  One solution is to make the load of the
+   toc word seem to appear to depend on the load of the function entry
+   word.  Another solution is to test for r2 being zero, and branch to
+   the appropriate glink entry if so.
+
+   .   fake dep barrier        compare
+   .   ld 11,xxx(2)            ld 11,xxx(2)
+   .   mtctr 11                mtctr 11
+   .   xor 11,11,11            ld 2,xxx+8(2)
+   .   add 2,2,11              cmpldi 2,0
+   .   ld 2,xxx+8(2)           bnectr+
+   .   bctr                    b <glink_entry>
+
+   The solution involving the compare turns out to be faster, so
+   that's what we use unless the branch won't reach.  */
+
+#define ALWAYS_USE_FAKE_DEP 0
+#define ALWAYS_EMIT_R2SAVE 0
 
-static inline bfd_byte *
-build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
-{
 #define PPC_LO(v) ((v) & 0xffff)
 #define PPC_HI(v) (((v) >> 16) & 0xffff)
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
+static inline unsigned int
+plt_stub_size (struct ppc_link_hash_table *htab,
+              struct ppc_stub_hash_entry *stub_entry,
+              bfd_vma off)
+{
+  unsigned size = PLT_CALL_STUB_SIZE;
+
+  if (!(ALWAYS_EMIT_R2SAVE
+       || stub_entry->stub_type == ppc_stub_plt_call_r2save))
+    size -= 4;
+  if (!htab->plt_static_chain)
+    size -= 4;
+  if (htab->plt_thread_safe)
+    size += 8;
+  if (PPC_HA (off) == 0)
+    size -= 4;
+  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
+         || stub_entry->h == htab->tls_get_addr)
+      && !htab->no_tls_get_addr_opt)
+    size += 13 * 4;
+  return size;
+}
+
+/* If this stub would cross fewer 2**plt_stub_align boundaries if we align,
+   then return the padding needed to do so.  */
+static inline unsigned int
+plt_stub_pad (struct ppc_link_hash_table *htab,
+             struct ppc_stub_hash_entry *stub_entry,
+             bfd_vma plt_off)
+{
+  int stub_align = 1 << htab->plt_stub_align;
+  unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
+  bfd_vma stub_off = stub_entry->stub_sec->size;
+
+  if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
+      > (stub_size & -stub_align))
+    return stub_align - (stub_off & (stub_align - 1));
+  return 0;
+}
+
+/* Build a .plt call stub.  */
+
+static inline bfd_byte *
+build_plt_stub (struct ppc_link_hash_table *htab,
+               struct ppc_stub_hash_entry *stub_entry,
+               bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
+{
+  bfd *obfd = htab->stub_bfd;
+  bfd_boolean plt_static_chain = htab->plt_static_chain;
+  bfd_boolean plt_thread_safe = htab->plt_thread_safe;
+  bfd_boolean use_fake_dep = plt_thread_safe;
+  bfd_vma cmp_branch_off = 0;
+
+  if (!ALWAYS_USE_FAKE_DEP
+      && plt_thread_safe
+      && !(stub_entry->h != NULL
+          && (stub_entry->h == htab->tls_get_addr_fd
+              || stub_entry->h == htab->tls_get_addr)
+          && !htab->no_tls_get_addr_opt))
+    {
+      bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
+      bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE;
+      bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
+      bfd_vma to, from;
+
+      if (pltindex > 32768)
+       glinkoff += (pltindex - 32768) * 4;
+      to = (glinkoff
+           + htab->glink->output_offset
+           + htab->glink->output_section->vma);
+      from = (p - stub_entry->stub_sec->contents
+             + 4 * (ALWAYS_EMIT_R2SAVE
+                    || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+             + 4 * (PPC_HA (offset) != 0)
+             + 4 * (PPC_HA (offset + 8 + 8 * plt_static_chain)
+                    != PPC_HA (offset))
+             + 4 * (plt_static_chain != 0)
+             + 20
+             + stub_entry->stub_sec->output_offset
+             + stub_entry->stub_sec->output_section->vma);
+      cmp_branch_off = to - from;
+      use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
+    }
+
   if (PPC_HA (offset) != 0)
     {
       if (r != NULL)
        {
+         if (ALWAYS_EMIT_R2SAVE
+             || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+           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);
@@ -9068,34 +9691,46 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
            }
          else
            {
-             r[2].r_offset = r[1].r_offset + 8;
+             r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
              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;
+               }
            }
        }
+      if (ALWAYS_EMIT_R2SAVE
+         || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+       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, STD_R2_40R1, 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;
+      if (use_fake_dep)
+       {
+         bfd_put_32 (obfd, XOR_R11_R11_R11, p),                p += 4;
+         bfd_put_32 (obfd, ADD_R12_R12_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;
-      bfd_put_32 (obfd, BCTR, p),                              p += 4;
+      if (plt_static_chain)
+       bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4;
     }
   else
     {
       if (r != NULL)
        {
-         r[0].r_offset += 4;
+         if (ALWAYS_EMIT_R2SAVE
+             || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+           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);
@@ -9103,26 +9738,44 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
            }
          else
            {
-             r[1].r_offset = r[0].r_offset + 8;
+             r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
              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;
+      if (ALWAYS_EMIT_R2SAVE
+         || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+       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 (use_fake_dep)
+       {
+         bfd_put_32 (obfd, XOR_R11_R11_R11, p),                p += 4;
+         bfd_put_32 (obfd, ADD_R2_R2_R11, 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;
     }
+  if (plt_thread_safe && !use_fake_dep)
+    {
+      bfd_put_32 (obfd, CMPLDI_R2_0, p),                       p += 4;
+      bfd_put_32 (obfd, BNECTR_P4, p),                         p += 4;
+      bfd_put_32 (obfd, B_DOT + cmp_branch_off, p),            p += 4;
+    }
+  else
+    bfd_put_32 (obfd, BCTR, p),                                        p += 4;
   return p;
 }
 
@@ -9143,9 +9796,12 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
 #define MTLR_R11       0x7d6803a6
 
 static inline bfd_byte *
-build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
-                        Elf_Internal_Rela *r)
+build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
+                        struct ppc_stub_hash_entry *stub_entry,
+                        bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
+  bfd *obfd = htab->stub_bfd;
+
   bfd_put_32 (obfd, LD_R11_0R3 + 0, p),                p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
   bfd_put_32 (obfd, MR_R0_R3, p),              p += 4;
@@ -9158,7 +9814,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 (htab, stub_entry, p, offset, r);
   bfd_put_32 (obfd, BCTRL, p - 4);
 
   bfd_put_32 (obfd, LD_R11_0R1 + 32, p),       p += 4;
@@ -9185,9 +9841,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;
@@ -9195,6 +9855,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)
 {
@@ -9239,10 +9931,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;
@@ -9260,8 +9955,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;
        }
@@ -9319,8 +10014,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;
        }
@@ -9380,8 +10075,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;
@@ -9426,10 +10121,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;
@@ -9462,6 +10161,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       break;
 
     case ppc_stub_plt_call:
+    case ppc_stub_plt_call_r2save:
       if (stub_entry->h != NULL
          && stub_entry->h->is_func_descriptor
          && stub_entry->h->oh != NULL)
@@ -9476,6 +10176,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.  */
@@ -9516,8 +10218,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>");
@@ -9526,12 +10228,23 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          return FALSE;
        }
 
+      if (htab->plt_stub_align != 0)
+       {
+         unsigned pad = plt_stub_pad (htab, stub_entry, off);
+
+         stub_entry->stub_sec->size += pad;
+         stub_entry->stub_offset = stub_entry->stub_sec->size;
+         loc += pad;
+       }
+
       r = NULL;
       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;
@@ -9543,9 +10256,9 @@ 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_entry, loc, off, r);
       else
-       p = build_plt_stub (htab->stub_bfd, loc, off, r);
+       p = build_plt_stub (htab, stub_entry, loc, off, r);
       size = p - loc;
       break;
 
@@ -9565,6 +10278,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                                       "long_branch_r2off",
                                       "plt_branch",
                                       "plt_branch_r2off",
+                                      "plt_call",
                                       "plt_call" };
 
       len1 = strlen (stub_str[stub_entry->stub_type - 1]);
@@ -9615,7 +10329,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   if (htab == NULL)
     return FALSE;
 
-  if (stub_entry->stub_type == ppc_stub_plt_call)
+  if (stub_entry->stub_type == ppc_stub_plt_call
+      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
     {
       asection *plt;
       off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
@@ -9631,20 +10346,16 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              - elf_gp (plt->output_section->owner)
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
-      size = PLT_CALL_STUB_SIZE;
-      if (PPC_HA (off) == 0)
-       size -= 4;
-      if (PPC_HA (off + 16) != PPC_HA (off))
-       size += 4;
-      if (stub_entry->h != NULL
-         && (stub_entry->h == htab->tls_get_addr_fd
-             || stub_entry->h == htab->tls_get_addr)
-         && !htab->no_tls_get_addr_opt)
-       size += 13 * 4;
+      size = plt_stub_size (htab, stub_entry, off);
+      if (htab->plt_stub_align)
+       size += plt_stub_pad (htab, stub_entry, off);
       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;
        }
     }
@@ -9669,8 +10380,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;
@@ -9687,8 +10402,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;
            }
@@ -9848,7 +10563,9 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
   if (!htab->second_toc_pass)
     {
       /* Keep track of the first .toc or .got section for this input bfd.  */
-      if (htab->toc_bfd != isec->owner)
+      bfd_boolean new_bfd = htab->toc_bfd != isec->owner;
+
+      if (new_bfd)
        {
          htab->toc_bfd = isec->owner;
          htab->toc_first_sec = isec;
@@ -9876,7 +10593,8 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
 
       /* Die if someone uses a linker script that doesn't keep input
         file .toc and .got together.  */
-      if (elf_gp (isec->owner) != 0
+      if (new_bfd
+         && elf_gp (isec->owner) != 0
          && elf_gp (isec->owner) != off)
        return FALSE;
 
@@ -9914,9 +10632,6 @@ merge_global_got (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;
-
   merge_got_entries (&h->got.glist);
 
   return TRUE;
@@ -9933,9 +10648,6 @@ reallocate_got (struct elf_link_hash_entry *h, void *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;
-
   for (gent = h->got.glist; gent != NULL; gent = gent->next)
     if (!gent->is_indirect)
       allocate_got (h, (struct bfd_link_info *) inf, gent);
@@ -10125,9 +10837,6 @@ ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  if (htab == NULL)
-    return;
-
   /* 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;
@@ -10144,10 +10853,10 @@ ppc64_elf_finish_multitoc_partition (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)
@@ -10159,179 +10868,190 @@ 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);
-  if (htab == NULL)
-    return -1;
-
-  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;
-       }
+      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Sym *local_syms;
+      struct ppc_link_hash_table *htab;
 
-      if (sym_sec == NULL)
-       /* Ignore other undefined symbols.  */
-       continue;
+      relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
+                                           info->keep_memory);
+      if (relstart == NULL)
+       return -1;
 
-      /* 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;
-       }
+      /* Look for branches to outside of this section.  */
+      local_syms = NULL;
+      htab = ppc_hash_table (info);
+      if (htab == NULL)
+       return -1;
 
-      if (h == NULL)
-       sym_value = sym->st_value;
-      else
+      for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
        {
-         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;
+         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;
 
-      /* 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)
+         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;
+
+                 adjust = opd->adjust[sym->st_value / 8];
+                 if (adjust == -1)
+                   /* Assume deleted functions won't ever be called.  */
+                   continue;
+                 sym_value += 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;
+             dest = opd_entry_value (sym_sec, sym_value,
+                                     &sym_sec, NULL, FALSE);
+             if (dest == (bfd_vma) -1)
+               continue;
+           }
+         else
+           dest = (sym_value
+                   + sym_sec->output_offset
+                   + sym_sec->output_section->vma);
 
-      /* 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;
+         /* Ignore branch to self.  */
+         if (sym_sec == isec)
+           continue;
 
-         /* 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 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 (recur < 0)
+         /* 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))
            {
-             /* An error.  Exit.  */
-             ret = -1;
+             ret = 1;
              break;
            }
-         else if (recur <= 1)
+
+         /* 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;
 }
@@ -10377,23 +11097,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
@@ -10442,7 +11217,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"),
@@ -10451,7 +11227,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;
@@ -10484,7 +11261,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)
                {
@@ -10501,6 +11279,41 @@ 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
+      && !(isec->output_section->flags & SEC_KEEP)
+      && !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
@@ -10508,7 +11321,9 @@ group_sections (struct ppc_link_hash_table *htab,
    instruction.  */
 
 bfd_boolean
-ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
+ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
+                     bfd_boolean plt_static_chain, int plt_thread_safe,
+                     int plt_stub_align)
 {
   bfd_size_type stub_group_size;
   bfd_boolean stubs_always_before_branch;
@@ -10517,6 +11332,44 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
   if (htab == NULL)
     return FALSE;
 
+  htab->plt_static_chain = plt_static_chain;
+  htab->plt_stub_align = plt_stub_align;
+  if (plt_thread_safe == -1)
+    {
+      const char *const thread_starter[] =
+       {
+         "pthread_create",
+         /* libstdc++ */
+         "_ZNSt6thread15_M_start_threadESt10shared_ptrINS_10_Impl_baseEE",
+         /* librt */
+         "aio_init", "aio_read", "aio_write", "aio_fsync", "lio_listio",
+         "mq_notify", "create_timer",
+         /* libanl */
+         "getaddrinfo_a",
+         /* libgomp */
+         "GOMP_parallel_start",
+         "GOMP_parallel_loop_static_start",
+         "GOMP_parallel_loop_dynamic_start",
+         "GOMP_parallel_loop_guided_start",
+         "GOMP_parallel_loop_runtime_start",
+         "GOMP_parallel_sections_start",
+       };
+      unsigned i;
+
+      for (i = 0; i < sizeof (thread_starter)/ sizeof (thread_starter[0]); i++)
+       {
+         struct elf_link_hash_entry *h;
+         h = elf_link_hash_lookup (&htab->elf, thread_starter[i],
+                                   FALSE, FALSE, TRUE);
+         plt_thread_safe = h != NULL && h->ref_regular;
+         if (plt_thread_safe)
+           break;
+       }
+    }
+  htab->plt_thread_safe = plt_thread_safe;
+  htab->dot_toc_dot = ((struct ppc_link_hash_entry *)
+                      elf_link_hash_lookup (&htab->elf, ".TOC.",
+                                            FALSE, FALSE, TRUE));
   stubs_always_before_branch = group_size < 0;
   if (group_size < 0)
     stub_group_size = -group_size;
@@ -10690,7 +11543,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
                          sym_value += adjust;
                        }
                      dest = opd_entry_value (sym_sec, sym_value,
-                                             &code_sec, &code_value);
+                                             &code_sec, &code_value, FALSE);
                      if (dest != (bfd_vma) -1)
                        {
                          destination = dest;
@@ -10748,6 +11601,18 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
                        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)
+                   {
+                     if (!tocsave_find (htab, INSERT,
+                                        &local_syms, irela + 1, input_bfd))
+                       goto error_ret_free_internal;
+                   }
+                 else if (stub_type == ppc_stub_plt_call)
+                   stub_type = ppc_stub_plt_call_r2save;
+
                  /* Support for grouping stub sections.  */
                  id_sec = htab->stub_group[section->id].link_sec;
 
@@ -10762,10 +11627,12 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
                    {
                      /* The proper stub has already been created.  */
                      free (stub_name);
+                     if (stub_type == ppc_stub_plt_call_r2save)
+                       stub_entry->stub_type = stub_type;
                      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);
@@ -10781,7 +11648,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
                    }
 
                  stub_entry->stub_type = stub_type;
-                 if (stub_type != ppc_stub_plt_call)
+                 if (stub_type != ppc_stub_plt_call
+                     && stub_type != ppc_stub_plt_call_r2save)
                    {
                      stub_entry->target_value = code_value;
                      stub_entry->target_section = code_sec;
@@ -10842,6 +11710,37 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
          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->output_section->size != 0)
+       {
+         size_t size = 0, align;
+
+         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);
+         align = 1;
+         align <<= htab->glink_eh_frame->output_section->alignment_power;
+         align -= 1;
+         size = (size + align) & ~align;
+         htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
+         htab->glink_eh_frame->size = size;
+       }
+
+      if (htab->plt_stub_align != 0)
+       for (stub_sec = htab->stub_bfd->sections;
+            stub_sec != NULL;
+            stub_sec = stub_sec->next)
+         if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+           stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
+                             & (-1 << htab->plt_stub_align));
+
       for (stub_sec = htab->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
@@ -10851,17 +11750,18 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
 
       /* 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;
 }
@@ -11066,12 +11966,131 @@ 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;
+      bfd_byte *last_fde;
+      size_t last_fde_len, size, align, pad;
+
+      p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
+      if (p == NULL)
+       return FALSE;
+      htab->glink_eh_frame->contents = p;
+      last_fde = 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).  */
+      last_fde_len = sizeof (glink_eh_frame_cie) - 4;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len, 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)
+         {
+           last_fde = p;
+           last_fde_len = 16;
+           /* 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)
+       {
+         last_fde = p;
+         last_fde_len = 20;
+         /* 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;
+       }
+      /* Subsume any padding into the last FDE if user .eh_frame
+        sections are aligned more than glink_eh_frame.  Otherwise any
+        zero padding will be seen as a terminator.  */
+      size = p - htab->glink_eh_frame->contents;
+      align = 1;
+      align <<= htab->glink_eh_frame->output_section->alignment_power;
+      align -= 1;
+      pad = ((size + align) & ~align) - size;
+      htab->glink_eh_frame->size = size + pad;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
+    }
+
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
   if (htab->relbrlt != NULL)
     htab->relbrlt->reloc_count = 0;
 
+  if (htab->plt_stub_align != 0)
+    for (stub_sec = htab->stub_bfd->sections;
+        stub_sec != NULL;
+        stub_sec = stub_sec->next)
+      if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
+       stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
+                         & (-1 << htab->plt_stub_align));
+
   for (stub_sec = htab->stub_bfd->sections;
        stub_sec != NULL;
        stub_sec = stub_sec->next)
@@ -11083,10 +12102,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)
@@ -11103,14 +12124,16 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
                         "  toc adjust   %lu\n"
                         "  long branch  %lu\n"
                         "  long toc adj %lu\n"
-                        "  plt call     %lu"),
+                        "  plt call     %lu\n"
+                        "  plt call toc %lu"),
               stub_sec_count,
               stub_sec_count == 1 ? "" : "s",
               htab->stub_count[ppc_stub_long_branch - 1],
               htab->stub_count[ppc_stub_long_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_branch - 1],
               htab->stub_count[ppc_stub_plt_branch_r2off - 1],
-              htab->stub_count[ppc_stub_plt_call - 1]);
+              htab->stub_count[ppc_stub_plt_call - 1],
+              htab->stub_count[ppc_stub_plt_call_r2save - 1]);
     }
   return TRUE;
 }
@@ -11125,9 +12148,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;
@@ -11213,8 +12233,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   bfd_vma TOCstart;
   bfd_boolean ret = TRUE;
   bfd_boolean is_opd;
-  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
-  bfd_boolean is_power4 = FALSE;
+  /* Assume 'at' branch hints.  */
+  bfd_boolean is_isa_v2 = TRUE;
   bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
 
   /* Initialize howto table if needed.  */
@@ -11242,7 +12262,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   for (; rel < relend; rel++)
     {
       enum elf_ppc64_reloc_type r_type;
-      bfd_vma addend, orig_addend;
+      bfd_vma addend;
       bfd_reloc_status_type r;
       Elf_Internal_Sym *sym;
       asection *sec;
@@ -11257,10 +12277,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       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;
+      const Elf_Internal_Rela orig_rel = *rel;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -11280,7 +12302,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       sym_name = NULL;
       unresolved_reloc = FALSE;
       warned = FALSE;
-      orig_addend = rel->r_addend;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -11320,20 +12341,48 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                   unresolved_reloc, warned);
          sym_name = h_elf->root.root.string;
          sym_type = h_elf->type;
+         if (sec != NULL
+             && sec->owner == output_bfd
+             && strcmp (sec->name, ".opd") == 0)
+           {
+             /* This is a symbol defined in a linker script.  All
+                such are defined in output sections, even those
+                defined by simple assignment from a symbol defined in
+                an input section.  Transfer the symbol to an
+                appropriate input .opd section, so that a branch to
+                this symbol will be mapped to the location specified
+                by the opd entry.  */
+             struct bfd_link_order *lo;
+             for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
+               if (lo->type == bfd_indirect_link_order)
+                 {
+                   asection *isec = lo->u.indirect.section;
+                   if (h_elf->root.u.def.value >= isec->output_offset
+                       && h_elf->root.u.def.value < (isec->output_offset
+                                                     + isec->size))
+                     {
+                       h_elf->root.u.def.value -= isec->output_offset;
+                       h_elf->root.u.def.section = isec;
+                       sec = isec;
+                       break;
+                     }
+                 }
+           }
+         if (h_elf == &htab->dot_toc_dot->elf)
+           {
+             relocation = (TOCstart
+                           + htab->stub_group[input_section->id].toc_off);
+             sec = bfd_abs_section_ptr;
+             unresolved_reloc = FALSE;
+           }
        }
       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;
-       }
+      if (sec != NULL && discarded_section (sec))
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, 1, relend,
+                                        ppc64_elf_howto_table[r_type], 0,
+                                        contents);
 
       if (info->relocatable)
        continue;
@@ -11373,7 +12422,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
@@ -11390,13 +12439,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);
        }
@@ -11419,6 +12466,16 @@ 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:
@@ -11463,6 +12520,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
@@ -11532,8 +12601,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);
@@ -11600,9 +12669,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);
@@ -11708,9 +12777,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);
@@ -11784,6 +12853,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:
@@ -11808,24 +12892,16 @@ 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, &orig_rel,
+                                          htab);
+         if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
+                 || stub_entry->stub_type == ppc_stub_plt_call_r2save
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
                  || stub_entry->stub_type == ppc_stub_long_branch_r2off))
            {
@@ -11854,7 +12930,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (!can_plt_call)
                {
-                 if (stub_entry->stub_type == ppc_stub_plt_call)
+                 if (stub_entry->stub_type == ppc_stub_plt_call
+                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
                    {
                      /* If this is a plain branch rather than a branch
                         and link, don't require a nop.  However, don't
@@ -11880,23 +12957,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);
@@ -11905,18 +12978,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              if (can_plt_call
-                 && stub_entry->stub_type == ppc_stub_plt_call)
+                 && (stub_entry->stub_type == ppc_stub_plt_call
+                     || stub_entry->stub_type == ppc_stub_plt_call_r2save))
                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. */
              bfd_vma off = (relocation + addend
                             - sec->output_section->vma
                             - sec->output_offset);
-             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
+             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE);
              if (dest != (bfd_vma) -1)
                {
                  relocation = dest;
@@ -11930,13 +13006,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, fdh, 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)
            {
@@ -11946,11 +13024,20 @@ 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
+                  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+                 && (ALWAYS_EMIT_R2SAVE
+                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+                 && 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)
            {
-             if (is_power4)
+             if (is_isa_v2)
                {
                  /* Set 'a' bit.  This is 0b00010 in BO field for branch
                     on CR(BI) insns (BO == 001at or 011at), and 0b01000
@@ -11993,8 +13080,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);
@@ -12005,6 +13092,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;
@@ -12070,7 +13158,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
@@ -12078,6 +13166,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      ;
                    else
                      {
+                       BFD_ASSERT (h->elf.dynindx != -1);
                        indx = h->elf.dynindx;
                        unresolved_reloc = FALSE;
                      }
@@ -12091,7 +13180,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  }
 
                for (; ent != NULL; ent = ent->next)
-                 if (ent->addend == orig_addend
+                 if (ent->addend == orig_rel.r_addend
                      && ent->owner == input_bfd
                      && ent->tls_type == tls_type)
                    break;
@@ -12244,7 +13333,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              struct plt_entry *ent;
              for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
-               if (ent->addend == orig_addend
+               if (ent->addend == orig_rel.r_addend
                    && ent->plt.offset != (bfd_vma) -1)
                  {
                    relocation = (htab->plt->output_section->vma
@@ -12258,7 +13347,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)
            ;
@@ -12447,10 +13536,13 @@ 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);
+               {
+                 BFD_ASSERT (h->elf.dynindx != -1);
+                 outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+               }
              else
                {
                  /* This symbol is local, or marked to become local,
@@ -12498,17 +13590,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)
                        {
@@ -12605,8 +13695,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);
 
@@ -12615,6 +13705,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)
        {
@@ -12688,9 +13844,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);
@@ -12705,13 +13861,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;
@@ -12749,16 +13905,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (!((*info->callbacks->reloc_overflow)
                    (info, (h ? &h->elf.root : NULL), sym_name,
                     ppc64_elf_howto_table[r_type]->name,
-                    orig_addend, input_bfd, input_section, rel->r_offset)))
+                    orig_rel.r_addend, input_bfd, input_section,
+                    rel->r_offset)))
                return FALSE;
            }
          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);
@@ -12825,7 +13980,7 @@ static bfd_boolean
 ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct elf_link_hash_entry *h,
-                                Elf_Internal_Sym *sym)
+                                Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
@@ -12894,10 +14049,6 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
     }
 
-  /* Mark some specially defined symbols as absolute.  */
-  if (strcmp (h->root.root.string, "_DYNAMIC") == 0)
-    sym->st_shndx = SHN_ABS;
-
   return TRUE;
 }
 
@@ -12938,7 +14089,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
     return FALSE;
 
   dynobj = htab->elf.dynobj;
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
   if (htab->elf.dynamic_sections_created)
     {
@@ -13050,7 +14201,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;
@@ -13059,11 +14210,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 == SEC_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.  */
@@ -13096,3 +14255,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"
+
This page took 0.08452 seconds and 4 git commands to generate.