2011-06-27 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 523d1374a7fa60e3691e0ed848e062750c3344b6..14fa20b2ac5477e9b126eef8313e87f1e4faf549 100644 (file)
@@ -1,9 +1,9 @@
 /* PowerPC64-specific support for 64-bit ELF.
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-   Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010, 2011 Free Software Foundation, Inc.
    Written by Linus Nordberg, Swox AB <info@swox.com>,
    based on elf32-ppc.c by Ian Lance Taylor.
-   Largely rewritten by Alan Modra <amodra@bigpond.net.au>
+   Largely rewritten by Alan Modra.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -61,6 +61,7 @@ static bfd_vma opd_entry_value
 #define TARGET_BIG_SYM         bfd_elf64_powerpc_vec
 #define TARGET_BIG_NAME                "elf64-powerpc"
 #define ELF_ARCH               bfd_arch_powerpc
+#define ELF_TARGET_ID          PPC64_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
 #define ELF_COMMONPAGESIZE     0x1000
@@ -78,12 +79,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_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_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
@@ -92,7 +94,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
 #define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
 #define elf_backend_add_symbol_hook          ppc64_elf_add_symbol_hook
-#define elf_backend_check_directives         ppc64_elf_check_directives
+#define elf_backend_check_directives         ppc64_elf_process_dot_syms
 #define elf_backend_as_needed_cleanup        ppc64_elf_as_needed_cleanup
 #define elf_backend_archive_symbol_lookup     ppc64_elf_archive_symbol_lookup
 #define elf_backend_check_relocs             ppc64_elf_check_relocs
@@ -112,6 +114,7 @@ static bfd_vma opd_entry_value
 #define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
 #define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
 #define elf_backend_special_sections         ppc64_elf_special_sections
+#define elf_backend_post_process_headers      _bfd_elf_set_osabi
 
 /* The name of the dynamic interpreter.  This is put in the .interp
    section.  */
@@ -1235,7 +1238,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xfffc,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC64_TLS,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -1250,6 +1253,34 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_TLSGD,
+        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_TLSGD",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC64_TLSLD,
+        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_TLSLD",       /* 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,
@@ -1845,6 +1876,95 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  HOWTO (R_PPC64_JMP_IREL,     /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
+        0,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_unhandled_reloc, /* special_function */
+        "R_PPC64_JMP_IREL",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC64_IRELATIVE,    /* type */
+        0,                     /* rightshift */
+        4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
+        64,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_IRELATIVE",   /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        ONES (64),             /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* A 16 bit relative relocation.  */
+  HOWTO (R_PPC64_REL16,                /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* A 16 bit relative relocation without overflow.  */
+  HOWTO (R_PPC64_REL16_LO,     /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16_LO",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* The high order 16 bits of a relative address.  */
+  HOWTO (R_PPC64_REL16_HI,     /* type */
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_PPC64_REL16_HI",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* The high order 16 bits of a relative address, plus 1 if the contents of
+     the low 16 bits, treated as a signed number, is negative.  */
+  HOWTO (R_PPC64_REL16_HA,     /* type */
+        16,                    /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        ppc64_elf_ha_reloc,    /* special_function */
+        "R_PPC64_REL16_HA",    /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_PPC64_GNU_VTINHERIT,        /* type */
         0,                     /* rightshift */
@@ -2031,6 +2151,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_TLS:                    r = R_PPC64_TLS;
       break;
+    case BFD_RELOC_PPC_TLSGD:                  r = R_PPC64_TLSGD;
+      break;
+    case BFD_RELOC_PPC_TLSLD:                  r = R_PPC64_TLSLD;
+      break;
     case BFD_RELOC_PPC_DTPMOD:                 r = R_PPC64_DTPMOD64;
       break;
     case BFD_RELOC_PPC_TPREL16:                        r = R_PPC64_TPREL16;
@@ -2109,6 +2233,14 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:    r = R_PPC64_DTPREL16_HIGHESTA;
       break;
+    case BFD_RELOC_16_PCREL:                   r = R_PPC64_REL16;
+      break;
+    case BFD_RELOC_LO16_PCREL:                 r = R_PPC64_REL16_LO;
+      break;
+    case BFD_RELOC_HI16_PCREL:                 r = R_PPC64_REL16_HI;
+      break;
+    case BFD_RELOC_HI16_S_PCREL:               r = R_PPC64_REL16_HA;
+      break;
     case BFD_RELOC_VTABLE_INHERIT:             r = R_PPC64_GNU_VTINHERIT;
       break;
     case BFD_RELOC_VTABLE_ENTRY:               r = R_PPC64_GNU_VTENTRY;
@@ -2396,6 +2528,54 @@ ppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
   return bfd_reloc_dangerous;
 }
 
+/* Track GOT entries needed for a given symbol.  We might need more
+   than one got entry per symbol.  */
+struct got_entry
+{
+  struct got_entry *next;
+
+  /* The symbol addend that we'll be placing in the GOT.  */
+  bfd_vma addend;
+
+  /* Unlike other ELF targets, we use separate GOT entries for the same
+     symbol referenced from different input files.  This is to support
+     automatic multiple TOC/GOT sections, where the TOC base can vary
+     from one input file to another.  After partitioning into TOC groups
+     we merge entries within the group.
+
+     Point to the BFD owning this GOT entry.  */
+  bfd *owner;
+
+  /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
+     TLS_TPREL or TLS_DTPREL for tls entries.  */
+  unsigned char tls_type;
+
+  /* Non-zero if got.ent points to real entry.  */
+  unsigned char is_indirect;
+
+  /* Reference count until size_dynamic_sections, GOT offset thereafter.  */
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+      struct got_entry *ent;
+    } got;
+};
+
+/* The same for PLT.  */
+struct plt_entry
+{
+  struct plt_entry *next;
+
+  bfd_vma addend;
+
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } plt;
+};
+
 struct ppc64_elf_obj_tdata
 {
   struct elf_obj_tdata elf;
@@ -2408,15 +2588,16 @@ struct ppc64_elf_obj_tdata
      on removed .opd entries to this section so that the sym is removed.  */
   asection *deleted_section;
 
-  /* TLS local dynamic got entry handling.  Suppose for multiple GOT
+  /* TLS local dynamic got entry handling.  Support for multiple GOT
      sections means we potentially need one of these for each input bfd.  */
-  union {
-    bfd_signed_vma refcount;
-    bfd_vma offset;
-  } tlsld_got;
+  struct got_entry tlsld_got;
 
   /* A copy of relocs before they are modified for --emit-relocs.  */
   Elf_Internal_Rela *opd_relocs;
+
+  /* Nonzero if this bfd has small toc/got relocs, ie. that expect
+     the reloc to be in the range -32768 to 32767.  */
+  unsigned int has_small_toc_reloc;
 };
 
 #define ppc64_elf_tdata(bfd) \
@@ -2427,7 +2608,7 @@ struct ppc64_elf_obj_tdata
 
 #define is_ppc64_elf(bfd) \
   (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
-   && elf_object_id (bfd) == PPC64_ELF_TDATA)
+   && elf_object_id (bfd) == PPC64_ELF_DATA)
 
 /* Override the generic function because we store some extras.  */
 
@@ -2435,7 +2616,7 @@ static bfd_boolean
 ppc64_elf_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct ppc64_elf_obj_tdata),
-                                 PPC64_ELF_TDATA);
+                                 PPC64_ELF_DATA);
 }
 
 /* Fix bad default arch selected for a 64 bit input bfd when the
@@ -2472,7 +2653,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;
@@ -2489,6 +2670,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
@@ -2550,7 +2733,7 @@ ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
 static bfd_boolean
 ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
-  /* Check if we have the same endianess.  */
+  /* Check if we have the same endianness.  */
   if (ibfd->xvec->byteorder != obfd->xvec->byteorder
       && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
       && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
@@ -2608,9 +2791,15 @@ struct _ppc64_elf_section_data
       long *adjust;
     } opd;
 
-    /* An array for toc sections, indexed by offset/8.
-       Specifies the relocation symbol index used at a given toc offset.  */
-    unsigned *t_symndx;
+    /* An array for toc sections, indexed by offset/8.  */
+    struct _toc_sec_data
+    {
+      /* Specifies the relocation symbol index used at a given toc offset.  */
+      unsigned *symndx;
+
+      /* And the relocation addend.  */
+      bfd_vma *add;
+    } toc;
   } u;
 
   enum _ppc64_sec_type sec_type:2;
@@ -2651,7 +2840,6 @@ get_opd_info (asection * sec)
 }
 \f
 /* Parameters for the qsort hook.  */
-static asection *synthetic_opd;
 static bfd_boolean synthetic_relocatable;
 
 /* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
@@ -2669,9 +2857,11 @@ compare_symbols (const void *ap, const void *bp)
     return 1;
 
   /* then .opd symbols.  */
-  if (a->section == synthetic_opd && b->section != synthetic_opd)
+  if (strcmp (a->section->name, ".opd") == 0
+      && strcmp (b->section->name, ".opd") != 0)
     return -1;
-  if (a->section != synthetic_opd && b->section == synthetic_opd)
+  if (strcmp (a->section->name, ".opd") != 0
+      && strcmp (b->section->name, ".opd") == 0)
     return 1;
 
   /* then other code symbols.  */
@@ -2825,7 +3015,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   else
     memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
-  synthetic_opd = opd;
   synthetic_relocatable = relocatable;
   qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
@@ -2843,7 +3032,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
     }
 
   i = 0;
-  if (syms[i]->section == opd)
+  if (strcmp (syms[i]->section->name, ".opd") == 0)
     ++i;
   codesecsym = i;
 
@@ -2860,7 +3049,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
   secsymend = i;
 
   for (; i < symcount; ++i)
-    if (syms[i]->section != opd)
+    if (strcmp (syms[i]->section->name, ".opd") != 0)
       break;
   opdsymend = i;
 
@@ -2995,6 +3184,10 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        {
          bfd_vma ent;
 
+         /* Ignore bogus symbols.  */
+         if (syms[i]->value > opd->size - 8)
+           continue;
+
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
@@ -3074,7 +3267,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
 
              p = relplt->relocation;
              for (i = 0; i < plt_count; i++, p++)
-               size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+               {
+                 size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+                 if (p->addend != 0)
+                   size += sizeof ("+0x") - 1 + 16;
+               }
            }
        }
 
@@ -3088,6 +3285,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
        {
          bfd_vma ent;
 
+         if (syms[i]->value > opd->size - 8)
+           continue;
+
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
@@ -3119,8 +3319,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;
@@ -3191,6 +3392,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              len = strlen ((*p->sym_ptr_ptr)->name);
              memcpy (names, (*p->sym_ptr_ptr)->name, len);
              names += len;
+             if (p->addend != 0)
+               {
+                 memcpy (names, "+0x", sizeof ("+0x") - 1);
+                 names += sizeof ("+0x") - 1;
+                 bfd_sprintf_vma (abfd, names, p->addend);
+                 names += strlen (names);
+               }
              memcpy (names, "@plt", sizeof ("@plt"));
              names += sizeof ("@plt");
              s++;
@@ -3279,70 +3487,6 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
    calls may use the function descriptor symbol, ie. "bl foo".  This
    behaves exactly as "bl .foo".  */
 
-/* The linker needs to keep track of the number of relocs that it
-   decides to copy as dynamic relocs in check_relocs for each symbol.
-   This is so that it can later discard them if they are found to be
-   unnecessary.  We store the information in a field extending the
-   regular ELF linker hash table.  */
-
-struct ppc_dyn_relocs
-{
-  struct ppc_dyn_relocs *next;
-
-  /* The input section of the reloc.  */
-  asection *sec;
-
-  /* Total number of relocs copied for the input section.  */
-  bfd_size_type count;
-
-  /* Number of pc-relative relocs copied for the input section.  */
-  bfd_size_type pc_count;
-};
-
-/* Track GOT entries needed for a given symbol.  We might need more
-   than one got entry per symbol.  */
-struct got_entry
-{
-  struct got_entry *next;
-
-  /* The symbol addend that we'll be placing in the GOT.  */
-  bfd_vma addend;
-
-  /* Unlike other ELF targets, we use separate GOT entries for the same
-     symbol referenced from different input files.  This is to support
-     automatic multiple TOC/GOT sections, where the TOC base can vary
-     from one input file to another.  FIXME: After group_sections we
-     ought to merge entries within the group.
-
-     Point to the BFD owning this GOT entry.  */
-  bfd *owner;
-
-  /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD,
-     TLS_TPREL or TLS_DTPREL for tls entries.  */
-  char tls_type;
-
-  /* Reference count until size_dynamic_sections, GOT offset thereafter.  */
-  union
-    {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } got;
-};
-
-/* The same for PLT.  */
-struct plt_entry
-{
-  struct plt_entry *next;
-
-  bfd_vma addend;
-
-  union
-    {
-      bfd_signed_vma refcount;
-      bfd_vma offset;
-    } plt;
-};
-
 /* Of those relocs that might be copied as dynamic relocs, this function
    selects those that must be copied when linking a shared library,
    even when the symbol is local.  */
@@ -3473,6 +3617,7 @@ struct ppc_stub_hash_entry {
 
   /* The symbol table entry, if any, that this was derived from.  */
   struct ppc_link_hash_entry *h;
+  struct plt_entry *plt_ent;
 
   /* And the reloc addend that this was derived from.  */
   bfd_vma addend;
@@ -3508,7 +3653,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;
@@ -3541,7 +3686,8 @@ struct ppc_link_hash_entry
 #define TLS_TLS                16      /* Any TLS reloc.  */
 #define TLS_EXPLICIT   32      /* Marks TOC section TLS relocs. */
 #define TLS_TPRELGD    64      /* TPREL reloc resulting from GD->IE. */
-  char tls_mask;
+#define PLT_IFUNC      128     /* STT_GNU_IFUNC.  */
+  unsigned char tls_mask;
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -3576,6 +3722,8 @@ struct ppc_link_hash_table
 
   /* Temp used when calculating TOC pointers.  */
   bfd_vma toc_curr;
+  bfd *toc_bfd;
+  asection *toc_first_sec;
 
   /* Highest input section id.  */
   int top_id;
@@ -3593,6 +3741,8 @@ struct ppc_link_hash_table
   asection *got;
   asection *plt;
   asection *relplt;
+  asection *iplt;
+  asection *reliplt;
   asection *dynbss;
   asection *relbss;
   asection *glink;
@@ -3604,6 +3754,9 @@ struct ppc_link_hash_table
   struct ppc_link_hash_entry *tls_get_addr;
   struct ppc_link_hash_entry *tls_get_addr_fd;
 
+  /* The size of reliplt used by got entry relocs.  */
+  bfd_size_type got_reli_size;
+
   /* Statistics.  */
   unsigned long stub_count[ppc_stub_plt_call];
 
@@ -3613,33 +3766,53 @@ struct ppc_link_hash_table
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
+  /* Set if __tls_get_addr optimization should not be done.  */
+  unsigned int no_tls_get_addr_opt:1;
+
   /* Support for multiple toc sections.  */
-  unsigned int no_multi_toc:1;
+  unsigned int do_multi_toc:1;
   unsigned int multi_toc_needed:1;
+  unsigned int second_toc_pass:1;
+  unsigned int do_toc_opt:1;
 
   /* Set on error.  */
   unsigned int stub_error:1;
 
-  /* Temp used by ppc64_elf_check_directives.  */
+  /* Temp used by ppc64_elf_process_dot_syms.  */
   unsigned int twiddled_syms:1;
 
   /* Incremented every time we size stubs.  */
   unsigned int stub_iteration;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 };
 
 /* Rename some of the generic section flags to better document how they
    are used here.  */
-#define has_toc_reloc has_gp_reloc
-#define makes_toc_func_call need_finalize_relax
-#define call_check_in_progress reloc_done
+
+/* Nonzero if this section has TLS related relocations.  */
+#define has_tls_reloc sec_flg0
+
+/* Nonzero if this section has a call to __tls_get_addr.  */
+#define has_tls_get_addr_call sec_flg1
+
+/* Nonzero if this section has any toc or got relocs.  */
+#define has_toc_reloc sec_flg2
+
+/* Nonzero if this section has a call to another section that uses
+   the toc or got.  */
+#define makes_toc_func_call sec_flg3
+
+/* Recursion protection when determining above flag.  */
+#define call_check_in_progress sec_flg4
+#define call_check_done sec_flg5
 
 /* Get the ppc64 ELF linker hash table from a link_info structure.  */
 
 #define ppc_hash_table(p) \
-  ((struct ppc_link_hash_table *) ((p)->hash))
+  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+  == PPC64_ELF_DATA ? ((struct ppc_link_hash_table *) ((p)->hash)) : NULL)
 
 #define ppc_stub_hash_lookup(table, string, create, copy) \
   ((struct ppc_stub_hash_entry *) \
@@ -3784,7 +3957,8 @@ ppc64_elf_link_hash_table_create (bfd *abfd)
     return NULL;
 
   if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc,
-                                     sizeof (struct ppc_link_hash_entry)))
+                                     sizeof (struct ppc_link_hash_entry),
+                                     PPC64_ELF_DATA))
     {
       free (htab);
       return NULL;
@@ -3841,6 +4015,8 @@ ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
    linker created stub bfd.  This ensures that the GOT header is at
    the start of the output TOC section.  */
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return;
   htab->stub_bfd = abfd;
   htab->elf.dynobj = abfd;
 }
@@ -3942,8 +4118,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;
@@ -3980,8 +4157,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 (_("%B: cannot create stub entry %s\n"),
+                             section->owner, stub_name);
       return NULL;
     }
 
@@ -4000,6 +4177,8 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   flagword flags;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Create .sfpr for code to save and restore fp regs.  */
   flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
@@ -4017,6 +4196,21 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
     return FALSE;
 
+  flags = SEC_ALLOC | SEC_LINKER_CREATED;
+  htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
+  if (htab->iplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
+    return FALSE;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
+                                                     ".rela.iplt",
+                                                     flags);
+  if (htab->reliplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
+    return FALSE;
+
   /* Create branch lookup table for plt_branch stubs.  */
   flags = (SEC_ALLOC | SEC_LOAD
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@@ -4034,7 +4228,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
   htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
                                                      ".rela.branch_lt",
                                                      flags);
-  if (!htab->relbrlt
+  if (htab->relbrlt == NULL
       || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
     return FALSE;
 
@@ -4053,6 +4247,8 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
 
   if (!is_ppc64_elf (abfd))
     return FALSE;
+  if (htab == NULL)
+    return FALSE;
 
   if (!htab->got)
     {
@@ -4094,6 +4290,9 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   if (!htab->got)
     htab->got = bfd_get_section_by_name (dynobj, ".got");
   htab->plt = bfd_get_section_by_name (dynobj, ".plt");
@@ -4109,6 +4308,29 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Follow indirect and warning symbol links.  */
+
+static inline struct bfd_link_hash_entry *
+follow_link (struct bfd_link_hash_entry *h)
+{
+  while (h->type == bfd_link_hash_indirect
+        || h->type == bfd_link_hash_warning)
+    h = h->u.i.link;
+  return h;
+}
+
+static inline struct elf_link_hash_entry *
+elf_follow_link (struct elf_link_hash_entry *h)
+{
+  return (struct elf_link_hash_entry *) follow_link (&h->root);
+}
+
+static inline struct ppc_link_hash_entry *
+ppc_follow_link (struct ppc_link_hash_entry *h)
+{
+  return (struct ppc_link_hash_entry *) follow_link (&h->elf.root);
+}
+
 /* Merge PLT info on FROM with that on TO.  */
 
 static void
@@ -4161,14 +4383,14 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
     {
       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)
@@ -4191,6 +4413,8 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
   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.
@@ -4260,7 +4484,7 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
    hash entry FH.  Link the entries via their OH fields.  */
 
 static struct ppc_link_hash_entry *
-get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
+lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
 {
   struct ppc_link_hash_entry *fdh = fh->oh;
 
@@ -4270,16 +4494,16 @@ get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
 
       fdh = (struct ppc_link_hash_entry *)
        elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
-      if (fdh != NULL)
-       {
-         fdh->is_func_descriptor = 1;
-         fdh->oh = fh;
-         fh->is_func = 1;
-         fh->oh = fdh;
-       }
+      if (fdh == NULL)
+       return fdh;
+
+      fdh->is_func_descriptor = 1;
+      fdh->oh = fh;
+      fh->is_func = 1;
+      fh->oh = fdh;
     }
 
-  return fdh;
+  return ppc_follow_link (fdh);
 }
 
 /* Make a fake function descriptor sym for the code sym FH.  */
@@ -4321,16 +4545,27 @@ make_fdh (struct bfd_link_info *info,
    function type.  */
 
 static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
-                          struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
+                          struct bfd_link_info *info,
                           Elf_Internal_Sym *isym,
                           const char **name ATTRIBUTE_UNUSED,
                           flagword *flags ATTRIBUTE_UNUSED,
                           asection **sec,
                           bfd_vma *value ATTRIBUTE_UNUSED)
 {
-  if (*sec != NULL
-      && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
+  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_gnu_symbols = TRUE;
+    }
+  else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
+    ;
+  else if (*sec != NULL
+          && strcmp ((*sec)->name, ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
   return TRUE;
@@ -4397,23 +4632,27 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
     abort ();
 
   htab = ppc_hash_table (info);
-  fdh = get_fdh (eh, htab);
-  if (fdh == NULL
-      && !info->relocatable
-      && (eh->elf.root.type == bfd_link_hash_undefined
-         || eh->elf.root.type == bfd_link_hash_undefweak)
-      && eh->elf.ref_regular)
-    {
-      /* Make an undefweak function descriptor sym, which is enough to
-        pull in an --as-needed shared lib, but won't cause link
-        errors.  Archives are handled elsewhere.  */
-      fdh = make_fdh (info, eh);
-      if (fdh == NULL)
-       return FALSE;
-      else
-       fdh->elf.ref_regular = 1;
+  if (htab == NULL)
+    return FALSE;
+
+  fdh = lookup_fdh (eh, htab);
+  if (fdh == NULL)
+    {
+      if (!info->relocatable
+         && (eh->elf.root.type == bfd_link_hash_undefined
+             || eh->elf.root.type == bfd_link_hash_undefweak)
+         && eh->elf.ref_regular)
+       {
+         /* Make an undefweak function descriptor sym, which is enough to
+            pull in an --as-needed shared lib, but won't cause link
+            errors.  Archives are handled elsewhere.  */
+         fdh = make_fdh (info, eh);
+         if (fdh == NULL)
+           return FALSE;
+         fdh->elf.ref_regular = 1;
+       }
     }
-  else if (fdh != NULL)
+  else
     {
       unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
       unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
@@ -4438,14 +4677,16 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
 /* Process list of dot-symbols we made in link_hash_newfunc.  */
 
 static bfd_boolean
-ppc64_elf_check_directives (bfd *ibfd, struct bfd_link_info *info)
+ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
   struct ppc_link_hash_entry **p, *eh;
 
-  htab = ppc_hash_table (info);
   if (!is_ppc64_elf (info->output_bfd))
     return TRUE;
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (is_ppc64_elf (ibfd))
     {
@@ -4484,29 +4725,56 @@ static bfd_boolean
 ppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED,
                             struct bfd_link_info *info)
 {
-  ppc_hash_table (info)->dot_syms = NULL;
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  if (htab == NULL)
+    return FALSE;
+
+  htab->dot_syms = NULL;
   return TRUE;
 }
 
-static bfd_boolean
+/* If --just-symbols against a final linked binary, then assume we need
+   toc adjusting stubs when calling functions defined there.  */
+
+static void
+ppc64_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
+{
+  if ((sec->flags & SEC_CODE) != 0
+      && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0
+      && is_ppc64_elf (sec->owner))
+    {
+      asection *got = bfd_get_section_by_name (sec->owner, ".got");
+      if (got != NULL
+         && got->size >= elf_backend_got_header_size
+         && bfd_get_section_by_name (sec->owner, ".opd") != NULL)
+       sec->has_toc_reloc = 1;
+    }
+  _bfd_elf_link_just_syms (sec, info);
+}
+
+static struct plt_entry **
 update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
                       unsigned long r_symndx, bfd_vma r_addend, int tls_type)
 {
   struct got_entry **local_got_ents = elf_local_got_ents (abfd);
-  char *local_got_tls_masks;
+  struct plt_entry **local_plt;
+  unsigned char *local_got_tls_masks;
 
   if (local_got_ents == NULL)
     {
       bfd_size_type size = symtab_hdr->sh_info;
 
-      size *= sizeof (*local_got_ents) + sizeof (*local_got_tls_masks);
+      size *= (sizeof (*local_got_ents)
+              + sizeof (*local_plt)
+              + sizeof (*local_got_tls_masks));
       local_got_ents = bfd_zalloc (abfd, size);
       if (local_got_ents == NULL)
-       return FALSE;
+       return NULL;
       elf_local_got_ents (abfd) = local_got_ents;
     }
 
-  if ((tls_type & TLS_EXPLICIT) == 0)
+  if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0)
     {
       struct got_entry *ent;
 
@@ -4525,23 +4793,26 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
          ent->addend = r_addend;
          ent->owner = abfd;
          ent->tls_type = tls_type;
+         ent->is_indirect = FALSE;
          ent->got.refcount = 0;
          local_got_ents[r_symndx] = ent;
        }
       ent->got.refcount += 1;
     }
 
-  local_got_tls_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+  local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
+  local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
   local_got_tls_masks[r_symndx] |= tls_type;
-  return TRUE;
+
+  return local_plt + r_symndx;
 }
 
 static bfd_boolean
-update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
+update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend)
 {
   struct plt_entry *ent;
 
-  for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next)
+  for (ent = *plist; ent != NULL; ent = ent->next)
     if (ent->addend == addend)
       break;
   if (ent == NULL)
@@ -4550,19 +4821,28 @@ update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
       ent = bfd_alloc (abfd, amt);
       if (ent == NULL)
        return FALSE;
-      ent->next = eh->elf.plt.plist;
+      ent->next = *plist;
       ent->addend = addend;
       ent->plt.refcount = 0;
-      eh->elf.plt.plist = ent;
+      *plist = ent;
     }
   ent->plt.refcount += 1;
-  eh->elf.needs_plt = 1;
-  if (eh->elf.root.root.string[0] == '.'
-      && eh->elf.root.root.string[1] != '\0')
-    eh->is_func = 1;
   return TRUE;
 }
 
+static bfd_boolean
+is_branch_reloc (enum elf_ppc64_reloc_type r_type)
+{
+  return (r_type == R_PPC64_REL24
+         || r_type == R_PPC64_REL14
+         || r_type == R_PPC64_REL14_BRTAKEN
+         || r_type == R_PPC64_REL14_BRNTAKEN
+         || r_type == R_PPC64_ADDR24
+         || r_type == R_PPC64_ADDR14
+         || r_type == R_PPC64_ADDR14_BRTAKEN
+         || r_type == R_PPC64_ADDR14_BRNTAKEN);
+}
+
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure
    linkage table, and dynamic reloc sections.  */
@@ -4573,11 +4853,12 @@ 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;
   asection **opd_sym_map;
+  struct elf_link_hash_entry *tga, *dottga;
 
   if (info->relocatable)
     return TRUE;
@@ -4594,16 +4875,18 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
   BFD_ASSERT (is_ppc64_elf (abfd));
 
   htab = ppc_hash_table (info);
-  symtab_hdr = &elf_symtab_hdr (abfd);
+  if (htab == NULL)
+    return FALSE;
 
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                             FALSE, FALSE, TRUE);
+  dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+                                FALSE, FALSE, TRUE);
+  symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = (sym_hashes
-                   + symtab_hdr->sh_size / sizeof (Elf64_External_Sym)
-                   - symtab_hdr->sh_info);
-
   sreloc = NULL;
   opd_sym_map = NULL;
-  if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
+  if (strcmp (sec->name, ".opd") == 0)
     {
       /* Garbage collection needs some extra help with .opd sections.
         We don't want to necessarily keep everything referenced by
@@ -4633,8 +4916,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       enum elf_ppc64_reloc_type r_type;
-      int tls_type = 0;
+      int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
+      struct plt_entry **ifunc;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -4642,14 +4926,64 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         h = elf_follow_link (h);
+       }
+
+      tls_type = 0;
+      ifunc = NULL;
+      if (h != NULL)
+       {
+         if (h->type == STT_GNU_IFUNC)
+           {
+             h->needs_plt = 1;
+             ifunc = &h->plt.plist;
+           }
        }
+      else
+       {
+         Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                                         abfd, r_symndx);
+         if (isym == NULL)
+           return FALSE;
 
+         if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+           {
+             ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                            rel->r_addend, PLT_IFUNC);
+             if (ifunc == NULL)
+               return FALSE;
+           }
+       }
       r_type = ELF64_R_TYPE (rel->r_info);
+      if (is_branch_reloc (r_type))
+       {
+         if (h != NULL && (h == tga || h == dottga))
+           {
+             if (rel != relocs
+                 && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+                     || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+               /* We have a new-style __tls_get_addr call with a marker
+                  reloc.  */
+               ;
+             else
+               /* Mark this section as having an old-style call.  */
+               sec->has_tls_get_addr_call = 1;
+           }
+
+         /* STT_GNU_IFUNC symbols must have a PLT entry.  */
+         if (ifunc != NULL
+             && !update_plt_info (abfd, ifunc, rel->r_addend))
+           return FALSE;
+       }
+
       switch (r_type)
        {
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
+         /* These special tls relocs tie a call to __tls_get_addr with
+            its parameter symbol.  */
+         break;
+
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
@@ -4690,6 +5024,17 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_GOT16_LO_DS:
          /* This symbol requires a global offset table entry.  */
          sec->has_toc_reloc = 1;
+         if (r_type == R_PPC64_GOT_TLSLD16
+             || r_type == R_PPC64_GOT_TLSGD16
+             || r_type == R_PPC64_GOT_TPREL16_DS
+             || r_type == R_PPC64_GOT_DTPREL16_DS
+             || r_type == R_PPC64_GOT16
+             || r_type == R_PPC64_GOT16_DS)
+           {
+             htab->do_multi_toc = 1;
+             ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
+           }
+
          if (ppc64_elf_tdata (abfd)->got == NULL
              && !create_got_section (abfd, info))
            return FALSE;
@@ -4715,6 +5060,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  ent->addend = rel->r_addend;
                  ent->owner = abfd;
                  ent->tls_type = tls_type;
+                 ent->is_indirect = FALSE;
                  ent->got.refcount = 0;
                  eh->elf.got.glist = ent;
                }
@@ -4746,9 +5092,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              return FALSE;
            }
          else
-           if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
-                                 rel->r_addend))
-             return FALSE;
+           {
+             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
+               return FALSE;
+             h->needs_plt = 1;
+             if (h->root.root.string[0] == '.'
+                 && h->root.root.string[1] != '\0')
+               ((struct ppc_link_hash_entry *) h)->is_func = 1;
+           }
          break;
 
          /* The following relocations don't need to propagate the
@@ -4773,11 +5124,19 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          break;
 
          /* Nor do these.  */
+       case R_PPC64_REL16:
+       case R_PPC64_REL16_LO:
+       case R_PPC64_REL16_HI:
+       case R_PPC64_REL16_HA:
+         break;
+
        case R_PPC64_TOC16:
+       case R_PPC64_TOC16_DS:
+         htab->do_multi_toc = 1;
+         ppc64_elf_tdata (abfd)->has_small_toc_reloc = 1;
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_HI:
        case R_PPC64_TOC16_HA:
-       case R_PPC64_TOC16_DS:
        case R_PPC64_TOC16_LO_DS:
          sec->has_toc_reloc = 1;
          break;
@@ -4814,40 +5173,35 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  dest = h->root.u.def.section;
              }
            else
-             dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                               sec, r_symndx);
+             {
+               Elf_Internal_Sym *isym;
+
+               isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                             abfd, r_symndx);
+               if (isym == NULL)
+                 return FALSE;
+
+               dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
+             }
+
            if (dest != sec)
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
          }
          /* Fall through.  */
 
        case R_PPC64_REL24:
-         if (h != NULL)
+         if (h != NULL && ifunc == NULL)
            {
              /* We may need a .plt entry if the function this reloc
                 refers to is in a shared lib.  */
-             if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
-                                   rel->r_addend))
+             if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                return FALSE;
-             if (h == &htab->tls_get_addr->elf
-                 || h == &htab->tls_get_addr_fd->elf)
+             h->needs_plt = 1;
+             if (h->root.root.string[0] == '.'
+                 && h->root.root.string[1] != '\0')
+               ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             if (h == tga || h == dottga)
                sec->has_tls_reloc = 1;
-             else if (htab->tls_get_addr == NULL
-                      && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr")
-                      && (h->root.root.string[15] == 0
-                          || h->root.root.string[15] == '@'))
-               {
-                 htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
-                 sec->has_tls_reloc = 1;
-               }
-             else if (htab->tls_get_addr_fd == NULL
-                      && CONST_STRNEQ (h->root.root.string, "__tls_get_addr")
-                      && (h->root.root.string[14] == 0
-                          || h->root.root.string[14] == '@'))
-               {
-                 htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
-                 sec->has_tls_reloc = 1;
-               }
            }
          break;
 
@@ -4891,23 +5245,30 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          ppc64_sec = ppc64_elf_section_data (sec);
          if (ppc64_sec->sec_type != sec_toc)
            {
+             bfd_size_type amt;
+
              /* One extra to simplify get_tls_mask.  */
-             bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1;
-             ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt);
-             if (ppc64_sec->u.t_symndx == NULL)
+             amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
+             ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
+             if (ppc64_sec->u.toc.symndx == NULL)
+               return FALSE;
+             amt = sec->size * sizeof (bfd_vma) / 8;
+             ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
+             if (ppc64_sec->u.toc.add == NULL)
                return FALSE;
              BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
              ppc64_sec->sec_type = sec_toc;
            }
          BFD_ASSERT (rel->r_offset % 8 == 0);
-         ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx;
+         ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
+         ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
 
          /* Mark the second slot of a GD or LD entry.
             -1 to indicate GD and -2 to indicate LD.  */
          if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
-           ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1;
+           ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1;
          else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
-           ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2;
+           ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
          goto dodyn;
 
        case R_PPC64_TPREL16:
@@ -4937,7 +5298,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                {
                  if (h->root.root.string[0] == '.'
                      && h->root.root.string[1] != 0
-                     && get_fdh ((struct ppc_link_hash_entry *) h, htab))
+                     && lookup_fdh ((struct ppc_link_hash_entry *) h, htab))
                    ;
                  else
                    ((struct ppc_link_hash_entry *) h)->is_func = 1;
@@ -4945,12 +5306,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              else
                {
                  asection *s;
+                 Elf_Internal_Sym *isym;
 
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
-                                                r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
-                 else if (s != sec)
+
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s != NULL && s != sec)
                    opd_sym_map[rel->r_offset / 8] = s;
                }
            }
@@ -5018,53 +5382,23 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  && !info->shared
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
-                     || !h->def_regular)))
+                     || !h->def_regular))
+             || (!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
                 this reloc.  */
              if (sreloc == NULL)
                {
-                 const char *name;
-                 bfd *dynobj;
-
-                 name = (bfd_elf_string_from_elf_section
-                         (abfd,
-                          elf_elfheader (abfd)->e_shstrndx,
-                          elf_section_data (sec)->rel_hdr.sh_name));
-                 if (name == NULL)
-                   return FALSE;
-
-                 if (! CONST_STRNEQ (name, ".rela")
-                     || strcmp (bfd_get_section_name (abfd, sec),
-                                name + 5) != 0)
-                   {
-                     (*_bfd_error_handler)
-                       (_("%B: bad relocation section name `%s\'"),
-                        abfd, name);
-                     bfd_set_error (bfd_error_bad_value);
-                   }
+                 sreloc = _bfd_elf_make_dynamic_reloc_section
+                   (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
 
-                 dynobj = htab->elf.dynobj;
-                 sreloc = bfd_get_section_by_name (dynobj, name);
                  if (sreloc == NULL)
-                   {
-                     flagword flags;
-
-                     flags = (SEC_HAS_CONTENTS | SEC_READONLY
-                              | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                              | SEC_ALLOC | SEC_LOAD);
-                     sreloc = bfd_make_section_with_flags (dynobj,
-                                                           name,
-                                                           flags);
-                     if (sreloc == NULL
-                         || ! bfd_set_section_alignment (dynobj, sreloc, 3))
-                       return FALSE;
-                   }
-                 elf_section_data (sec)->sreloc = sreloc;
+                   return FALSE;
                }
 
              /* If this is a global symbol, we count the number of
@@ -5078,17 +5412,21 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     easily.  Oh well.  */
-
                  asection *s;
                  void *vpp;
+                 Elf_Internal_Sym *isym;
 
-                 s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
-                                                sec, r_symndx);
-                 if (s == NULL)
+                 isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+                                               abfd, r_symndx);
+                 if (isym == NULL)
                    return FALSE;
 
+                 s = bfd_section_from_elf_index (abfd, isym->st_shndx);
+                 if (s == NULL)
+                   s = sec;
+
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct ppc_dyn_relocs **) vpp;
+                 head = (struct elf_dyn_relocs **) vpp;
                }
 
              p = *head;
@@ -5135,11 +5473,12 @@ opd_entry_value (asection *opd_sec,
   /* No relocs implies we are linking a --just-symbols object.  */
   if (opd_sec->reloc_count == 0)
     {
-      bfd_vma val;
+      char buf[8];
 
-      if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 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;
@@ -5213,9 +5552,7 @@ opd_entry_value (asection *opd_sec,
 
                  sym_hashes = elf_sym_hashes (opd_bfd);
                  rh = sym_hashes[symndx - symtab_hdr->sh_info];
-                 while (rh->root.type == bfd_link_hash_indirect
-                        || rh->root.type == bfd_link_hash_warning)
-                   rh = ((struct elf_link_hash_entry *) rh->root.u.i.link);
+                 rh = elf_follow_link (rh);
                  BFD_ASSERT (rh->root.type == bfd_link_hash_defined
                              || rh->root.type == bfd_link_hash_defweak);
                  val = rh->root.u.def.value;
@@ -5236,6 +5573,50 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
+/* Return true if symbol is defined in a regular object file.  */
+
+static bfd_boolean
+is_static_defined (struct elf_link_hash_entry *h)
+{
+  return ((h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section != NULL
+         && h->root.u.def.section->output_section != NULL);
+}
+
+/* If FDH is a function descriptor symbol, return the associated code
+   entry symbol if it is defined.  Return NULL otherwise.  */
+
+static struct ppc_link_hash_entry *
+defined_code_entry (struct ppc_link_hash_entry *fdh)
+{
+  if (fdh->is_func_descriptor)
+    {
+      struct ppc_link_hash_entry *fh = ppc_follow_link (fdh->oh);
+      if (fh->elf.root.type == bfd_link_hash_defined
+         || fh->elf.root.type == bfd_link_hash_defweak)
+       return fh;
+    }
+  return NULL;
+}
+
+/* If FH is a function code entry symbol, return the associated
+   function descriptor symbol if it is defined.  Return NULL otherwise.  */
+
+static struct ppc_link_hash_entry *
+defined_func_desc (struct ppc_link_hash_entry *fh)
+{
+  if (fh->oh != NULL
+      && fh->oh->is_func_descriptor)
+    {
+      struct ppc_link_hash_entry *fdh = ppc_follow_link (fh->oh);
+      if (fdh->elf.root.type == bfd_link_hash_defined
+         || fdh->elf.root.type == bfd_link_hash_defweak)
+       return fdh;
+    }
+  return NULL;
+}
+
 /* Mark all our entry sym sections, both opd and code section.  */
 
 static void
@@ -5244,24 +5625,26 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
   struct bfd_sym_chain *sym;
 
+  if (htab == NULL)
+    return;
+
   for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
     {
-      struct ppc_link_hash_entry *eh;
+      struct ppc_link_hash_entry *eh, *fh;
       asection *sec;
 
       eh = (struct ppc_link_hash_entry *)
-       elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
+       elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE);
       if (eh == NULL)
        continue;
       if (eh->elf.root.type != bfd_link_hash_defined
          && eh->elf.root.type != bfd_link_hash_defweak)
        continue;
 
-      if (eh->is_func_descriptor
-         && (eh->oh->elf.root.type == bfd_link_hash_defined
-             || eh->oh->elf.root.type == bfd_link_hash_defweak))
+      fh = defined_code_entry (eh);
+      if (fh != NULL)
        {
-         sec = eh->oh->elf.root.u.def.section;
+         sec = fh->elf.root.u.def.section;
          sec->flags |= SEC_KEEP;
        }
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
@@ -5284,16 +5667,12 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info = (struct bfd_link_info *) inf;
   struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
-
-  if (eh->elf.root.type == bfd_link_hash_warning)
-    eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
+  struct ppc_link_hash_entry *fdh;
 
   /* Dynamic linking info is on the func descriptor sym.  */
-  if (eh->oh != NULL
-      && eh->oh->is_func_descriptor
-      && (eh->oh->elf.root.type == bfd_link_hash_defined
-         || eh->oh->elf.root.type == bfd_link_hash_defweak))
-    eh = eh->oh;
+  fdh = defined_func_desc (eh);
+  if (fdh != NULL)
+    eh = fdh;
 
   if ((eh->elf.root.type == bfd_link_hash_defined
        || eh->elf.root.type == bfd_link_hash_defweak)
@@ -5304,15 +5683,18 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN)))
     {
       asection *code_sec;
+      struct ppc_link_hash_entry *fh;
 
       eh->elf.root.u.def.section->flags |= SEC_KEEP;
 
       /* Function descriptor syms cause the associated
         function code sym section to be marked.  */
-      if (eh->is_func_descriptor
-         && (eh->oh->elf.root.type == bfd_link_hash_defined
-             || eh->oh->elf.root.type == bfd_link_hash_defweak))
-       eh->oh->elf.root.u.def.section->flags |= SEC_KEEP;
+      fh = defined_code_entry (eh);
+      if (fh != NULL)
+       {
+         code_sec = fh->elf.root.u.def.section;
+         code_sec->flags |= SEC_KEEP;
+       }
       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,
@@ -5328,7 +5710,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
 
 static asection *
 ppc64_elf_gc_mark_hook (asection *sec,
-                       struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                       struct bfd_link_info *info,
                        Elf_Internal_Rela *rel,
                        struct elf_link_hash_entry *h,
                        Elf_Internal_Sym *sym)
@@ -5344,7 +5726,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
   if (h != NULL)
     {
       enum elf_ppc64_reloc_type r_type;
-      struct ppc_link_hash_entry *eh;
+      struct ppc_link_hash_entry *eh, *fh, *fdh;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       switch (r_type)
@@ -5359,22 +5741,19 @@ ppc64_elf_gc_mark_hook (asection *sec,
            case bfd_link_hash_defined:
            case bfd_link_hash_defweak:
              eh = (struct ppc_link_hash_entry *) h;
-             if (eh->oh != NULL
-                 && eh->oh->is_func_descriptor
-                 && (eh->oh->elf.root.type == bfd_link_hash_defined
-                     || eh->oh->elf.root.type == bfd_link_hash_defweak))
-               eh = eh->oh;
+             fdh = defined_func_desc (eh);
+             if (fdh != NULL)
+               eh = fdh;
 
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
-             if (eh->is_func_descriptor
-                 && (eh->oh->elf.root.type == bfd_link_hash_defined
-                     || eh->oh->elf.root.type == bfd_link_hash_defweak))
+             fh = defined_code_entry (eh);
+             if (fh != NULL)
                {
                  /* They also mark their opd section.  */
                  eh->elf.root.u.def.section->gc_mark = 1;
 
-                 rsec = eh->oh->elf.root.u.def.section;
+                 rsec = fh->elf.root.u.def.section;
                }
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                       && opd_entry_value (eh->elf.root.u.def.section,
@@ -5390,7 +5769,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
              break;
 
            default:
-             break;
+             return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
            }
        }
     }
@@ -5433,6 +5812,9 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
   elf_section_data (sec)->local_dynrel = NULL;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   local_got_ents = elf_local_got_ents (abfd);
@@ -5443,20 +5825,18 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
       unsigned long r_symndx;
       enum elf_ppc64_reloc_type r_type;
       struct elf_link_hash_entry *h = NULL;
-      char tls_type = 0;
+      unsigned char tls_type = 0;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
       r_type = ELF64_R_TYPE (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
        {
          struct ppc_link_hash_entry *eh;
-         struct ppc_dyn_relocs **pp;
-         struct ppc_dyn_relocs *p;
+         struct elf_dyn_relocs **pp;
+         struct elf_dyn_relocs *p;
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-         while (h->root.type == bfd_link_hash_indirect
-                || h->root.type == bfd_link_hash_warning)
-           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         h = elf_follow_link (h);
          eh = (struct ppc_link_hash_entry *) h;
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
@@ -5468,6 +5848,38 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
              }
        }
 
+      if (is_branch_reloc (r_type))
+       {
+         struct plt_entry **ifunc = NULL;
+         if (h != NULL)
+           {
+             if (h->type == STT_GNU_IFUNC)
+               ifunc = &h->plt.plist;
+           }
+         else if (local_got_ents != NULL)
+           {
+             struct plt_entry **local_plt = (struct plt_entry **)
+               (local_got_ents + symtab_hdr->sh_info);
+             unsigned char *local_got_tls_masks = (unsigned char *)
+               (local_plt + symtab_hdr->sh_info);
+             if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
+               ifunc = local_plt + r_symndx;
+           }
+         if (ifunc != NULL)
+           {
+             struct plt_entry *ent;
+
+             for (ent = *ifunc; ent != NULL; ent = ent->next)
+               if (ent->addend == rel->r_addend)
+                 break;
+             if (ent == NULL)
+               abort ();
+             if (ent->plt.refcount > 0)
+               ent->plt.refcount -= 1;
+             continue;
+           }
+       }
+
       switch (r_type)
        {
        case R_PPC64_GOT_TLSLD16:
@@ -5541,9 +5953,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
              for (ent = h->plt.plist; ent != NULL; ent = ent->next)
                if (ent->addend == rel->r_addend)
                  break;
-             if (ent == NULL)
-               abort ();
-             if (ent->plt.refcount > 0)
+             if (ent != NULL && ent->plt.refcount > 0)
                ent->plt.refcount -= 1;
            }
          break;
@@ -5568,7 +5978,7 @@ struct sfpr_def_parms
 
 /* Auto-generate _save*, _rest* functions in .sfpr.  */
 
-static unsigned int
+static bfd_boolean
 sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
@@ -5577,6 +5987,9 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
   bfd_boolean writing = FALSE;
   char sym[16];
 
+  if (htab == NULL)
+    return FALSE;
+
   memcpy (sym, parm->name, len);
   sym[len + 2] = 0;
 
@@ -5798,11 +6211,10 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   if (fh->elf.root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (fh->elf.root.type == bfd_link_hash_warning)
-    fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link;
-
   info = inf;
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Resolve undefined references to dot-symbols as the value
      in the function descriptor, if we have one in a regular object.
@@ -5810,18 +6222,17 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
      in dynamic objects are handled elsewhere.  */
   if (fh->elf.root.type == bfd_link_hash_undefweak
       && fh->was_undefined
-      && (fh->oh->elf.root.type == bfd_link_hash_defined
-         || fh->oh->elf.root.type == bfd_link_hash_defweak)
-      && get_opd_info (fh->oh->elf.root.u.def.section) != NULL
-      && opd_entry_value (fh->oh->elf.root.u.def.section,
-                         fh->oh->elf.root.u.def.value,
+      && (fdh = defined_func_desc (fh)) != NULL
+      && get_opd_info (fdh->elf.root.u.def.section) != NULL
+      && 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.type = fh->oh->elf.root.type;
+      fh->elf.root.type = fdh->elf.root.type;
       fh->elf.forced_local = 1;
-      fh->elf.def_regular = fh->oh->elf.def_regular;
-      fh->elf.def_dynamic = fh->oh->elf.def_dynamic;
+      fh->elf.def_regular = fdh->elf.def_regular;
+      fh->elf.def_dynamic = fdh->elf.def_dynamic;
     }
 
   /* If this is a function code symbol, transfer dynamic linking
@@ -5840,14 +6251,9 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
   /* Find the corresponding function descriptor symbol.  Create it
      as undefined if necessary.  */
 
-  fdh = get_fdh (fh, htab);
-  if (fdh != NULL)
-    while (fdh->elf.root.type == bfd_link_hash_indirect
-          || fdh->elf.root.type == bfd_link_hash_warning)
-      fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
-
+  fdh = lookup_fdh (fh, htab);
   if (fdh == NULL
-      && info->shared
+      && !info->executable
       && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
     {
@@ -5880,7 +6286,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
 
   if (fdh != NULL
       && !fdh->elf.forced_local
-      && (info->shared
+      && (!info->executable
          || fdh->elf.def_dynamic
          || fdh->elf.ref_dynamic
          || (fdh->elf.root.type == bfd_link_hash_undefweak
@@ -5947,6 +6353,9 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
     };
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   if (htab->sfpr == NULL)
     /* We don't have any relocs.  */
     return TRUE;
@@ -5979,9 +6388,12 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   asection *s;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Deal with function syms.  */
   if (h->type == STT_FUNC
+      || h->type == STT_GNU_IFUNC
       || h->needs_plt)
     {
       /* Clear procedure linkage table information for any symbol that
@@ -5991,9 +6403,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || SYMBOL_CALLS_LOCAL (info, h)
-         || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
-             && h->root.type == bfd_link_hash_undefweak))
+         || (h->type != STT_GNU_IFUNC
+             && (SYMBOL_CALLS_LOCAL (info, h)
+                 || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+                     && h->root.type == bfd_link_hash_undefweak))))
        {
          h->plt.plist = NULL;
          h->needs_plt = 0;
@@ -6035,7 +6448,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)
@@ -6061,9 +6474,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         function pointers, vtable refs and suchlike in read-only
         sections.  Allow them to proceed, but warn that this might
         break at runtime.  */
-      (*_bfd_error_handler)
+      info->callbacks->einfo
        (_("copy reloc against `%s' requires lazy plt linking; "
-          "avoid setting LD_BIND_NOW=1 or upgrade gcc"),
+          "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
         h->root.root.string);
     }
 
@@ -6072,8 +6485,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   if (h->size == 0)
     {
-      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
-                            h->root.root.string);
+      info->callbacks->einfo (_("dynamic variable `%s' is zero size\n"),
+                             h->root.root.string);
       return TRUE;
     }
 
@@ -6136,6 +6549,9 @@ ppc64_elf_hide_symbol (struct bfd_link_info *info,
          save = *p;
          *(char *) p = '.';
          htab = ppc_hash_table (info);
+         if (htab == NULL)
+           return;
+
          fh = (struct ppc_link_hash_entry *)
            elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE);
          *(char *) p = save;
@@ -6168,7 +6584,7 @@ static bfd_boolean
 get_sym_h (struct elf_link_hash_entry **hp,
           Elf_Internal_Sym **symp,
           asection **symsecp,
-          char **tls_maskp,
+          unsigned char **tls_maskp,
           Elf_Internal_Sym **locsymsp,
           unsigned long r_symndx,
           bfd *ibfd)
@@ -6181,9 +6597,7 @@ get_sym_h (struct elf_link_hash_entry **hp,
       struct elf_link_hash_entry *h;
 
       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-      while (h->root.type == bfd_link_hash_indirect
-            || h->root.type == bfd_link_hash_warning)
-       h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      h = elf_follow_link (h);
 
       if (hp != NULL)
        *hp = h;
@@ -6238,13 +6652,16 @@ get_sym_h (struct elf_link_hash_entry **hp,
       if (tls_maskp != NULL)
        {
          struct got_entry **lgot_ents;
-         char *tls_mask;
+         unsigned char *tls_mask;
 
          tls_mask = NULL;
          lgot_ents = elf_local_got_ents (ibfd);
          if (lgot_ents != NULL)
            {
-             char *lgot_masks = (char *) (lgot_ents + symtab_hdr->sh_info);
+             struct plt_entry **local_plt = (struct plt_entry **)
+               (lgot_ents + symtab_hdr->sh_info);
+             unsigned char *lgot_masks = (unsigned char *)
+               (local_plt + symtab_hdr->sh_info);
              tls_mask = &lgot_masks[r_symndx];
            }
          *tls_maskp = tls_mask;
@@ -6258,9 +6675,12 @@ get_sym_h (struct elf_link_hash_entry **hp,
    type suitable for optimization, and 1 otherwise.  */
 
 static int
-get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
+get_tls_mask (unsigned char **tls_maskp,
+             unsigned long *toc_symndx,
+             bfd_vma *toc_addend,
              Elf_Internal_Sym **locsymsp,
-             const Elf_Internal_Rela *rel, bfd *ibfd)
+             const Elf_Internal_Rela *rel,
+             bfd *ibfd)
 {
   unsigned long r_symndx;
   int next_r;
@@ -6275,6 +6695,7 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
 
   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;
 
@@ -6288,16 +6709,15 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
     off = sym->st_value;
   off += rel->r_addend;
   BFD_ASSERT (off % 8 == 0);
-  r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8];
-  next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1];
-  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
-    return 0;
+  r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
+  next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
   if (toc_symndx != NULL)
     *toc_symndx = r_symndx;
-  if ((h == NULL
-       || ((h->root.type == bfd_link_hash_defined
-           || h->root.type == bfd_link_hash_defweak)
-          && !h->def_dynamic))
+  if (toc_addend != NULL)
+    *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 || is_static_defined (h))
       && (next_r == -1 || next_r == -2))
     return 1 - next_r;
   return 1;
@@ -6316,9 +6736,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;
@@ -6368,8 +6785,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.  */
@@ -6454,12 +6871,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
@@ -6483,8 +6900,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 (_("dynreloc miscount for %B, section %A\n"),
+                         sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
   return FALSE;
 }
@@ -6496,8 +6913,7 @@ dec_dynrel_count (bfd_vma r_info,
    applications.  */
 
 bfd_boolean
-ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
-                   bfd_boolean non_overlapping)
+ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
 {
   bfd *ibfd;
   bfd_boolean some_edited = FALSE;
@@ -6509,12 +6925,14 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       Elf_Internal_Rela *relstart, *rel, *relend;
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
-      struct elf_link_hash_entry **sym_hashes;
       bfd_vma offset;
       struct _opd_sec_data *opd;
       bfd_boolean need_edit, add_aux_fields;
       bfd_size_type cnt_16b = 0;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       sec = bfd_get_section_by_name (ibfd, ".opd");
       if (sec == NULL || sec->size == 0)
        continue;
@@ -6531,7 +6949,6 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
       local_syms = NULL;
       symtab_hdr = &elf_symtab_hdr (ibfd);
-      sym_hashes = elf_sym_hashes (ibfd);
 
       /* Read the relocations.  */
       relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -6658,15 +7075,17 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
       if (need_edit || add_aux_fields)
        {
          Elf_Internal_Rela *write_rel;
+         Elf_Internal_Shdr *rel_hdr;
          bfd_byte *rptr, *wptr;
-         bfd_byte *new_contents = NULL;
+         bfd_byte *new_contents;
          bfd_boolean skip;
          long opd_ent_size;
          bfd_size_type amt;
 
+         new_contents = NULL;
          amt = sec->size * sizeof (long) / 8;
          opd = &ppc64_elf_section_data (sec)->u.opd;
-         opd->adjust = bfd_zalloc (obfd, amt);
+         opd->adjust = bfd_zalloc (sec->owner, amt);
          if (opd->adjust == NULL)
            return FALSE;
          ppc64_elf_section_data (sec)->sec_type = sec_opd;
@@ -6742,8 +7161,12 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
                  if (h != NULL
                      && h->root.root.string[0] == '.')
                    {
-                     fdh = get_fdh ((struct ppc_link_hash_entry *) h,
-                                    ppc_hash_table (info));
+                     struct ppc_link_hash_table *htab;
+
+                     htab = ppc_hash_table (info);
+                     if (htab != NULL)
+                       fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
+                                         htab);
                      if (fdh != NULL
                          && fdh->elf.root.type != bfd_link_hash_defined
                          && fdh->elf.root.type != bfd_link_hash_defweak)
@@ -6832,9 +7255,8 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 
          /* Fudge the header size too, as this is used later in
             elf_bfd_final_link if we are emitting relocs.  */
-         elf_section_data (sec)->rel_hdr.sh_size
-           = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize;
-         BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL);
+         rel_hdr = _bfd_elf_single_rel_hdr (sec);
+         rel_hdr->sh_size = sec->reloc_count * rel_hdr->sh_entsize;
          some_edited = TRUE;
        }
       else if (elf_section_data (sec)->relocs != relstart)
@@ -6893,41 +7315,128 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
 /* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 asection *
-ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ppc64_elf_tls_setup (struct bfd_link_info *info,
+                    int no_tls_get_addr_opt,
+                    int *no_multi_toc)
 {
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
-  if (htab->tls_get_addr != NULL)
-    {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr;
+  if (htab == NULL)
+    return NULL;
 
-      while (h->elf.root.type == bfd_link_hash_indirect
-            || h->elf.root.type == bfd_link_hash_warning)
-       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+  if (*no_multi_toc)
+    htab->do_multi_toc = 0;
+  else if (!htab->do_multi_toc)
+    *no_multi_toc = 1;
 
-      htab->tls_get_addr = h;
+  htab->tls_get_addr = ((struct ppc_link_hash_entry *)
+                       elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+                                             FALSE, FALSE, TRUE));
+  /* Move dynamic linking info to the function descriptor sym.  */
+  if (htab->tls_get_addr != NULL)
+    func_desc_adjust (&htab->tls_get_addr->elf, info);
+  htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
+                          elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+                                                FALSE, FALSE, TRUE));
+  if (!no_tls_get_addr_opt)
+    {
+      struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
+
+      opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt",
+                                 FALSE, FALSE, TRUE);
+      if (opt != NULL)
+       func_desc_adjust (opt, info);
+      opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
+                                    FALSE, FALSE, TRUE);
+      if (opt_fd != NULL
+         && (opt_fd->root.type == bfd_link_hash_defined
+             || opt_fd->root.type == bfd_link_hash_defweak))
+       {
+         /* If glibc supports an optimized __tls_get_addr call stub,
+            signalled by the presence of __tls_get_addr_opt, and we'll
+            be calling __tls_get_addr via a plt call stub, then
+            make __tls_get_addr point to __tls_get_addr_opt.  */
+         tga_fd = &htab->tls_get_addr_fd->elf;
+         if (htab->elf.dynamic_sections_created
+             && tga_fd != NULL
+             && (tga_fd->type == STT_FUNC
+                 || tga_fd->needs_plt)
+             && !(SYMBOL_CALLS_LOCAL (info, tga_fd)
+                  || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT
+                      && tga_fd->root.type == bfd_link_hash_undefweak)))
+           {
+             struct plt_entry *ent;
 
-      if (htab->tls_get_addr_fd == NULL
-         && h->oh != NULL
-         && h->oh->is_func_descriptor
-         && (h->oh->elf.root.type == bfd_link_hash_defined
-             || h->oh->elf.root.type == bfd_link_hash_defweak))
-       htab->tls_get_addr_fd = h->oh;
+             for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next)
+               if (ent->plt.refcount > 0)
+                 break;
+             if (ent != NULL)
+               {
+                 tga_fd->root.type = bfd_link_hash_indirect;
+                 tga_fd->root.u.i.link = &opt_fd->root;
+                 ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+                 if (opt_fd->dynindx != -1)
+                   {
+                     /* Use __tls_get_addr_opt in dynamic relocations.  */
+                     opt_fd->dynindx = -1;
+                     _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+                                             opt_fd->dynstr_index);
+                     if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
+                       return NULL;
+                   }
+                 htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
+                 tga = &htab->tls_get_addr->elf;
+                 if (opt != NULL && tga != NULL)
+                   {
+                     tga->root.type = bfd_link_hash_indirect;
+                     tga->root.u.i.link = &opt->root;
+                     ppc64_elf_copy_indirect_symbol (info, opt, tga);
+                     _bfd_elf_link_hash_hide_symbol (info, opt,
+                                                     tga->forced_local);
+                     htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
+                   }
+                 htab->tls_get_addr_fd->oh = htab->tls_get_addr;
+                 htab->tls_get_addr_fd->is_func_descriptor = 1;
+                 if (htab->tls_get_addr != NULL)
+                   {
+                     htab->tls_get_addr->oh = htab->tls_get_addr_fd;
+                     htab->tls_get_addr->is_func = 1;
+                   }
+               }
+           }
+       }
+      else
+       no_tls_get_addr_opt = TRUE;
     }
+  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
+  return _bfd_elf_tls_setup (info->output_bfd, info);
+}
 
-  if (htab->tls_get_addr_fd != NULL)
-    {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+   HASH1 or HASH2.  */
 
-      while (h->elf.root.type == bfd_link_hash_indirect
-            || h->elf.root.type == bfd_link_hash_warning)
-       h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+                        const Elf_Internal_Rela *rel,
+                        const struct ppc_link_hash_entry *hash1,
+                        const struct ppc_link_hash_entry *hash2)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+  enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
+  unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
 
-      htab->tls_get_addr_fd = h;
-    }
+  if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
 
-  return _bfd_elf_tls_setup (obfd, info);
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      h = elf_follow_link (h);
+      if (h == &hash1->elf || h == &hash2->elf)
+       return TRUE;
+    }
+  return FALSE;
 }
 
 /* Run through all the TLS relocs looking for optimization
@@ -6938,34 +7447,40 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
    dynamic relocations.  */
 
 bfd_boolean
-ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+ppc64_elf_tls_optimize (struct bfd_link_info *info)
 {
   bfd *ibfd;
   asection *sec;
   struct ppc_link_hash_table *htab;
+  unsigned char *toc_ref;
   int pass;
 
   if (info->relocatable || !info->executable)
     return TRUE;
 
   htab = ppc_hash_table (info);
-  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
-    {
-      Elf_Internal_Sym *locsyms = NULL;
-      asection *toc = bfd_get_section_by_name (ibfd, ".toc");
-      unsigned char *toc_ref = NULL;
-
-      /* Look at all the sections for this file.  Make two passes over
-        the relocs.  On the first pass, mark toc entries involved
-        with tls relocs, and check that tls relocs involved in
-        setting up a tls_get_addr call are indeed followed by such a
-        call.  If they are not, exclude them from the optimizations
-        done on the second pass.  */
-      for (pass = 0; pass < 2; ++pass)
+  if (htab == NULL)
+    return FALSE;
+
+  /* Make two passes over the relocs.  On the first pass, mark toc
+     entries involved with tls relocs, and check that tls relocs
+     involved in setting up a tls_get_addr call are indeed followed by
+     such a call.  If they are not, we can't do any tls optimization.
+     On the second pass twiddle tls_mask flags to notify
+     relocate_section that optimization can be done, and adjust got
+     and plt refcounts.  */
+  toc_ref = NULL;
+  for (pass = 0; pass < 2; ++pass)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+      {
+       Elf_Internal_Sym *locsyms = NULL;
+       asection *toc = bfd_get_section_by_name (ibfd, ".toc");
+
        for (sec = ibfd->sections; sec != NULL; sec = sec->next)
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
            {
              Elf_Internal_Rela *relstart, *rel, *relend;
+             bfd_boolean found_tls_get_addr_arg = 0;
 
              /* Read the relocations.  */
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -6981,12 +7496,13 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                  struct elf_link_hash_entry *h;
                  Elf_Internal_Sym *sym;
                  asection *sym_sec;
-                 char *tls_mask;
-                 char tls_set, tls_clear, tls_type = 0;
+                 unsigned char *tls_mask;
+                 unsigned char tls_set, tls_clear, tls_type = 0;
                  bfd_vma value;
                  bfd_boolean ok_tprel, is_local;
                  long toc_ref_index = 0;
                  int expecting_tls_get_addr = 0;
+                 bfd_boolean ret = FALSE;
 
                  r_symndx = ELF64_R_SYM (rel->r_info);
                  if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms,
@@ -7001,15 +7517,21 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                          && (elf_symtab_hdr (ibfd).contents
                              != (unsigned char *) locsyms))
                        free (locsyms);
-                     return FALSE;
+                     return ret;
                    }
 
                  if (h != NULL)
                    {
-                     if (h->root.type != bfd_link_hash_defined
-                         && h->root.type != bfd_link_hash_defweak)
-                       continue;
-                     value = h->root.u.def.value;
+                     if (h->root.type == bfd_link_hash_defined
+                         || h->root.type == bfd_link_hash_defweak)
+                       value = h->root.u.def.value;
+                     else if (h->root.type == bfd_link_hash_undefweak)
+                       value = 0;
+                     else
+                       {
+                         found_tls_get_addr_arg = 0;
+                         continue;
+                       }
                    }
                  else
                    /* Symbols referenced by TLS relocs must be of type
@@ -7022,19 +7544,48 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      || !h->def_dynamic)
                    {
                      is_local = TRUE;
-                     value += sym_sec->output_offset;
-                     value += sym_sec->output_section->vma;
-                     value -= htab->elf.tls_sec->vma;
-                     ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
-                                 < (bfd_vma) 1 << 32);
+                     if (h != NULL
+                         && h->root.type == bfd_link_hash_undefweak)
+                       ok_tprel = TRUE;
+                     else
+                       {
+                         value += sym_sec->output_offset;
+                         value += sym_sec->output_section->vma;
+                         value -= htab->elf.tls_sec->vma;
+                         ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
+                                     < (bfd_vma) 1 << 32);
+                       }
                    }
 
                  r_type = ELF64_R_TYPE (rel->r_info);
+                 /* If this section has old-style __tls_get_addr calls
+                    without marker relocs, then check that each
+                    __tls_get_addr call reloc is preceded by a reloc
+                    that conceivably belongs to the __tls_get_addr arg
+                    setup insn.  If we don't find matching arg setup
+                    relocs, don't do any tls optimization.  */
+                 if (pass == 0
+                     && sec->has_tls_get_addr_call
+                     && h != NULL
+                     && (h == &htab->tls_get_addr->elf
+                         || h == &htab->tls_get_addr_fd->elf)
+                     && !found_tls_get_addr_arg
+                     && is_branch_reloc (r_type))
+                   {
+                     info->callbacks->minfo (_("%H __tls_get_addr lost arg, "
+                                               "TLS optimization disabled\n"),
+                                             ibfd, sec, rel->r_offset);
+                     ret = TRUE;
+                     goto err_free_rel;
+                   }
+
+                 found_tls_get_addr_arg = 0;
                  switch (r_type)
                    {
                    case R_PPC64_GOT_TLSLD16:
                    case R_PPC64_GOT_TLSLD16_LO:
                      expecting_tls_get_addr = 1;
+                     found_tls_get_addr_arg = 1;
                      /* Fall thru */
 
                    case R_PPC64_GOT_TLSLD16_HI:
@@ -7054,6 +7605,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                    case R_PPC64_GOT_TLSGD16:
                    case R_PPC64_GOT_TLSGD16_LO:
                      expecting_tls_get_addr = 1;
+                     found_tls_get_addr_arg = 1;
                      /* Fall thru */
 
                    case R_PPC64_GOT_TLSGD16_HI:
@@ -7082,9 +7634,14 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                        }
                      continue;
 
+                   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:
-                   case R_PPC64_TLS:
                      if (sym_sec == NULL || sym_sec != toc)
                        continue;
 
@@ -7093,19 +7650,20 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                         case of R_PPC64_TLS, and after checking for
                         tls_get_addr for the TOC16 relocs.  */
                      if (toc_ref == NULL)
-                       {
-                         toc_ref = bfd_zmalloc (toc->size / 8);
-                         if (toc_ref == NULL)
-                           goto err_free_rel;
-                       }
+                       toc_ref = bfd_zmalloc (toc->output_section->rawsize / 8);
+                     if (toc_ref == NULL)
+                       goto err_free_rel;
+
                      if (h != NULL)
                        value = h->root.u.def.value;
                      else
                        value = sym->st_value;
                      value += rel->r_addend;
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
-                     toc_ref_index = value / 8;
-                     if (r_type == R_PPC64_TLS)
+                     toc_ref_index = (value + toc->output_offset) / 8;
+                     if (r_type == R_PPC64_TLS
+                         || r_type == R_PPC64_TLSGD
+                         || r_type == R_PPC64_TLSLD)
                        {
                          toc_ref[toc_ref_index] = 1;
                          continue;
@@ -7123,7 +7681,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      if (pass == 0
                          || sec != toc
                          || toc_ref == NULL
-                         || !toc_ref[rel->r_offset / 8])
+                         || !toc_ref[(rel->r_offset + toc->output_offset) / 8])
                        continue;
                      if (ok_tprel)
                        {
@@ -7138,7 +7696,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      if (pass == 0
                          || sec != toc
                          || toc_ref == NULL
-                         || !toc_ref[rel->r_offset / 8])
+                         || !toc_ref[(rel->r_offset + toc->output_offset) / 8])
                        continue;
                      if (rel + 1 < relend
                          && (rel[1].r_info
@@ -7170,58 +7728,35 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 
                  if (pass == 0)
                    {
-                     if (!expecting_tls_get_addr)
+                     if (!expecting_tls_get_addr
+                         || !sec->has_tls_get_addr_call)
                        continue;
 
-                     if (rel + 1 < relend)
+                     if (rel + 1 < relend
+                         && branch_reloc_hash_match (ibfd, rel + 1,
+                                                     htab->tls_get_addr,
+                                                     htab->tls_get_addr_fd))
                        {
-                         Elf_Internal_Shdr *symtab_hdr;
-                         enum elf_ppc64_reloc_type r_type2;
-                         unsigned long r_symndx2;
-                         struct elf_link_hash_entry *h2;
-
-                         symtab_hdr = &elf_symtab_hdr (ibfd);
-
-                         /* The next instruction should be a call to
-                            __tls_get_addr.  Peek at the reloc to be sure.  */
-                         r_type2 = ELF64_R_TYPE (rel[1].r_info);
-                         r_symndx2 = ELF64_R_SYM (rel[1].r_info);
-                         if (r_symndx2 >= symtab_hdr->sh_info
-                             && (r_type2 == R_PPC64_REL14
-                                 || r_type2 == R_PPC64_REL14_BRTAKEN
-                                 || r_type2 == R_PPC64_REL14_BRNTAKEN
-                                 || r_type2 == R_PPC64_REL24))
+                         if (expecting_tls_get_addr == 2)
                            {
-                             struct elf_link_hash_entry **sym_hashes;
-
-                             sym_hashes = elf_sym_hashes (ibfd);
-
-                             h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
-                             while (h2->root.type == bfd_link_hash_indirect
-                                    || h2->root.type == bfd_link_hash_warning)
-                               h2 = ((struct elf_link_hash_entry *)
-                                     h2->root.u.i.link);
-                             if (h2 != NULL
-                                 && (h2 == &htab->tls_get_addr->elf
-                                     || h2 == &htab->tls_get_addr_fd->elf))
+                             /* Check for toc tls entries.  */
+                             unsigned char *toc_tls;
+                             int retval;
+
+                             retval = get_tls_mask (&toc_tls, NULL, NULL,
+                                                    &locsyms,
+                                                    rel, ibfd);
+                             if (retval == 0)
+                               goto err_free_rel;
+                             if (toc_tls != NULL)
                                {
-                                 if (expecting_tls_get_addr == 2)
-                                   {
-                                     /* Check for toc tls entries.  */
-                                     char *toc_tls;
-                                     int retval;
-
-                                     retval = get_tls_mask (&toc_tls, NULL,
-                                                            &locsyms,
-                                                            rel, ibfd);
-                                     if (retval == 0)
-                                       goto err_free_rel;
-                                     if (retval > 1 && toc_tls != NULL)
-                                       toc_ref[toc_ref_index] = 1;
-                                   }
-                                 continue;
+                                 if ((*toc_tls & (TLS_GD | TLS_LD)) != 0)
+                                   found_tls_get_addr_arg = 1;
+                                 if (retval > 1)
+                                   toc_ref[toc_ref_index] = 1;
                                }
                            }
+                         continue;
                        }
 
                      if (expecting_tls_get_addr != 1)
@@ -7230,9 +7765,12 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
-                        the entire section.  */
-                     sec->has_tls_reloc = 0;
-                     break;
+                        the entire optimization.  */
+                     info->callbacks->minfo (_("%H arg lost __tls_get_addr, "
+                                               "TLS optimization disabled\n"),
+                                             ibfd, sec, rel->r_offset);
+                     ret = TRUE;
+                     goto err_free_rel;
                    }
 
                  if (expecting_tls_get_addr && htab->tls_get_addr != NULL)
@@ -7318,9 +7856,6 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                free (relstart);
            }
 
-       if (toc_ref != NULL)
-         free (toc_ref);
-
        if (locsyms != NULL
            && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
          {
@@ -7330,6 +7865,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
          }
       }
+
+  if (toc_ref != NULL)
+    free (toc_ref);
   return TRUE;
 }
 
@@ -7346,18 +7884,18 @@ 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;
+  unsigned long i;
 
   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;
@@ -7368,16 +7906,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)
@@ -7390,23 +7934,27 @@ adjust_toc_syms (struct elf_link_hash_entry *h, void *inf)
    unused .toc entries.  */
 
 bfd_boolean
-ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+ppc64_elf_edit_toc (struct bfd_link_info *info)
 {
   bfd *ibfd;
   struct adjust_toc_info toc_inf;
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
+  htab->do_toc_opt = 1;
   toc_inf.global_toc_syms = TRUE;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
       asection *toc, *sec;
       Elf_Internal_Shdr *symtab_hdr;
       Elf_Internal_Sym *local_syms;
-      struct elf_link_hash_entry **sym_hashes;
-      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Rela *relstart, *rel, *toc_relocs;
       unsigned long *skip, *drop;
       unsigned char *used;
       unsigned char *keep, last, some_unused;
 
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
       toc = bfd_get_section_by_name (ibfd, ".toc");
       if (toc == NULL
          || toc->size == 0
@@ -7414,9 +7962,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
          || elf_discarded_section (toc))
        continue;
 
+      toc_relocs = NULL;
       local_syms = NULL;
       symtab_hdr = &elf_symtab_hdr (ibfd);
-      sym_hashes = elf_sym_hashes (ibfd);
 
       /* Look at sections dropped from the final link.  */
       skip = NULL;
@@ -7484,18 +8032,101 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
 
              if (skip == NULL)
                {
-                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8);
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
                  if (skip == NULL)
                    goto error_ret;
                }
 
-             skip[val >> 3] = 1;
+             skip[val >> 3] = ref_from_discarded;
            }
 
          if (elf_section_data (sec)->relocs != relstart)
            free (relstart);
        }
 
+      /* For largetoc loads of address constants, we can convert
+        .  addis rx,2,addr@got@ha
+        .  ld ry,addr@got@l(rx)
+        to
+        .  addis rx,2,addr@toc@ha
+        .  addi ry,rx,addr@toc@l
+        when addr is within 2G of the toc pointer.  This then means
+        that the word storing "addr" in the toc is no longer needed.  */
+        
+      if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
+         && toc->output_section->rawsize < (bfd_vma) 1 << 31
+         && toc->reloc_count != 0)
+       {
+         /* Read toc relocs.  */
+         toc_relocs = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
+                                                 info->keep_memory);
+         if (toc_relocs == NULL)
+           goto error_ret;
+
+         for (rel = toc_relocs; rel < toc_relocs + toc->reloc_count; ++rel)
+           {
+             enum elf_ppc64_reloc_type r_type;
+             unsigned long r_symndx;
+             asection *sym_sec;
+             struct elf_link_hash_entry *h;
+             Elf_Internal_Sym *sym;
+             bfd_vma val, addr;
+
+             r_type = ELF64_R_TYPE (rel->r_info);
+             if (r_type != R_PPC64_ADDR64)
+               continue;
+
+             r_symndx = ELF64_R_SYM (rel->r_info);
+             if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                             r_symndx, ibfd))
+               goto error_ret;
+
+             if (sym_sec == NULL
+                 || elf_discarded_section (sym_sec))
+               continue;
+
+             if (!SYMBOL_CALLS_LOCAL (info, h))
+               continue;
+
+             if (h != NULL)
+               {
+                 if (h->type == STT_GNU_IFUNC)
+                   continue;
+                 val = h->root.u.def.value;
+               }
+             else
+               {
+                 if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   continue;
+                 val = sym->st_value;
+               }
+             val += rel->r_addend;
+             val += sym_sec->output_section->vma + sym_sec->output_offset;
+
+             /* We don't yet know the exact toc pointer value, but we
+                know it will be somewhere in the toc section.  Don't
+                optimize if the difference from any possible toc
+                pointer is outside [ff..f80008000, 7fff7fff].  */
+             addr = toc->output_section->vma + TOC_BASE_OFF;
+             if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32)
+               continue;
+
+             addr = toc->output_section->vma + toc->output_section->rawsize;
+             if (val - addr + (bfd_vma) 0x80008000 >= (bfd_vma) 1 << 32)
+               continue;
+
+             if (skip == NULL)
+               {
+                 skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 15) / 8);
+                 if (skip == NULL)
+                   goto error_ret;
+               }
+
+             skip[rel->r_offset >> 3]
+               |= can_optimize | ((rel - toc_relocs) << 2);
+           }
+       }
+
       if (skip == NULL)
        continue;
 
@@ -7510,6 +8141,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              && relstart != NULL
              && elf_section_data (sec)->relocs != relstart)
            free (relstart);
+         if (toc_relocs != NULL
+             && elf_section_data (toc)->relocs != toc_relocs)
+           free (toc_relocs);
          if (skip != NULL)
            free (skip);
          return FALSE;
@@ -7534,7 +8168,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              || (sec->flags & SEC_DEBUGGING) != 0)
            continue;
 
-         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE);
+         relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                               info->keep_memory);
          if (relstart == NULL)
            goto error_ret;
 
@@ -7587,12 +8222,37 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                if (val >= toc->size)
                  continue;
 
+               if ((skip[val >> 3] & can_optimize) != 0)
+                 {
+                   bfd_vma off;
+                   unsigned char opc;
+
+                   switch (r_type)
+                     {
+                     case R_PPC64_TOC16_HA:
+                       break;
+
+                     case R_PPC64_TOC16_LO_DS:
+                       off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
+                       if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
+                         return FALSE;
+                       if ((opc & (0x3f << 2)) == (58u << 2))
+                         break;
+                       /* Fall thru */
+
+                     default:
+                       /* Wrong sort of reloc, or not a ld.  We may
+                          as well clear ref_from_discarded too.  */
+                       skip[val >> 3] = 0;
+                     }
+                 }
+
                /* For the toc section, we only mark as used if
                   this entry itself isn't unused.  */
                if (sec == toc
                    && !used[val >> 3]
                    && (used[rel->r_offset >> 3]
-                       || !skip[rel->r_offset >> 3]))
+                       || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
                  /* Do all the relocs again, to catch reference
                     chains.  */
                  repeat = 1;
@@ -7600,6 +8260,9 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                used[val >> 3] = 1;
              }
          while (repeat);
+
+         if (elf_section_data (sec)->relocs != relstart)
+           free (relstart);
        }
 
       /* Merge the used and skip arrays.  Assume that TOC
@@ -7611,13 +8274,15 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
        {
          if (*keep)
            {
-             *drop = 0;
+             *drop &= ~ref_from_discarded;
+             if ((*drop & can_optimize) != 0)
+               some_unused = 1;
              last = 0;
            }
          else if (*drop)
            {
              some_unused = 1;
-             last = 1;
+             last = ref_from_discarded;
            }
          else
            *drop = last;
@@ -7629,6 +8294,8 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
        {
          bfd_byte *contents, *src;
          unsigned long off;
+         Elf_Internal_Sym *sym;
+         bfd_boolean local_toc_syms = FALSE;
 
          /* Shuffle the toc contents, and at the same time convert the
             skip array from booleans into offsets.  */
@@ -7641,52 +8308,20 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
               src < contents + toc->size;
               src += 8, ++drop)
            {
-             if (*drop)
-               {
-                 *drop = (unsigned long) -1;
-                 off += 8;
-               }
+             if ((*drop & (can_optimize | ref_from_discarded)) != 0)
+               off += 8;
              else if (off != 0)
                {
                  *drop = off;
                  memcpy (src - off, src, 8);
                }
            }
+         *drop = off;
          toc->rawsize = toc->size;
          toc->size = src - contents - off;
 
-         if (toc->reloc_count != 0)
-           {
-             Elf_Internal_Rela *wrel;
-             bfd_size_type sz;
-
-             /* Read toc relocs.  */
-             relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL,
-                                                   TRUE);
-             if (relstart == NULL)
-               goto error_ret;
-
-             /* Remove unused toc relocs, and adjust those we keep.  */
-             wrel = relstart;
-             for (rel = relstart; rel < relstart + toc->reloc_count; ++rel)
-               if (skip[rel->r_offset >> 3] != (unsigned long) -1)
-                 {
-                   wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3];
-                   wrel->r_info = rel->r_info;
-                   wrel->r_addend = rel->r_addend;
-                   ++wrel;
-                 }
-               else if (!dec_dynrel_count (rel->r_info, toc, info,
-                                           &local_syms, NULL, NULL))
-                 goto error_ret;
-
-             toc->reloc_count = wrel - relstart;
-             sz = elf_section_data (toc)->rel_hdr.sh_entsize;
-             elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz;
-             BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL);
-           }
-
-         /* Adjust addends for relocs against the toc section sym.  */
+         /* Adjust addends for relocs against the toc section sym,
+            and optimize any accesses we can.  */
          for (sec = ibfd->sections; sec != NULL; sec = sec->next)
            {
              if (sec->reloc_count == 0
@@ -7694,7 +8329,7 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                continue;
 
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
-                                                   TRUE);
+                                                   info->keep_memory);
              if (relstart == NULL)
                goto error_ret;
 
@@ -7704,7 +8339,7 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                  unsigned long r_symndx;
                  asection *sym_sec;
                  struct elf_link_hash_entry *h;
-                 Elf_Internal_Sym *sym;
+                 bfd_vma val;
 
                  r_type = ELF64_R_TYPE (rel->r_info);
                  switch (r_type)
@@ -7727,41 +8362,92 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
                                  r_symndx, ibfd))
                    goto error_ret;
 
-                 if (sym_sec != toc || h != NULL || sym->st_value != 0)
+                 if (sym_sec != toc)
+                   continue;
+
+                 if (h != NULL)
+                   val = h->root.u.def.value;
+                 else
+                   {
+                     val = sym->st_value;
+                     if (val != 0)
+                       local_toc_syms = TRUE;
+                   }
+
+                 val += rel->r_addend;
+
+                 if (val > toc->rawsize)
+                   val = toc->rawsize;
+                 else if ((skip[val >> 3] & ref_from_discarded) != 0)
+                   continue;
+                 else if ((skip[val >> 3] & can_optimize) != 0)
+                   {
+                     Elf_Internal_Rela *tocrel
+                       = toc_relocs + (skip[val >> 3] >> 2);
+                     unsigned long tsym = ELF64_R_SYM (tocrel->r_info);
+
+                     switch (r_type)
+                       {
+                       case R_PPC64_TOC16_HA:
+                         rel->r_info = ELF64_R_INFO (tsym, R_PPC64_TOC16_HA);
+                         break;
+
+                       case R_PPC64_TOC16_LO_DS:
+                         rel->r_info = ELF64_R_INFO (tsym, R_PPC64_LO_DS_OPT);
+                         break;
+
+                       default:
+                         abort ();
+                       }
+                     rel->r_addend = tocrel->r_addend;
+                     elf_section_data (sec)->relocs = relstart;
+                     continue;
+                   }
+
+                 if (h != NULL || sym->st_value != 0)
                    continue;
 
-                 rel->r_addend -= skip[rel->r_addend >> 3];
+                 rel->r_addend -= skip[val >> 3];
+                 elf_section_data (sec)->relocs = relstart;
                }
+
+             if (elf_section_data (sec)->relocs != relstart)
+               free (relstart);
            }
 
          /* We shouldn't have local or global symbols defined in the TOC,
             but handle them anyway.  */
          if (local_syms != NULL)
-           {
-             Elf_Internal_Sym *sym;
+           for (sym = local_syms;
+                sym < local_syms + symtab_hdr->sh_info;
+                ++sym)
+             if (sym->st_value != 0
+                 && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
+               {
+                 unsigned long i;
 
-             for (sym = local_syms;
-                  sym < local_syms + symtab_hdr->sh_info;
-                  ++sym)
-               if (sym->st_value != 0
-                   && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
-                 {
-                   if (skip[sym->st_value >> 3] != (unsigned long) -1)
-                     sym->st_value -= skip[sym->st_value >> 3];
-                   else
-                     {
+                 if (sym->st_value > toc->rawsize)
+                   i = toc->rawsize >> 3;
+                 else
+                   i = sym->st_value >> 3;
+
+                 if ((skip[i] & (ref_from_discarded | can_optimize)) != 0)
+                   {
+                     if (local_toc_syms)
                        (*_bfd_error_handler)
-                         (_("%s defined in removed toc entry"),
-                          bfd_elf_sym_name (ibfd, symtab_hdr, sym,
-                                            NULL));
-                       sym->st_value = 0;
-                       sym->st_shndx = SHN_ABS;
-                     }
-                   symtab_hdr->contents = (unsigned char *) local_syms;
-                 }
-           }
+                         (_("%s defined on removed toc entry"),
+                          bfd_elf_sym_name (ibfd, symtab_hdr, sym, NULL));
+                     do
+                       ++i;
+                     while ((skip[i] & (ref_from_discarded | can_optimize)));
+                     sym->st_value = (bfd_vma) i << 3;
+                   }
 
-         /* 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;
@@ -7770,7 +8456,44 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
              elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms,
                                      &toc_inf);
            }
+
+         if (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)
@@ -7786,6 +8509,72 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, 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
+allocate_got (struct elf_link_hash_entry *h,
+             struct bfd_link_info *info,
+             struct got_entry *gent)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd_boolean dyn;
+  struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
+  int entsize = (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)
+                ? 16 : 8);
+  int rentsize = (gent->tls_type & eh->tls_mask & TLS_GD
+                 ? 2 : 1) * sizeof (Elf64_External_Rela);
+  asection *got = ppc64_elf_tdata (gent->owner)->got;
+
+  gent->got.offset = got->size;
+  got->size += entsize;
+
+  dyn = htab->elf.dynamic_sections_created;
+  if ((info->shared
+       || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+               || h->root.type != bfd_link_hash_undefweak))
+    {
+      asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
+      relgot->size += rentsize;
+    }
+  else if (h->type == STT_GNU_IFUNC)
+    {
+      asection *relgot = htab->reliplt;
+      relgot->size += rentsize;
+      htab->got_reli_size += rentsize;
+    }
+}
+
+/* This function merges got entries in the same toc group.  */
+
+static void
+merge_got_entries (struct got_entry **pent)
+{
+  struct got_entry *ent, *ent2;
+
+  for (ent = *pent; ent != NULL; ent = ent->next)
+    if (!ent->is_indirect)
+      for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
+       if (!ent2->is_indirect
+           && ent2->addend == ent->addend
+           && ent2->tls_type == ent->tls_type
+           && elf_gp (ent2->owner) == elf_gp (ent->owner))
+         {
+           ent2->is_indirect = TRUE;
+           ent2->got.ent = ent;
+         }
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
@@ -7796,49 +8585,60 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   struct ppc_link_hash_table *htab;
   asection *s;
   struct ppc_link_hash_entry *eh;
-  struct ppc_dyn_relocs *p;
-  struct got_entry *gent;
+  struct elf_dyn_relocs *p;
+  struct got_entry **pgent, *gent;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
-  if (h->root.type == bfd_link_hash_warning)
-    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
   info = (struct bfd_link_info *) inf;
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
-  if (htab->elf.dynamic_sections_created
-      && h->dynindx != -1
-      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+  if ((htab->elf.dynamic_sections_created
+       && h->dynindx != -1
+       && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+      || h->type == STT_GNU_IFUNC)
     {
       struct plt_entry *pent;
       bfd_boolean doneone = FALSE;
       for (pent = h->plt.plist; pent != NULL; pent = pent->next)
        if (pent->plt.refcount > 0)
          {
-           /* If this is the first .plt entry, make room for the special
-              first entry.  */
-           s = htab->plt;
-           if (s->size == 0)
-             s->size += PLT_INITIAL_ENTRY_SIZE;
-
-           pent->plt.offset = s->size;
-
-           /* Make room for this entry.  */
-           s->size += PLT_ENTRY_SIZE;
-
-           /* Make room for the .glink code.  */
-           s = htab->glink;
-           if (s->size == 0)
-             s->size += GLINK_CALL_STUB_SIZE;
-           /* We need bigger stubs past index 32767.  */
-           if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
-             s->size += 4;
-           s->size += 2*4;
-
-           /* We also need to make an entry in the .rela.plt section.  */
-           s = htab->relplt;
+           if (!htab->elf.dynamic_sections_created
+               || h->dynindx == -1)
+             {
+               s = htab->iplt;
+               pent->plt.offset = s->size;
+               s->size += PLT_ENTRY_SIZE;
+               s = htab->reliplt;
+             }
+           else
+             {
+               /* If this is the first .plt entry, make room for the special
+                  first entry.  */
+               s = htab->plt;
+               if (s->size == 0)
+                 s->size += PLT_INITIAL_ENTRY_SIZE;
+
+               pent->plt.offset = s->size;
+
+               /* Make room for this entry.  */
+               s->size += PLT_ENTRY_SIZE;
+
+               /* Make room for the .glink code.  */
+               s = htab->glink;
+               if (s->size == 0)
+                 s->size += GLINK_CALL_STUB_SIZE;
+               /* We need bigger stubs past index 32767.  */
+               if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+                 s->size += 4;
+               s->size += 2*4;
+
+               /* We also need to make an entry in the .rela.plt section.  */
+               s = htab->relplt;
+             }
            s->size += sizeof (Elf64_External_Rela);
            doneone = TRUE;
          }
@@ -7882,52 +8682,52 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            gent->tls_type = TLS_TLS | TLS_TPREL;
        }
 
-  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+  /* Remove any list entry that won't generate a word in the GOT before
+     we call merge_got_entries.  Otherwise we risk merging to empty
+     entries.  */
+  pgent = &h->got.glist;
+  while ((gent = *pgent) != NULL)
     if (gent->got.refcount > 0)
       {
-       bfd_boolean dyn;
+       if ((gent->tls_type & TLS_LD) != 0
+           && !h->def_dynamic)
+         {
+           ppc64_tlsld_got (gent->owner)->got.refcount += 1;
+           *pgent = gent->next;
+         }
+       else
+         pgent = &gent->next;
+      }
+    else
+      *pgent = gent->next;
 
+  if (!htab->do_multi_toc)
+    merge_got_entries (&h->got.glist);
+
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (!gent->is_indirect)
+      {
        /* Make sure this symbol is output as a dynamic symbol.
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
        if (h->dynindx == -1
            && !h->forced_local
+           && h->type != STT_GNU_IFUNC
            && htab->elf.dynamic_sections_created)
          {
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
              return FALSE;
          }
 
-       if ((gent->tls_type & TLS_LD) != 0
-           && !h->def_dynamic)
-         {
-           ppc64_tlsld_got (gent->owner)->refcount += 1;
-           gent->got.offset = (bfd_vma) -1;
-           continue;
-         }
-
        if (!is_ppc64_elf (gent->owner))
-         continue;
+         abort ();
 
-       s = ppc64_elf_tdata (gent->owner)->got;
-       gent->got.offset = s->size;
-       s->size
-         += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
-       dyn = htab->elf.dynamic_sections_created;
-       if ((info->shared
-            || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
-           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-               || h->root.type != bfd_link_hash_undefweak))
-         ppc64_elf_tdata (gent->owner)->relgot->size
-           += (gent->tls_type & eh->tls_mask & TLS_GD
-               ? 2 * sizeof (Elf64_External_Rela)
-               : sizeof (Elf64_External_Rela));
+       allocate_got (h, info, gent);
       }
-    else
-      gent->got.offset = (bfd_vma) -1;
 
   if (eh->dyn_relocs == NULL
-      || !htab->elf.dynamic_sections_created)
+      || (!htab->elf.dynamic_sections_created
+         && h->type != STT_GNU_IFUNC))
     return TRUE;
 
   /* In the shared -Bsymbolic case, discard space allocated for
@@ -7946,7 +8746,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; )
            {
@@ -7977,6 +8777,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            }
        }
     }
+  else if (h->type == STT_GNU_IFUNC)
+    {
+      if (!h->non_got_ref)
+       eh->dyn_relocs = NULL;
+    }
   else if (ELIMINATE_COPY_RELOCS)
     {
       /* For the non-shared case, discard space for relocs against
@@ -8010,6 +8815,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
+      if (!htab->elf.dynamic_sections_created)
+       sreloc = htab->reliplt;
       sreloc->size += p->count * sizeof (Elf64_External_Rela);
     }
 
@@ -8022,10 +8829,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)
@@ -8056,8 +8860,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   asection *s;
   bfd_boolean relocs;
   bfd *ibfd;
+  struct got_entry *first_tlsld;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   dynobj = htab->elf.dynobj;
   if (dynobj == NULL)
     abort ();
@@ -8081,7 +8889,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
     {
       struct got_entry **lgot_ents;
       struct got_entry **end_lgot_ents;
-      char *lgot_masks;
+      struct plt_entry **local_plt;
+      struct plt_entry **end_local_plt;
+      unsigned char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
       asection *srel;
@@ -8091,7 +8901,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)
            {
@@ -8106,6 +8916,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
              else if (p->count != 0)
                {
                  srel = elf_section_data (p->sec)->sreloc;
+                 if (!htab->elf.dynamic_sections_created)
+                   srel = htab->reliplt;
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
@@ -8120,40 +8932,63 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       symtab_hdr = &elf_symtab_hdr (ibfd);
       locsymcount = symtab_hdr->sh_info;
       end_lgot_ents = lgot_ents + locsymcount;
-      lgot_masks = (char *) end_lgot_ents;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      lgot_masks = (unsigned char *) end_local_plt;
       s = ppc64_elf_tdata (ibfd)->got;
       srel = ppc64_elf_tdata (ibfd)->relgot;
       for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
        {
-         struct got_entry *ent;
+         struct got_entry **pent, *ent;
 
-         for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+         pent = lgot_ents;
+         while ((ent = *pent) != NULL)
            if (ent->got.refcount > 0)
              {
                if ((ent->tls_type & *lgot_masks & TLS_LD) != 0)
                  {
-                   ppc64_tlsld_got (ibfd)->refcount += 1;
-                   ent->got.offset = (bfd_vma) -1;
+                   ppc64_tlsld_got (ibfd)->got.refcount += 1;
+                   *pent = ent->next;
                  }
                else
                  {
+                   unsigned int num = 1;
                    ent->got.offset = s->size;
                    if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
+                     num = 2;
+                   s->size += num * 8;
+                   if (info->shared)
+                     srel->size += num * sizeof (Elf64_External_Rela);
+                   else if ((*lgot_masks & PLT_IFUNC) != 0)
                      {
-                       s->size += 16;
-                       if (info->shared)
-                         srel->size += 2 * sizeof (Elf64_External_Rela);
-                     }
-                   else
-                     {
-                       s->size += 8;
-                       if (info->shared)
-                         srel->size += sizeof (Elf64_External_Rela);
+                       htab->reliplt->size
+                         += num * sizeof (Elf64_External_Rela);
+                       htab->got_reli_size
+                         += num * sizeof (Elf64_External_Rela);
                      }
+                   pent = &ent->next;
                  }
              }
            else
-             ent->got.offset = (bfd_vma) -1;
+             *pent = ent->next;
+       }
+
+      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
+      for (; local_plt < end_local_plt; ++local_plt)
+       {
+         struct plt_entry *ent;
+
+         for (ent = *local_plt; ent != NULL; ent = ent->next)
+           if (ent->plt.refcount > 0)
+             {
+               s = htab->iplt;
+               ent->plt.offset = s->size;
+               s->size += PLT_ENTRY_SIZE;
+
+               htab->reliplt->size += sizeof (Elf64_External_Rela);
+             }
+           else
+             ent->plt.offset = (bfd_vma) -1;
        }
     }
 
@@ -8161,24 +8996,39 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
 
+  first_tlsld = NULL;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
+      struct got_entry *ent;
+
       if (!is_ppc64_elf (ibfd))
        continue;
 
-      if (ppc64_tlsld_got (ibfd)->refcount > 0)
+      ent = ppc64_tlsld_got (ibfd);
+      if (ent->got.refcount > 0)
        {
-         s = ppc64_elf_tdata (ibfd)->got;
-         ppc64_tlsld_got (ibfd)->offset = s->size;
-         s->size += 16;
-         if (info->shared)
+         if (!htab->do_multi_toc && first_tlsld != NULL)
            {
-             asection *srel = ppc64_elf_tdata (ibfd)->relgot;
-             srel->size += sizeof (Elf64_External_Rela);
+             ent->is_indirect = TRUE;
+             ent->got.ent = first_tlsld;
+           }
+         else
+           {
+             if (first_tlsld == NULL)
+               first_tlsld = ent;
+             s = ppc64_elf_tdata (ibfd)->got;
+             ent->got.offset = s->size;
+             ent->owner = ibfd;
+             s->size += 16;
+             if (info->shared)
+               {
+                 asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+                 srel->size += sizeof (Elf64_External_Rela);
+               }
            }
        }
       else
-       ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
+       ent->got.offset = (bfd_vma) -1;
     }
 
   /* We now have determined the sizes of the various dynamic sections.
@@ -8194,13 +9044,14 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        continue;
       else if (s == htab->got
               || s == htab->plt
+              || s == htab->iplt
               || s == htab->glink
               || s == htab->dynbss)
        {
          /* 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 (CONST_STRNEQ (s->name, ".rela"))
        {
          if (s->size != 0)
            {
@@ -8314,6 +9165,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
            return FALSE;
        }
 
+      if (!htab->no_tls_get_addr_opt
+         && htab->tls_get_addr_fd != NULL
+         && htab->tls_get_addr_fd->elf.plt.plist != NULL
+         && !add_dynamic_entry (DT_PPC64_TLSOPT, 0))
+       return FALSE;
+
       if (relocs)
        {
          if (!add_dynamic_entry (DT_RELA, 0)
@@ -8344,6 +9201,7 @@ static inline enum ppc_stub_type
 ppc_type_of_stub (asection *input_sec,
                  const Elf_Internal_Rela *rel,
                  struct ppc_link_hash_entry **hash,
+                 struct plt_entry **plt_ent,
                  bfd_vma destination)
 {
   struct ppc_link_hash_entry *h = *hash;
@@ -8354,36 +9212,51 @@ ppc_type_of_stub (asection *input_sec,
 
   if (h != NULL)
     {
+      struct plt_entry *ent;
       struct ppc_link_hash_entry *fdh = h;
-      if (fdh->oh != NULL
-         && fdh->oh->is_func_descriptor)
-       fdh = fdh->oh;
-
-      if (fdh->elf.dynindx != -1)
+      if (h->oh != NULL
+         && h->oh->is_func_descriptor)
        {
-         struct plt_entry *ent;
-
-         for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
-           if (ent->addend == rel->r_addend
-               && ent->plt.offset != (bfd_vma) -1)
-             {
-               *hash = fdh;
-               return ppc_stub_plt_call;
-             }
+         fdh = ppc_follow_link (h->oh);
+         *hash = fdh;
        }
 
+      for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
+       if (ent->addend == rel->r_addend
+           && ent->plt.offset != (bfd_vma) -1)
+         {
+           *plt_ent = ent;
+           return ppc_stub_plt_call;
+         }
+
       /* Here, we know we don't have a plt entry.  If we don't have a
         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)
+    {
+      Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_sec->owner);
+      struct plt_entry **local_plt = (struct plt_entry **)
+       elf_local_got_ents (input_sec->owner) + symtab_hdr->sh_info;
+      unsigned long r_symndx = ELF64_R_SYM (rel->r_info);
+
+      if (local_plt[r_symndx] != NULL)
+       {
+         struct plt_entry *ent;
+
+         for (ent = local_plt[r_symndx]; ent != NULL; ent = ent->next)
+           if (ent->addend == rel->r_addend
+               && ent->plt.offset != (bfd_vma) -1)
+             {
+               *plt_ent = ent;
+               return ppc_stub_plt_call;
+             }
+       }
+    }
 
   /* Determine where the call point is.  */
   location = (input_sec->output_offset
@@ -8489,6 +9362,49 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
   return p;
 }
 
+/* Build a special .plt call stub for __tls_get_addr.  */
+
+#define LD_R11_0R3     0xe9630000
+#define LD_R12_0R3     0xe9830000
+#define MR_R0_R3       0x7c601b78
+#define CMPDI_R11_0    0x2c2b0000
+#define ADD_R3_R12_R13 0x7c6c6a14
+#define BEQLR          0x4d820020
+#define MR_R3_R0       0x7c030378
+#define MFLR_R11       0x7d6802a6
+#define STD_R11_0R1    0xf9610000
+#define BCTRL          0x4e800421
+#define LD_R11_0R1     0xe9610000
+#define LD_R2_0R1      0xe8410000
+#define MTLR_R11       0x7d6803a6
+
+static inline bfd_byte *
+build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
+                        Elf_Internal_Rela *r)
+{
+  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;
+  bfd_put_32 (obfd, CMPDI_R11_0, p),           p += 4;
+  bfd_put_32 (obfd, ADD_R3_R12_R13, p),                p += 4;
+  bfd_put_32 (obfd, BEQLR, p),                 p += 4;
+  bfd_put_32 (obfd, MR_R3_R0, p),              p += 4;
+  bfd_put_32 (obfd, MFLR_R11, p),              p += 4;
+  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),      p += 4;
+
+  if (r != NULL)
+    r[0].r_offset += 9 * 4;
+  p = build_plt_stub (obfd, p, offset, r);
+  bfd_put_32 (obfd, BCTRL, p - 4);
+
+  bfd_put_32 (obfd, LD_R11_0R1 + 32, p),       p += 4;
+  bfd_put_32 (obfd, LD_R2_0R1 + 40, p),                p += 4;
+  bfd_put_32 (obfd, MTLR_R11, p),              p += 4;
+  bfd_put_32 (obfd, BLR, p),                   p += 4;
+
+  return p;
+}
+
 static Elf_Internal_Rela *
 get_relocs (asection *sec, int count)
 {
@@ -8505,9 +9421,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;
@@ -8515,6 +9435,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 (_("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)
 {
@@ -8524,16 +9476,18 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   struct ppc_link_hash_table *htab;
   bfd_byte *loc;
   bfd_byte *p;
-  struct plt_entry *ent;
   bfd_vma dest, off;
   int size;
   Elf_Internal_Rela *r;
+  asection *plt;
 
   /* Massage our args to the form they really have.  */
   stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
   info = in_arg;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Make a note of the offset within the stubs for this entry.  */
   stub_entry->stub_offset = stub_entry->stub_sec->size;
@@ -8557,10 +9511,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;
@@ -8578,8 +9535,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 (_("long branch stub `%s' offset overflow\n"),
+                                 stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -8615,7 +9572,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
              hashes[symndx] = &h->elf;
              r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
              if (h->oh != NULL && h->oh->is_func)
-               h = h->oh;
+               h = ppc_follow_link (h->oh);
              if (h->elf.root.u.def.section != stub_entry->target_section)
                /* H is an opd symbol.  The addend must be zero.  */
                r->r_addend = 0;
@@ -8637,8 +9594,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 (_("can't find branch stub `%s'\n"),
+                                 stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -8698,8 +9655,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
+           (_("linkage table error against `%s'\n"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
@@ -8744,10 +9701,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;
@@ -8780,47 +9741,67 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       break;
 
     case ppc_stub_plt_call:
-      /* Do the best we can for shared libraries built without
-        exporting ".foo" for each "foo".  This can happen when symbol
-        versioning scripts strip all bar a subset of symbols.  */
-      if (stub_entry->h->oh != NULL
-         && stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
-         && stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
-       {
-         /* Point the symbol at the stub.  There may be multiple stubs,
-            we don't really care;  The main thing is to make this sym
-            defined somewhere.  Maybe defining the symbol in the stub
-            section is a silly idea.  If we didn't do this, htab->top_id
-            could disappear.  */
-         stub_entry->h->oh->elf.root.type = bfd_link_hash_defined;
-         stub_entry->h->oh->elf.root.u.def.section = stub_entry->stub_sec;
-         stub_entry->h->oh->elf.root.u.def.value = stub_entry->stub_offset;
+      if (stub_entry->h != NULL
+         && stub_entry->h->is_func_descriptor
+         && stub_entry->h->oh != NULL)
+       {
+         struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
+
+         /* If the old-ABI "dot-symbol" is undefined make it weak so
+            we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.
+            FIXME: We used to define the symbol on one of the call
+            stubs instead, which is why we test symbol section id
+            against htab->top_id in various places.  Likely all
+            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.  */
-      dest = (bfd_vma) -1;
-      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
-       if (ent->addend == stub_entry->addend)
-         {
-           dest = ent->plt.offset;
-           break;
-         }
+      dest = stub_entry->plt_ent->plt.offset & ~1;
       if (dest >= (bfd_vma) -2)
        abort ();
 
-      dest &= ~ (bfd_vma) 1;
-      dest += (htab->plt->output_offset
-              + htab->plt->output_section->vma);
+      plt = htab->plt;
+      if (!htab->elf.dynamic_sections_created
+         || stub_entry->h == NULL
+         || stub_entry->h->elf.dynindx == -1)
+       plt = htab->iplt;
+
+      dest += plt->output_offset + plt->output_section->vma;
+
+      if (stub_entry->h == NULL
+         && (stub_entry->plt_ent->plt.offset & 1) == 0)
+       {
+         Elf_Internal_Rela rela;
+         bfd_byte *rl;
+
+         rela.r_offset = dest;
+         rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+         rela.r_addend = (stub_entry->target_value
+                          + stub_entry->target_section->output_offset
+                          + stub_entry->target_section->output_section->vma);
+
+         rl = (htab->reliplt->contents
+               + (htab->reliplt->reloc_count++
+                  * sizeof (Elf64_External_Rela)));
+         bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
+         stub_entry->plt_ent->plt.offset |= 1;
+       }
 
       off = (dest
-            - elf_gp (htab->plt->output_section->owner)
+            - elf_gp (plt->output_section->owner)
             - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
-         (*_bfd_error_handler)
-           (_("linkage table error against `%s'"),
-            stub_entry->h->elf.root.root.string);
+         info->callbacks->einfo
+           (_("linkage table error against `%s'\n"),
+            stub_entry->h != NULL
+            ? stub_entry->h->elf.root.root.string
+            : "<local sym>");
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
          return FALSE;
@@ -8839,7 +9820,13 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            r[0].r_offset += 2;
          r[0].r_addend = dest;
        }
-      p = build_plt_stub (htab->stub_bfd, loc, off, r);
+      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)
+       p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r);
+      else
+       p = build_plt_stub (htab->stub_bfd, loc, off, r);
       size = p - loc;
       break;
 
@@ -8906,22 +9893,23 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   info = in_arg;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   if (stub_entry->stub_type == ppc_stub_plt_call)
     {
-      struct plt_entry *ent;
-      off = (bfd_vma) -1;
-      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
-       if (ent->addend == stub_entry->addend)
-         {
-           off = ent->plt.offset & ~(bfd_vma) 1;
-           break;
-         }
+      asection *plt;
+      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
       if (off >= (bfd_vma) -2)
        abort ();
-      off += (htab->plt->output_offset
-             + htab->plt->output_section->vma
-             - elf_gp (htab->plt->output_section->owner)
+      plt = htab->plt;
+      if (!htab->elf.dynamic_sections_created
+         || stub_entry->h == NULL
+         || stub_entry->h->elf.dynindx == -1)
+       plt = htab->iplt;
+      off += (plt->output_offset
+             + plt->output_section->vma
+             - elf_gp (plt->output_section->owner)
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
       size = PLT_CALL_STUB_SIZE;
@@ -8929,6 +9917,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        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;
       if (info->emitrelocations)
        {
          stub_entry->stub_sec->reloc_count
@@ -8957,8 +9950,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;
@@ -8975,8 +9972,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 (_("can't build branch stub `%s'\n"),
+                                     stub_entry->root.string);
              htab->stub_error = TRUE;
              return FALSE;
            }
@@ -9041,9 +10038,10 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
    0 when no stubs will be needed, and 1 on success.  */
 
 int
-ppc64_elf_setup_section_lists (bfd *output_bfd,
-                              struct bfd_link_info *info,
-                              int no_multi_toc)
+ppc64_elf_setup_section_lists
+  (struct bfd_link_info *info,
+   asection *(*add_stub_section) (const char *, asection *),
+   void (*layout_sections_again) (void))
 {
   bfd *input_bfd;
   int top_id, top_index, id;
@@ -9052,7 +10050,11 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   bfd_size_type amt;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  htab->no_multi_toc = no_multi_toc;
+  if (htab == NULL)
+    return -1;
+  /* Stash our params away.  */
+  htab->add_stub_section = add_stub_section;
+  htab->layout_sections_again = layout_sections_again;
 
   if (htab->brlt == NULL)
     return 0;
@@ -9081,12 +10083,10 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   for (id = 0; id < 3; id++)
     htab->stub_group[id].toc_off = TOC_BASE_OFF;
 
-  elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd);
-
   /* We can't use output_bfd->section_count here to find the top output
      section index as some sections may have been removed, and
      strip_excluded_output_sections doesn't renumber the indices.  */
-  for (section = output_bfd->sections, top_index = 0;
+  for (section = info->output_bfd->sections, top_index = 0;
        section != NULL;
        section = section->next)
     {
@@ -9104,41 +10104,308 @@ ppc64_elf_setup_section_lists (bfd *output_bfd,
   return 1;
 }
 
+/* Set up for first pass at multitoc partitioning.  */
+
+void
+ppc64_elf_start_multitoc_partition (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  elf_gp (info->output_bfd) = ppc64_elf_toc (info->output_bfd);
+  htab->toc_curr = elf_gp (info->output_bfd);
+  htab->toc_bfd = NULL;
+  htab->toc_first_sec = NULL;
+}
+
 /* The linker repeatedly calls this function for each TOC input section
    and linker generated GOT section.  Group input bfds such that the toc
-   within a group is less than 64k in size.  Will break with cute linker
-   scripts that play games with dot in the output toc section.  */
+   within a group is less than 64k in size.  */
 
-void
+bfd_boolean
 ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd_vma addr, off, limit;
 
-  if (!htab->no_multi_toc)
+  if (htab == NULL)
+    return FALSE;
+
+  if (!htab->second_toc_pass)
     {
-      bfd_vma addr = isec->output_offset + isec->output_section->vma;
-      bfd_vma off = addr - htab->toc_curr;
+      /* Keep track of the first .toc or .got section for this input bfd.  */
+      if (htab->toc_bfd != isec->owner)
+       {
+         htab->toc_bfd = isec->owner;
+         htab->toc_first_sec = isec;
+       }
 
-      if (off + isec->size > 0x10000)
-       htab->toc_curr = addr;
+      addr = isec->output_offset + isec->output_section->vma;
+      off = addr - htab->toc_curr;
+      limit = 0x80008000;
+      if (ppc64_elf_tdata (isec->owner)->has_small_toc_reloc)
+       limit = 0x10000;
+      if (off + isec->size > limit)
+       {
+         addr = (htab->toc_first_sec->output_offset
+                 + htab->toc_first_sec->output_section->vma);
+         htab->toc_curr = addr;
+       }
+
+      /* toc_curr is the base address of this toc group.  Set elf_gp
+        for the input section to be the offset relative to the
+        output toc base plus 0x8000.  Making the input elf_gp an
+        offset allows us to move the toc as a whole without
+        recalculating input elf_gp.  */
+      off = htab->toc_curr - elf_gp (isec->output_section->owner);
+      off += TOC_BASE_OFF;
 
-      elf_gp (isec->owner) = (htab->toc_curr
-                             - elf_gp (isec->output_section->owner)
-                             + TOC_BASE_OFF);
+      /* Die if someone uses a linker script that doesn't keep input
+        file .toc and .got together.  */
+      if (elf_gp (isec->owner) != 0
+         && elf_gp (isec->owner) != off)
+       return FALSE;
+
+      elf_gp (isec->owner) = off;
+      return TRUE;
+    }
+
+  /* During the second pass toc_first_sec points to the start of
+     a toc group, and toc_curr is used to track the old elf_gp.
+     We use toc_bfd to ensure we only look at each bfd once.  */
+  if (htab->toc_bfd == isec->owner)
+    return TRUE;
+  htab->toc_bfd = isec->owner;
+
+  if (htab->toc_first_sec == NULL
+      || htab->toc_curr != elf_gp (isec->owner))
+    {
+      htab->toc_curr = elf_gp (isec->owner);
+      htab->toc_first_sec = isec;
     }
+  addr = (htab->toc_first_sec->output_offset
+         + htab->toc_first_sec->output_section->vma);
+  off = addr - elf_gp (isec->output_section->owner) + TOC_BASE_OFF;
+  elf_gp (isec->owner) = off;
+
+  return TRUE;
 }
 
-/* Called after the last call to the above function.  */
+/* Called via elf_link_hash_traverse to merge GOT entries for global
+   symbol H.  */
 
-void
-ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info)
+static bfd_boolean
+merge_global_got (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
+{
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  merge_got_entries (&h->got.glist);
+
+  return TRUE;
+}
+
+/* Called via elf_link_hash_traverse to allocate GOT entries for global
+   symbol H.  */
+
+static bfd_boolean
+reallocate_got (struct elf_link_hash_entry *h, void *inf)
+{
+  struct got_entry *gent;
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return TRUE;
+
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (!gent->is_indirect)
+      allocate_got (h, (struct bfd_link_info *) inf, gent);
+  return TRUE;
+}
+
+/* Called on the first multitoc pass after the last call to
+   ppc64_elf_next_toc_section.  This function removes duplicate GOT
+   entries.  */
+
+bfd_boolean
+ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  struct bfd *ibfd, *ibfd2;
+  bfd_boolean done_something;
+
+  htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd);
+
+  if (!htab->do_multi_toc)
+    return FALSE;
+
+  /* Merge global sym got entries within a toc group.  */
+  elf_link_hash_traverse (&htab->elf, merge_global_got, info);
+
+  /* And tlsld_got.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry *ent, *ent2;
 
-  htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd);
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      ent = ppc64_tlsld_got (ibfd);
+      if (!ent->is_indirect
+         && ent->got.offset != (bfd_vma) -1)
+       {
+         for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next)
+           {
+             if (!is_ppc64_elf (ibfd2))
+               continue;
+
+             ent2 = ppc64_tlsld_got (ibfd2);
+             if (!ent2->is_indirect
+                 && ent2->got.offset != (bfd_vma) -1
+                 && elf_gp (ibfd2) == elf_gp (ibfd))
+               {
+                 ent2->is_indirect = TRUE;
+                 ent2->got.ent = ent;
+               }
+           }
+       }
+    }
+
+  /* Zap sizes of got sections.  */
+  htab->reliplt->rawsize = htab->reliplt->size;
+  htab->reliplt->size -= htab->got_reli_size;
+  htab->got_reli_size = 0;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      asection *got, *relgot;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      got = ppc64_elf_tdata (ibfd)->got;
+      if (got != NULL)
+       {
+         got->rawsize = got->size;
+         got->size = 0;
+         relgot = ppc64_elf_tdata (ibfd)->relgot;
+         relgot->rawsize = relgot->size;
+         relgot->size = 0;
+       }
+    }
+
+  /* Now reallocate the got, local syms first.  We don't need to
+     allocate section contents again since we never increase size.  */
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry **lgot_ents;
+      struct got_entry **end_lgot_ents;
+      struct plt_entry **local_plt;
+      struct plt_entry **end_local_plt;
+      unsigned char *lgot_masks;
+      bfd_size_type locsymcount;
+      Elf_Internal_Shdr *symtab_hdr;
+      asection *s, *srel;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
 
-  /* toc_curr tracks the TOC offset used for code sections below in
-     ppc64_elf_next_input_section.  Start off at 0x8000.  */
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      lgot_masks = (unsigned char *) end_local_plt;
+      s = ppc64_elf_tdata (ibfd)->got;
+      srel = ppc64_elf_tdata (ibfd)->relgot;
+      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
+       {
+         struct got_entry *ent;
+
+         for (ent = *lgot_ents; ent != NULL; ent = ent->next)
+           {
+             unsigned int num = 1;
+             ent->got.offset = s->size;
+             if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
+               num = 2;
+             s->size += num * 8;
+             if (info->shared)
+               srel->size += num * sizeof (Elf64_External_Rela);
+             else if ((*lgot_masks & PLT_IFUNC) != 0)
+               {
+                 htab->reliplt->size
+                   += num * sizeof (Elf64_External_Rela);
+                 htab->got_reli_size
+                   += num * sizeof (Elf64_External_Rela);
+               }
+           }
+       }
+    }
+
+  elf_link_hash_traverse (&htab->elf, reallocate_got, info);
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+    {
+      struct got_entry *ent;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      ent = ppc64_tlsld_got (ibfd);
+      if (!ent->is_indirect
+         && ent->got.offset != (bfd_vma) -1)
+       {
+         asection *s = ppc64_elf_tdata (ibfd)->got;
+         ent->got.offset = s->size;
+         s->size += 16;
+         if (info->shared)
+           {
+             asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+             srel->size += sizeof (Elf64_External_Rela);
+           }
+       }
+    }
+
+  done_something = htab->reliplt->rawsize != htab->reliplt->size;
+  if (!done_something)
+    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+      {
+       asection *got;
+
+       if (!is_ppc64_elf (ibfd))
+         continue;
+
+       got = ppc64_elf_tdata (ibfd)->got;
+       if (got != NULL)
+         {
+           done_something = got->rawsize != got->size;
+           if (done_something)
+             break;
+         }
+      }
+
+  if (done_something)
+    (*htab->layout_sections_again) ();
+
+  /* Set up for second pass over toc sections to recalculate elf_gp
+     on input sections.  */
+  htab->toc_bfd = NULL;
+  htab->toc_first_sec = NULL;
+  htab->second_toc_pass = TRUE;
+  return done_something;
+}
+
+/* Called after second pass of multitoc partitioning.  */
+
+void
+ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  /* 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;
 }
 
@@ -9153,10 +10420,10 @@ ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info)
 static int
 toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
 {
-  Elf_Internal_Rela *relstart, *rel;
-  Elf_Internal_Sym *local_syms;
   int ret;
-  struct ppc_link_hash_table *htab;
+
+  /* Mark this section as checked.  */
+  isec->call_check_done = 1;
 
   /* We know none of our code bearing sections will need toc stubs.  */
   if ((isec->flags & SEC_LINKER_CREATED) != 0)
@@ -9168,176 +10435,189 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
   if (isec->output_section == NULL)
     return 0;
 
-  if (isec->reloc_count == 0)
-    return 0;
-
-  relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
-                                       info->keep_memory);
-  if (relstart == NULL)
-    return -1;
-
-  /* Look for branches to outside of this section.  */
-  local_syms = NULL;
   ret = 0;
-  htab = ppc_hash_table (info);
-  for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
+  if (isec->reloc_count != 0)
     {
-      enum elf_ppc64_reloc_type r_type;
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
-      struct ppc_link_hash_entry *eh;
-      Elf_Internal_Sym *sym;
-      asection *sym_sec;
-      struct _opd_sec_data *opd;
-      bfd_vma sym_value;
-      bfd_vma dest;
-
-      r_type = ELF64_R_TYPE (rel->r_info);
-      if (r_type != R_PPC64_REL24
-         && r_type != R_PPC64_REL14
-         && r_type != R_PPC64_REL14_BRTAKEN
-         && r_type != R_PPC64_REL14_BRNTAKEN)
-       continue;
-
-      r_symndx = ELF64_R_SYM (rel->r_info);
-      if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx,
-                     isec->owner))
-       {
-         ret = -1;
-         break;
-       }
-
-      /* Calls to dynamic lib functions go through a plt call stub
-        that uses r2.  */
-      eh = (struct ppc_link_hash_entry *) h;
-      if (eh != NULL
-         && (eh->elf.plt.plist != NULL
-             || (eh->oh != NULL
-                 && 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;
 
-      /* If calling back to a section in the process of being tested, we
-        can't say for sure that no toc adjusting stubs are needed, so
-        don't return zero.  */
-      else if (sym_sec->call_check_in_progress)
-       ret = 2;
+                 adjust = opd->adjust[sym->st_value / 8];
+                 if (adjust == -1)
+                   /* Assume deleted functions won't ever be called.  */
+                   continue;
+                 sym_value += adjust;
+               }
 
-      /* Branches to another section that itself doesn't have any TOC
-        references are OK.  Recursively call ourselves to check.  */
-      else if (sym_sec->id <= htab->top_id
-              && htab->stub_group[sym_sec->id].toc_off == 0)
-       {
-         int recur;
+             dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
+             if (dest == (bfd_vma) -1)
+               continue;
+           }
+         else
+           dest = (sym_value
+                   + sym_sec->output_offset
+                   + sym_sec->output_section->vma);
 
-         /* Mark current section as indeterminate, so that other
-            sections that call back to current won't be marked as
-            known.  */
-         isec->call_check_in_progress = 1;
-         recur = toc_adjusting_stub_needed (info, sym_sec);
-         isec->call_check_in_progress = 0;
+         /* Ignore branch to self.  */
+         if (sym_sec == isec)
+           continue;
 
-         if (recur < 0)
+         /* If the called function uses the toc, we need a stub.  */
+         if (sym_sec->has_toc_reloc
+             || sym_sec->makes_toc_func_call)
            {
-             /* An error.  Exit.  */
-             ret = -1;
+             ret = 1;
              break;
            }
-         else if (recur <= 1)
+
+         /* Assume any branch that needs a long branch stub might in fact
+            need a plt_branch stub.  A plt_branch stub uses r2.  */
+         else if (dest - (isec->output_offset
+                          + isec->output_section->vma
+                          + rel->r_offset) + (1 << 25) >= (2 << 25))
            {
-             /* Known result.  Mark as checked and set section flag.  */
-             htab->stub_group[sym_sec->id].toc_off = 1;
+             ret = 1;
+             break;
+           }
+
+         /* If calling back to a section in the process of being
+            tested, we can't say for sure that no toc adjusting stubs
+            are needed, so don't return zero.  */
+         else if (sym_sec->call_check_in_progress)
+           ret = 2;
+
+         /* Branches to another section that itself doesn't have any TOC
+            references are OK.  Recursively call ourselves to check.  */
+         else if (!sym_sec->call_check_done)
+           {
+             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 (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 (ret == 1)
+    isec->makes_toc_func_call = 1;
 
   return ret;
 }
@@ -9352,6 +10632,9 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
+  if (htab == NULL)
+    return FALSE;
+
   if ((isec->output_section->flags & SEC_CODE) != 0
       && isec->output_section->index <= htab->top_index)
     {
@@ -9380,23 +10663,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.  */
-  htab->stub_group[isec->id].toc_off = htab->toc_curr;
+  /* Functions that don't use the TOC can belong in any TOC group.
+     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
@@ -9445,7 +10783,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"),
@@ -9454,7 +10793,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;
@@ -9487,7 +10827,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)
                {
@@ -9511,19 +10852,15 @@ group_sections (struct ppc_link_hash_table *htab,
    instruction.  */
 
 bfd_boolean
-ppc64_elf_size_stubs (bfd *output_bfd,
-                     struct bfd_link_info *info,
-                     bfd_signed_vma group_size,
-                     asection *(*add_stub_section) (const char *, asection *),
-                     void (*layout_sections_again) (void))
+ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size)
 {
   bfd_size_type stub_group_size;
   bfd_boolean stubs_always_before_branch;
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  /* Stash our params away.  */
-  htab->add_stub_section = add_stub_section;
-  htab->layout_sections_again = layout_sections_again;
+  if (htab == NULL)
+    return FALSE;
+
   stubs_always_before_branch = group_size < 0;
   if (group_size < 0)
     stub_group_size = -group_size;
@@ -9575,7 +10912,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
              /* If this section is a link-once section that will be
                 discarded, then don't create any stubs.  */
              if (section->output_section == NULL
-                 || section->output_section->owner != output_bfd)
+                 || section->output_section->owner != info->output_bfd)
                continue;
 
              /* Get the relocs.  */
@@ -9595,7 +10932,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                  enum ppc_stub_type stub_type;
                  struct ppc_stub_hash_entry *stub_entry;
                  asection *sym_sec, *code_sec;
-                 bfd_vma sym_value;
+                 bfd_vma sym_value, code_value;
                  bfd_vma destination;
                  bfd_boolean ok_dest;
                  struct ppc_link_hash_entry *hash;
@@ -9605,6 +10942,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                  char *stub_name;
                  const asection *id_sec;
                  struct _opd_sec_data *opd;
+                 struct plt_entry *plt_ent;
 
                  r_type = ELF64_R_TYPE (irela->r_info);
                  r_indx = ELF64_R_SYM (irela->r_info);
@@ -9651,7 +10989,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                         use the func descriptor sym instead if it is
                         defined.  */
                      if (hash->elf.root.root.string[0] == '.'
-                         && (fdh = get_fdh (hash, htab)) != NULL)
+                         && (fdh = lookup_fdh (hash, htab)) != NULL)
                        {
                          if (fdh->elf.root.type == bfd_link_hash_defined
                              || fdh->elf.root.type == bfd_link_hash_defweak)
@@ -9681,6 +11019,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                    }
 
                  code_sec = sym_sec;
+                 code_value = sym_value;
                  opd = get_opd_info (sym_sec);
                  if (opd != NULL)
                    {
@@ -9691,10 +11030,11 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                          long adjust = opd->adjust[sym_value / 8];
                          if (adjust == -1)
                            continue;
+                         code_value += adjust;
                          sym_value += adjust;
                        }
                      dest = opd_entry_value (sym_sec, sym_value,
-                                             &code_sec, &sym_value);
+                                             &code_sec, &code_value);
                      if (dest != (bfd_vma) -1)
                        {
                          destination = dest;
@@ -9704,14 +11044,15 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                                 entry.  */
                              hash->elf.root.type = bfd_link_hash_defweak;
                              hash->elf.root.u.def.section = code_sec;
-                             hash->elf.root.u.def.value = sym_value;
+                             hash->elf.root.u.def.value = code_value;
                            }
                        }
                    }
 
                  /* Determine what (if any) linker stub is needed.  */
+                 plt_ent = NULL;
                  stub_type = ppc_type_of_stub (section, irela, &hash,
-                                               destination);
+                                               &plt_ent, destination);
 
                  if (stub_type != ppc_stub_plt_call)
                    {
@@ -9742,9 +11083,9 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      && irela != internal_relocs)
                    {
                      /* Get tls info.  */
-                     char *tls_mask;
+                     unsigned char *tls_mask;
 
-                     if (!get_tls_mask (&tls_mask, NULL, &local_syms,
+                     if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
                                         irela - 1, input_bfd))
                        goto error_ret_free_internal;
                      if (*tls_mask != 0)
@@ -9768,7 +11109,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                      continue;
                    }
 
-                 stub_entry = ppc_add_stub (stub_name, section, htab);
+                 stub_entry = ppc_add_stub (stub_name, section, info);
                  if (stub_entry == NULL)
                    {
                      free (stub_name);
@@ -9784,9 +11125,18 @@ ppc64_elf_size_stubs (bfd *output_bfd,
                    }
 
                  stub_entry->stub_type = stub_type;
-                 stub_entry->target_value = sym_value;
-                 stub_entry->target_section = code_sec;
+                 if (stub_type != ppc_stub_plt_call)
+                   {
+                     stub_entry->target_value = code_value;
+                     stub_entry->target_section = code_sec;
+                   }
+                 else
+                   {
+                     stub_entry->target_value = sym_value;
+                     stub_entry->target_section = sym_sec;
+                   }
                  stub_entry->h = hash;
+                 stub_entry->plt_ent = plt_ent;
                  stub_entry->addend = irela->r_addend;
 
                  if (stub_entry->h != NULL)
@@ -9872,13 +11222,13 @@ ppc64_elf_toc (bfd *obfd)
   /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
      order.  The TOC starts where the first of these sections starts.  */
   s = bfd_get_section_by_name (obfd, ".got");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".toc");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".tocbss");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     s = bfd_get_section_by_name (obfd, ".plt");
-  if (s == NULL)
+  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
     {
       /* This may happen for
         o  references to TOC base (SYM@toc / TOC[tc0]) without a
@@ -9891,21 +11241,23 @@ ppc64_elf_toc (bfd *obfd)
       /* Look for a likely section.  We probably won't even be
         using TOCstart.  */
       for (s = obfd->sections; s != NULL; s = s->next)
-       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
+       if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY
+                        | SEC_EXCLUDE))
            == (SEC_ALLOC | SEC_SMALL_DATA))
          break;
       if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
-         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
+         if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE))
              == (SEC_ALLOC | SEC_SMALL_DATA))
            break;
       if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
-         if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
+         if ((s->flags & (SEC_ALLOC | SEC_READONLY | SEC_EXCLUDE))
+             == SEC_ALLOC)
            break;
       if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
-         if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
+         if ((s->flags & (SEC_ALLOC | SEC_EXCLUDE)) == SEC_ALLOC)
            break;
     }
 
@@ -9930,6 +11282,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
   bfd_byte *p;
   int stub_sec_count = 0;
 
+  if (htab == NULL)
+    return FALSE;
+
   htab->emit_stub_syms = emit_stub_syms;
 
   /* Allocate memory to hold the linker stubs.  */
@@ -10075,7 +11430,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       || htab->glink->rawsize != htab->glink->size)
     {
       htab->stub_error = TRUE;
-      (*_bfd_error_handler) (_("stubs don't match calculated size"));
+      info->callbacks->einfo (_("stubs don't match calculated size\n"));
     }
 
   if (htab->stub_error)
@@ -10114,9 +11469,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;
@@ -10129,7 +11481,9 @@ void
 ppc64_elf_restore_symbols (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
-  elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
+
+  if (htab != NULL)
+    elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info);
 }
 
 /* What to do when ld finds relocations against symbols defined in
@@ -10150,6 +11504,63 @@ ppc64_elf_action_discarded (asection *sec)
   return _bfd_elf_default_action_discarded (sec);
 }
 
+/* REL points to a low-part reloc on a largetoc instruction sequence.
+   Find the matching high-part reloc instruction and verify that it
+   is addis REG,x,imm.  If so, set *REG to x and return a pointer to
+   the high-part reloc.  */
+
+static const Elf_Internal_Rela *
+ha_reloc_match (const Elf_Internal_Rela *relocs,
+               const Elf_Internal_Rela *rel,
+               unsigned int *reg,
+               bfd_boolean match_addend,
+               const bfd *input_bfd,
+               const bfd_byte *contents)
+{
+  enum elf_ppc64_reloc_type r_type, r_type_ha;
+  bfd_vma r_info_ha, r_addend;
+
+  r_type = ELF64_R_TYPE (rel->r_info);
+  switch (r_type)
+    {
+    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_TOC16_LO:
+      r_type_ha = r_type + 2;
+      break;
+    case R_PPC64_GOT16_LO_DS:
+      r_type_ha = R_PPC64_GOT16_HA;
+      break;
+    case R_PPC64_TOC16_LO_DS:
+      r_type_ha = R_PPC64_TOC16_HA;
+      break;
+    default:
+      abort ();
+    }
+  r_info_ha = ELF64_R_INFO (ELF64_R_SYM (rel->r_info), r_type_ha);
+  r_addend = rel->r_addend;
+
+  while (--rel >= relocs)
+    if (rel->r_info == r_info_ha
+       && (!match_addend
+           || rel->r_addend == r_addend))
+      {
+       const bfd_byte *p = contents + (rel->r_offset & ~3);
+       unsigned int insn = bfd_get_32 (input_bfd, p);
+       if ((insn & (0x3f << 26)) == (15u << 26) /* addis rt,x,imm */
+           && (insn & (0x1f << 21)) == (*reg << 21))
+         {
+           *reg = (insn >> 16) & 0x1f;
+           return rel;
+         }
+       break;
+      }
+  return NULL;
+}
+
 /* The RELOCATE_SECTION function is called by the ELF backend linker
    to handle the relocations for a section.
 
@@ -10197,7 +11608,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Rela outrel;
   bfd_byte *loc;
   struct got_entry **local_got_ents;
+  unsigned char *ha_opt;
   bfd_vma TOCstart;
+  bfd_boolean no_ha_opt;
   bfd_boolean ret = TRUE;
   bfd_boolean is_opd;
   /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
@@ -10209,6 +11622,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
     ppc_howto_init ();
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   /* Don't relocate stub sections.  */
   if (input_section->owner == htab->stub_bfd)
@@ -10221,6 +11636,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   symtab_hdr = &elf_symtab_hdr (input_bfd);
   sym_hashes = elf_sym_hashes (input_bfd);
   is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
+  ha_opt = NULL;
+  no_ha_opt = FALSE;
 
   rel = relocs;
   relend = relocs + input_section->reloc_count;
@@ -10236,12 +11653,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       struct ppc_link_hash_entry *fdh;
       const char *sym_name;
       unsigned long r_symndx, toc_symndx;
-      char tls_mask, tls_gd, tls_type;
-      char sym_type;
+      bfd_vma toc_addend;
+      unsigned char tls_mask, tls_gd, tls_type;
+      unsigned char sym_type;
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
-      unsigned long insn, mask;
+      unsigned int insn;
+      unsigned int mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
@@ -10308,16 +11727,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       h = (struct ppc_link_hash_entry *) h_elf;
 
       if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd,
-                              contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+       RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                        rel, relend,
+                                        ppc64_elf_howto_table[r_type],
+                                        contents);
 
       if (info->relocatable)
        continue;
@@ -10329,33 +11742,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       tls_mask = 0;
       tls_gd = 0;
       toc_symndx = 0;
-      if (IS_PPC64_TLS_RELOC (r_type))
+      if (h != NULL)
+       tls_mask = h->tls_mask;
+      else if (local_got_ents != NULL)
        {
-         if (h != NULL)
-           tls_mask = h->tls_mask;
-         else if (local_got_ents != NULL)
-           {
-             char *lgot_masks;
-             lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
-             tls_mask = lgot_masks[r_symndx];
-           }
-         if (tls_mask == 0 && r_type == R_PPC64_TLS)
-           {
-             /* Check for toc tls entries.  */
-             char *toc_tls;
+         struct plt_entry **local_plt = (struct plt_entry **)
+           (local_got_ents + symtab_hdr->sh_info);
+         unsigned char *lgot_masks = (unsigned char *)
+           (local_plt + symtab_hdr->sh_info);
+         tls_mask = lgot_masks[r_symndx];
+       }
+      if (tls_mask == 0
+         && (r_type == R_PPC64_TLS
+             || r_type == R_PPC64_TLSGD
+             || r_type == R_PPC64_TLSLD))
+       {
+         /* Check for toc tls entries.  */
+         unsigned char *toc_tls;
 
-             if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-                                rel, input_bfd))
-               return FALSE;
+         if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                            &local_syms, rel, input_bfd))
+           return FALSE;
 
-             if (toc_tls)
-               tls_mask = *toc_tls;
-           }
+         if (toc_tls)
+           tls_mask = *toc_tls;
        }
 
       /* 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
@@ -10365,17 +11780,18 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || (sym_type == STT_SECTION
                      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
        {
-         if (r_type == R_PPC64_TLS && tls_mask != 0)
+         if (tls_mask != 0
+             && (r_type == R_PPC64_TLS
+                 || r_type == R_PPC64_TLSGD
+                 || r_type == R_PPC64_TLSLD))
            /* 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,
+              ? _("%H: %s used with TLS symbol %s\n")
+              : _("%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);
        }
@@ -10398,17 +11814,27 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        default:
          break;
 
+       case R_PPC64_LO_DS_OPT:
+         insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+         if ((insn & (0x3f << 26)) != 58u << 26)
+           abort ();
+         insn += (14u << 26) - (58u << 26);
+         bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+         r_type = R_PPC64_TOC16_LO;
+         rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+         break;
+
        case R_PPC64_TOC16:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_DS:
        case R_PPC64_TOC16_LO_DS:
          {
            /* Check for toc tls entries.  */
-           char *toc_tls;
+           unsigned char *toc_tls;
            int retval;
 
-           retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-                                  rel, input_bfd);
+           retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+                                  &local_syms, rel, input_bfd);
            if (retval == 0)
              return FALSE;
 
@@ -10442,6 +11868,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
@@ -10456,6 +11894,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (toc_symndx != 0)
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+                 rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                  rel--;
@@ -10470,37 +11909,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
-             bfd_vma rtra;
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
-             if ((insn & ((0x3f << 26) | (31 << 11)))
-                 == ((31 << 26) | (13 << 11)))
-               rtra = insn & ((1 << 26) - (1 << 16));
-             else if ((insn & ((0x3f << 26) | (31 << 16)))
-                      == ((31 << 26) | (13 << 16)))
-               rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
-             else
+             insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
+             if (insn == 0)
                abort ();
-             if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1)
-               /* add -> addi.  */
-               insn = 14 << 26;
-             else if ((insn & (31 << 1)) == 23 << 1
-                      && ((insn & (31 << 6)) < 14 << 6
-                          || ((insn & (31 << 6)) >= 16 << 6
-                              && (insn & (31 << 6)) < 24 << 6)))
-               /* load and store indexed -> dform.  */
-               insn = (32 | ((insn >> 6) & 31)) << 26;
-             else if ((insn & (31 << 1)) == 21 << 1
-                      && (insn & (0x1a << 6)) == 0)
-               /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
-               insn = (((58 | ((insn >> 6) & 4)) << 26)
-                       | ((insn >> 6) & 1));
-             else if ((insn & (31 << 1)) == 21 << 1
-                      && (insn & ((1 << 11) - (1 << 1))) == 341 << 1)
-               /* lwax -> lwa.  */
-               insn = (58 << 26) | 2;
-             else
-               abort ();
-             insn |= rtra;
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              /* Was PPC64_TLS which sits on insn boundary, now
                 PPC64_TPREL16_LO which is at low-order half-word.  */
@@ -10509,6 +11921,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              if (toc_symndx != 0)
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+                 rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                  rel--;
@@ -10536,8 +11949,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);
@@ -10555,25 +11968,32 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSLD16_LO:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
            {
-             bfd_vma insn1, insn2, insn3;
+             unsigned int insn1, insn2, insn3;
              bfd_vma offset;
 
            tls_ldgd_opt:
-             /* We know that the next reloc is on a tls_get_addr
-                call, since ppc64_elf_tls_optimize checks this.  */
-             offset = rel[1].r_offset;
-             insn1 = bfd_get_32 (output_bfd,
-                                 contents + rel->r_offset - d_offset);
-             insn3 = bfd_get_32 (output_bfd,
-                                 contents + offset + 4);
+             offset = (bfd_vma) -1;
+             /* If not using the newer R_PPC64_TLSGD/LD to mark
+                __tls_get_addr calls, we must trust that the call
+                stays with its arg setup insns, ie. that the next
+                reloc is the __tls_get_addr call associated with
+                the current reloc.  Edit both insns.  */
+             if (input_section->has_tls_get_addr_call
+                 && rel + 1 < relend
+                 && branch_reloc_hash_match (input_bfd, rel + 1,
+                                             htab->tls_get_addr,
+                                             htab->tls_get_addr_fd))
+               offset = rel[1].r_offset;
              if ((tls_mask & tls_gd) != 0)
                {
                  /* IE */
+                 insn1 = bfd_get_32 (output_bfd,
+                                     contents + rel->r_offset - d_offset);
                  insn1 &= (1 << 26) - (1 << 2);
                  insn1 |= 58 << 26;    /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
-                 rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
-                                               R_PPC64_NONE);
+                 if (offset != (bfd_vma) -1)
+                   rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
                  if ((tls_mask & TLS_EXPLICIT) == 0)
                    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
                              + R_PPC64_GOT_TPREL16_DS);
@@ -10597,43 +12017,143 @@ 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);
-                     rel[1].r_addend = rel->r_addend;
                    }
                  else if (toc_symndx != 0)
-                   r_symndx = toc_symndx;
+                   {
+                     r_symndx = toc_symndx;
+                     rel->r_addend = toc_addend;
+                   }
                  r_type = R_PPC64_TPREL16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-                 rel[1].r_info = ELF64_R_INFO (r_symndx,
-                                               R_PPC64_TPREL16_LO);
-                 rel[1].r_offset += d_offset;
+                 if (offset != (bfd_vma) -1)
+                   {
+                     rel[1].r_info = ELF64_R_INFO (r_symndx,
+                                                   R_PPC64_TPREL16_LO);
+                     rel[1].r_offset = offset + d_offset;
+                     rel[1].r_addend = rel->r_addend;
+                   }
                }
+             bfd_put_32 (output_bfd, insn1,
+                         contents + rel->r_offset - d_offset);
+             if (offset != (bfd_vma) -1)
+               {
+                 insn3 = bfd_get_32 (output_bfd,
+                                     contents + offset + 4);
+                 if (insn3 == NOP
+                     || insn3 == CROR_151515 || insn3 == CROR_313131)
+                   {
+                     rel[1].r_offset += 4;
+                     bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                     insn2 = NOP;
+                   }
+                 bfd_put_32 (output_bfd, insn2, contents + offset);
+               }
+             if ((tls_mask & tls_gd) == 0
+                 && (tls_gd == 0 || toc_symndx != 0))
+               {
+                 /* We changed the symbol.  Start over in order
+                    to get h, sym, sec etc. right.  */
+                 rel--;
+                 continue;
+               }
+           }
+         break;
+
+       case R_PPC64_TLSGD:
+         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if ((tls_mask & TLS_TPRELGD) != 0)
+               {
+                 /* IE */
+                 r_type = R_PPC64_NONE;
+                 insn2 = 0x7c636a14;   /* add 3,3,13 */
+               }
+             else
+               {
+                 /* LE */
+                 if (toc_symndx != 0)
+                   {
+                     r_symndx = toc_symndx;
+                     rel->r_addend = toc_addend;
+                   }
+                 r_type = R_PPC64_TPREL16_LO;
+                 rel->r_offset = offset + d_offset;
+                 insn2 = 0x38630000;   /* addi 3,3,0 */
+               }
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
-                 insn3 = insn2;
+                 rel->r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
                  insn2 = NOP;
-                 rel[1].r_offset += 4;
                }
-             bfd_put_32 (output_bfd, insn1,
-                         contents + rel->r_offset - d_offset);
              bfd_put_32 (output_bfd, insn2, contents + offset);
-             bfd_put_32 (output_bfd, insn3, contents + offset + 4);
-             if (tls_gd == 0 || toc_symndx != 0)
+             if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
                {
-                 /* We changed the symbol.  Start over in order
-                    to get h, sym, sec etc. right.  */
                  rel--;
                  continue;
                }
            }
          break;
 
+       case R_PPC64_TLSLD:
+         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+           {
+             unsigned int insn2, insn3;
+             bfd_vma offset = rel->r_offset;
+
+             if (toc_symndx)
+               sec = local_sections[toc_symndx];
+             for (r_symndx = 0;
+                  r_symndx < symtab_hdr->sh_info;
+                  r_symndx++)
+               if (local_sections[r_symndx] == sec)
+                 break;
+             if (r_symndx >= symtab_hdr->sh_info)
+               r_symndx = STN_UNDEF;
+             rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+             if (r_symndx != STN_UNDEF)
+               rel->r_addend -= (local_syms[r_symndx].st_value
+                                 + sec->output_offset
+                                 + sec->output_section->vma);
+
+             r_type = R_PPC64_TPREL16_LO;
+             rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+             rel->r_offset = offset + d_offset;
+             /* Zap the reloc on the _tls_get_addr call too.  */
+             BFD_ASSERT (offset == rel[1].r_offset);
+             rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+             insn2 = 0x38630000;       /* addi 3,3,0 */
+             insn3 = bfd_get_32 (output_bfd,
+                                 contents + offset + 4);
+             if (insn3 == NOP
+                 || insn3 == CROR_151515 || insn3 == CROR_313131)
+               {
+                 rel->r_offset += 4;
+                 bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+                 insn2 = NOP;
+               }
+             bfd_put_32 (output_bfd, insn2, contents + offset);
+             rel--;
+             continue;
+           }
+         break;
+
        case R_PPC64_DTPMOD64:
          if (rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
@@ -10705,19 +12225,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             linkage stubs needs to be followed by a nop, as the nop
             will be replaced with an instruction to restore the TOC
             base pointer.  */
-         stub_entry = NULL;
          fdh = h;
-         if (((h != NULL
-               && (((fdh = h->oh) != NULL
-                    && fdh->elf.plt.plist != NULL)
-                   || (fdh = h)->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)))
-             && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
-                                                  rel, htab)) != NULL
+         if (h != NULL
+             && h->oh != NULL
+             && h->oh->is_func_descriptor)
+           fdh = ppc_follow_link (h->oh);
+         stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
+         if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
                  || stub_entry->stub_type == ppc_stub_long_branch_r2off))
@@ -10731,8 +12245,16 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  if (nop == NOP
                      || nop == CROR_151515 || nop == CROR_313131)
                    {
-                     bfd_put_32 (input_bfd, LD_R2_40R1,
-                                 contents + rel->r_offset + 4);
+                     if (h != NULL
+                         && (h == htab->tls_get_addr_fd
+                             || h == htab->tls_get_addr)
+                         && !htab->no_tls_get_addr_opt)
+                       {
+                         /* Special stub used, leave nop alone.  */
+                       }
+                     else
+                       bfd_put_32 (input_bfd, LD_R2_40R1,
+                                   contents + rel->r_offset + 4);
                      can_plt_call = TRUE;
                    }
                }
@@ -10765,23 +12287,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
+                         (_("%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
+                         (_("%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);
@@ -10794,7 +12312,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                unresolved_reloc = FALSE;
            }
 
-         if (stub_entry == NULL
+         if ((stub_entry == NULL
+              || stub_entry->stub_type == ppc_stub_long_branch
+              || stub_entry->stub_type == ppc_stub_plt_branch)
              && get_opd_info (sec) != NULL)
            {
              /* The branch destination is the value of the opd entry. */
@@ -10815,13 +12335,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  + input_section->output_offset
                  + input_section->output_section->vma);
 
-         if (stub_entry == NULL
-             && (relocation + addend - from + max_br_offset
-                 >= 2 * max_br_offset)
-             && r_type != R_PPC64_ADDR14_BRTAKEN
-             && r_type != R_PPC64_ADDR14_BRNTAKEN)
-           stub_entry = ppc_get_stub_entry (input_section, sec, h, rel,
-                                            htab);
+         if (stub_entry != NULL
+             && (stub_entry->stub_type == ppc_stub_long_branch
+                 || stub_entry->stub_type == ppc_stub_plt_branch)
+             && (r_type == R_PPC64_ADDR14_BRTAKEN
+                 || r_type == R_PPC64_ADDR14_BRNTAKEN
+                 || (relocation + addend - from + max_br_offset
+                     < 2 * max_br_offset)))
+           /* Don't use the stub if this branch is in range.  */
+           stub_entry = NULL;
 
          if (stub_entry != NULL)
            {
@@ -10862,6 +12384,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             checking whether the function is defined.  */
          else if (h != NULL
                   && h->elf.root.type == bfd_link_hash_undefweak
+                  && h->elf.dynindx == -1
                   && r_type == R_PPC64_REL24
                   && relocation == 0
                   && addend == 0)
@@ -10877,8 +12400,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
+           (_("%B: unknown relocation type %d for symbol %s\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
@@ -10887,6 +12410,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_NONE:
        case R_PPC64_TLS:
+       case R_PPC64_TLSGD:
+       case R_PPC64_TLSLD:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
          continue;
@@ -10937,14 +12462,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            bfd_vma *offp;
            bfd_vma off;
            unsigned long indx = 0;
+           struct got_entry *ent;
 
            if (tls_type == (TLS_TLS | TLS_LD)
                && (h == NULL
                    || !h->elf.def_dynamic))
-             offp = &ppc64_tlsld_got (input_bfd)->offset;
+             ent = ppc64_tlsld_got (input_bfd);
            else
              {
-               struct got_entry *ent;
 
                if (h != NULL)
                  {
@@ -10952,7 +12477,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
@@ -10977,12 +12502,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      && ent->owner == input_bfd
                      && ent->tls_type == tls_type)
                    break;
-               if (ent == NULL)
-                 abort ();
-               offp = &ent->got.offset;
              }
 
-           got = ppc64_elf_tdata (input_bfd)->got;
+           if (ent == NULL)
+             abort ();
+           if (ent->is_indirect)
+             ent = ent->got.ent;
+           offp = &ent->got.offset;
+           got = ppc64_elf_tdata (ent->owner)->got;
            if (got == NULL)
              abort ();
 
@@ -10997,13 +12524,24 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                /* Generate relocs for the dynamic linker, except in
                   the case of TLSLD where we'll use one entry per
                   module.  */
-               asection *relgot = ppc64_elf_tdata (input_bfd)->relgot;
+               asection *relgot;
+               bfd_boolean ifunc;
 
                *offp = off | 1;
+               relgot = NULL;
+               ifunc = (h != NULL
+                        ? h->elf.type == STT_GNU_IFUNC
+                        : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if ((info->shared || indx != 0)
                    && (h == NULL
+                       || (tls_type == (TLS_TLS | TLS_LD)
+                           && !h->elf.def_dynamic)
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || h->elf.root.type != bfd_link_hash_undefweak))
+                 relgot = ppc64_elf_tdata (ent->owner)->relgot;
+               else if (ifunc)
+                 relgot = htab->reliplt;
+               if (relgot != NULL)
                  {
                    outrel.r_offset = (got->output_section->vma
                                       + got->output_offset
@@ -11030,9 +12568,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
                    else if (tls_type == (TLS_TLS | TLS_TPREL))
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
-                   else if (indx == 0)
+                   else if (indx != 0)
+                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
+                   else
                      {
-                       outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE);
+                       if (ifunc)
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+                       else
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
                        /* Write the .got section contents for the sake
                           of prelink.  */
@@ -11040,8 +12583,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                        bfd_put_64 (output_bfd, outrel.r_addend + relocation,
                                    loc);
                      }
-                   else
-                     outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
 
                    if (indx == 0 && tls_type != (TLS_TLS | TLS_LD))
                      {
@@ -11084,10 +12625,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            if (off >= (bfd_vma) -2)
              abort ();
 
-           relocation = got->output_offset + off;
-
-           /* TOC base (r2) is TOC start plus 0x8000.  */
-           addend = -TOC_BASE_OFF;
+           relocation = got->output_section->vma + got->output_offset + off;
+           addend = -(TOCstart + htab->stub_group[input_section->id].toc_off);
          }
          break;
 
@@ -11126,7 +12665,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)
            ;
@@ -11160,6 +12699,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            addend -= sec->output_section->vma;
          break;
 
+       case R_PPC64_REL16:
+       case R_PPC64_REL16_LO:
+       case R_PPC64_REL16_HI:
+       case R_PPC64_REL16_HA:
+         break;
+
        case R_PPC64_REL14:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
@@ -11176,6 +12721,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
+         if (h != NULL
+             && h->elf.root.type == bfd_link_hash_undefweak
+             && h->elf.dynindx == -1)
+           {
+             /* Make this relocation against an undefined weak symbol
+                resolve to zero.  This is really just a tweak, since
+                code using weak externs ought to check that they are
+                defined before using them.  */
+             bfd_byte *p = contents + rel->r_offset - d_offset;
+
+             insn = bfd_get_32 (output_bfd, p);
+             insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
+             if (insn != 0)
+               bfd_put_32 (output_bfd, insn, p);
+             break;
+           }
          addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          if (info->shared)
            /* The TPREL16 relocs shouldn't really be used in shared
@@ -11252,12 +12813,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  && h != NULL
                  && h->elf.dynindx != -1
                  && !h->elf.non_got_ref
-                 && !h->elf.def_regular))
+                 && !h->elf.def_regular)
+             || (!info->shared
+                 && (h != NULL
+                     ? h->elf.type == STT_GNU_IFUNC
+                     : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
            {
-             Elf_Internal_Rela outrel;
              bfd_boolean skip, relocate;
              asection *sreloc;
-             bfd_byte *loc;
              bfd_vma out_off;
 
              /* When generating a dynamic object, these relocations
@@ -11291,7 +12854,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (skip)
                memset (&outrel, 0, sizeof outrel);
-             else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
+             else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
                outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
@@ -11317,19 +12880,40 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                             entry in this lib.  */
                          unresolved_reloc = FALSE;
                        }
-                     outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                     if (!is_opd
+                         && r_type == R_PPC64_ADDR64
+                         && (h != NULL
+                             ? h->elf.type == STT_GNU_IFUNC
+                             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
+                       outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+                     else
+                       {
+                         outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
-                     /* We need to relocate .opd contents for ld.so.
-                        Prelink also wants simple and consistent rules
-                        for relocs.  This make all RELATIVE relocs have
-                        *r_offset equal to r_addend.  */
-                     relocate = TRUE;
+                         /* We need to relocate .opd contents for ld.so.
+                            Prelink also wants simple and consistent rules
+                            for relocs.  This make all RELATIVE relocs have
+                            *r_offset equal to r_addend.  */
+                         relocate = TRUE;
+                       }
                    }
                  else
                    {
                      long indx = 0;
 
-                     if (r_symndx == 0 || bfd_is_abs_section (sec))
+                     if (h != NULL
+                         ? h->elf.type == STT_GNU_IFUNC
+                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                       {
+                         info->callbacks->einfo
+                           (_("%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 == STN_UNDEF || bfd_is_abs_section (sec))
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                        {
@@ -11367,6 +12951,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              sreloc = elf_section_data (input_section)->sreloc;
+             if (!htab->elf.dynamic_sections_created)
+               sreloc = htab->reliplt;
              if (sreloc == NULL)
                abort ();
 
@@ -11408,6 +12994,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_COPY:
        case R_PPC64_GLOB_DAT:
        case R_PPC64_JMP_SLOT:
+       case R_PPC64_JMP_IREL:
        case R_PPC64_RELATIVE:
          /* We shouldn't ever see these dynamic relocs in relocatable
             files.  */
@@ -11423,8 +13010,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
+           (_("%B: relocation %s is not supported for symbol %s\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
@@ -11433,6 +13020,100 @@ 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:
+         /* nop is done later.  */
+         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)
+           {
+             bfd_byte *p = contents + (rel->r_offset & ~3);
+             insn = bfd_get_32 (input_bfd, p);
+             if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+                 || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+                 || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+                 || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+                 || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+                 || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+                 || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+                 || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+                 || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+                 || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+                 || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+                 || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+                 || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+                 || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+                 || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+                     && (insn & 3) != 1)
+                 || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+                     && ((insn & 3) == 0 || (insn & 3) == 3)))
+               {
+                 unsigned int reg = (insn >> 16) & 0x1f;
+                 const Elf_Internal_Rela *ha;
+                 bfd_boolean match_addend;
+
+                 match_addend = (sym != NULL
+                                 && ELF_ST_TYPE (sym->st_info) == STT_SECTION);
+                 ha = ha_reloc_match (relocs, rel, &reg, match_addend,
+                                      input_bfd, contents);
+                 if (ha != NULL)
+                   {
+                     insn &= ~(0x1f << 16);
+                     insn |= reg << 16;
+                     bfd_put_32 (input_bfd, insn, p);
+                     if (ha_opt == NULL)
+                       {
+                         ha_opt = bfd_zmalloc (input_section->reloc_count);
+                         if (ha_opt == NULL)
+                           return FALSE;
+                       }
+                     ha_opt[ha - relocs] = 1;
+                   }
+                 else
+                   /* If we don't find a matching high part insn,
+                      something is fishy.  Refuse to nop any high
+                      part insn in this section.  */
+                   no_ha_opt = TRUE;
+               }
+           }
+         break;
+       }
+
       /* Do any further special processing.  */
       switch (r_type)
        {
@@ -11440,6 +13121,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_ADDR16_HA:
+       case R_PPC64_REL16_HA:
        case R_PPC64_ADDR16_HIGHERA:
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_TOC16_HA:
@@ -11505,9 +13187,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
+               (_("%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);
@@ -11524,11 +13206,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->elf.def_dynamic))
        {
-         (*_bfd_error_handler)
-           (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
-            input_bfd,
-            input_section,
-            (long) rel->r_offset,
+         info->callbacks->einfo
+           (_("%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;
@@ -11571,11 +13251,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            }
          else
            {
-             (*_bfd_error_handler)
-               (_("%B(%A+0x%lx): %s reloc against `%s': error %d"),
-                input_bfd,
-                input_section,
-                (long) rel->r_offset,
+             info->callbacks->einfo
+               (_("%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);
@@ -11584,6 +13262,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        }
     }
 
+  if (ha_opt != NULL)
+    {
+      if (!no_ha_opt)
+       {
+         unsigned char *opt = ha_opt;
+         rel = relocs;
+         relend = relocs + input_section->reloc_count;
+         for (; rel < relend; opt++, rel++)
+           if (*opt != 0)
+             {
+               bfd_byte *p = contents + (rel->r_offset & ~3);
+               bfd_put_32 (input_bfd, NOP, p);
+             }
+       }
+      free (ha_opt);
+    }
+
   /* If we're emitting relocations, then shortly after this function
      returns, reloc offsets and addends for this section will be
      adjusted.  Worse, reloc symbol indices will be for the output
@@ -11605,7 +13300,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
 /* Adjust the value of any local symbols in opd sections.  */
 
-static bfd_boolean
+static int
 ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
                              const char *name ATTRIBUTE_UNUSED,
                              Elf_Internal_Sym *elfsym,
@@ -11617,11 +13312,11 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
   bfd_vma value;
 
   if (h != NULL)
-    return TRUE;
+    return 1;
 
   opd = get_opd_info (input_sec);
   if (opd == NULL || opd->adjust == NULL)
-    return TRUE;
+    return 1;
 
   value = elfsym->st_value - input_sec->output_offset;
   if (!info->relocatable)
@@ -11629,10 +13324,10 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
 
   adjust = opd->adjust[value / 8];
   if (adjust == -1)
-    elfsym->st_value = 0;
-  else
-    elfsym->st_value += adjust;
-  return TRUE;
+    return 2;
+
+  elfsym->st_value += adjust;
+  return 1;
 }
 
 /* Finish up dynamic symbol handling.  We set the contents of various
@@ -11650,37 +13345,49 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
   bfd_byte *loc;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
 
   for (ent = h->plt.plist; ent != NULL; ent = ent->next)
     if (ent->plt.offset != (bfd_vma) -1)
       {
        /* This symbol has an entry in the procedure linkage
           table.  Set it up.  */
-
-       if (htab->plt == NULL
-           || htab->relplt == NULL
-           || htab->glink == NULL)
-         abort ();
-
-       /* Create a JMP_SLOT reloc to inform the dynamic linker to
-          fill in the PLT entry.  */
-       rela.r_offset = (htab->plt->output_section->vma
-                        + htab->plt->output_offset
-                        + ent->plt.offset);
-       rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-       rela.r_addend = ent->addend;
-
-       loc = htab->relplt->contents;
-       loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
-               * sizeof (Elf64_External_Rela));
+       if (!htab->elf.dynamic_sections_created
+           || h->dynindx == -1)
+         {
+           BFD_ASSERT (h->type == STT_GNU_IFUNC
+                       && h->def_regular
+                       && (h->root.type == bfd_link_hash_defined
+                           || h->root.type == bfd_link_hash_defweak));
+           rela.r_offset = (htab->iplt->output_section->vma
+                            + htab->iplt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+           rela.r_addend = (h->root.u.def.value
+                            + h->root.u.def.section->output_offset
+                            + h->root.u.def.section->output_section->vma
+                            + ent->addend);
+           loc = (htab->reliplt->contents
+                  + (htab->reliplt->reloc_count++
+                     * sizeof (Elf64_External_Rela)));
+         }
+       else
+         {
+           rela.r_offset = (htab->plt->output_section->vma
+                            + htab->plt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+           rela.r_addend = ent->addend;
+           loc = (htab->relplt->contents
+                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
+                     / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
+         }
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
       }
 
   if (h->needs_copy)
     {
-      Elf_Internal_Rela rela;
-      bfd_byte *loc;
-
       /* This symbol needs a copy reloc.  Set it up.  */
 
       if (h->dynindx == -1
@@ -11739,6 +13446,9 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
   asection *sdyn;
 
   htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   dynobj = htab->elf.dynobj;
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
@@ -11852,7 +13562,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;
@@ -11861,7 +13571,7 @@ 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;
This page took 0.103909 seconds and 4 git commands to generate.