Return unique_xmalloc_ptr for generate_c_for_variable_locations
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index b2d288bd4e77e7e576523643efa410585babc695..c9ac8e9aace7db5dfd2a61dc503bf2e97bb66e11 100644 (file)
@@ -64,7 +64,8 @@ static bfd_vma opd_entry_value
 #define ELF_TARGET_ID          PPC64_ELF_DATA
 #define ELF_MACHINE_CODE       EM_PPC64
 #define ELF_MAXPAGESIZE                0x10000
-#define ELF_COMMONPAGESIZE     0x10000
+#define ELF_COMMONPAGESIZE     0x1000
+#define ELF_RELROPAGESIZE      ELF_MAXPAGESIZE
 #define elf_info_to_howto      ppc64_elf_info_to_howto
 
 #define elf_backend_want_got_sym 0
@@ -129,6 +130,7 @@ static bfd_vma opd_entry_value
 
 /* The size in bytes of an entry in the procedure linkage table.  */
 #define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8)
+#define LOCAL_PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 16 : 8)
 
 /* The initial size of the plt reserved for the dynamic linker.  */
 #define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16)
@@ -161,11 +163,9 @@ static bfd_vma opd_entry_value
 #define LD_R11_0R11    0xe96b0000      /* ld    %r11,xxx+16@l(%r11) */
 #define BCTR           0x4e800420      /* bctr                      */
 
-#define CRSETEQ                0x4c421242      /* crset 4*%cr0+%eq      */
-#define BEQCTRM                0x4dc20420      /* beqctr-               */
-#define BEQCTRLM       0x4dc20421      /* beqctrl-              */
-
 #define ADDI_R11_R11   0x396b0000      /* addi %r11,%r11,off@l  */
+#define ADDI_R12_R11   0x398b0000      /* addi %r12,%r11,off@l  */
+#define ADDI_R12_R12   0x398c0000      /* addi %r12,%r12,off@l  */
 #define ADDIS_R2_R2    0x3c420000      /* addis %r2,%r2,off@ha  */
 #define ADDI_R2_R2     0x38420000      /* addi  %r2,%r2,off@l   */
 
@@ -186,15 +186,21 @@ static bfd_vma opd_entry_value
 #define ADD_R2_R2_R12  0x7c426214      /* add   %r2,%r2,%r12    */
 
 #define LIS_R2         0x3c400000      /* lis %r2,xxx@ha         */
+#define LIS_R12                0x3d800000      /* lis %r12,xxx@ha        */
 #define ADDIS_R2_R12   0x3c4c0000      /* addis %r2,%r12,xxx@ha  */
 #define ADDIS_R12_R2   0x3d820000      /* addis %r12,%r2,xxx@ha  */
+#define ADDIS_R12_R11  0x3d8b0000      /* addis %r12,%r11,xxx@ha */
 #define ADDIS_R12_R12  0x3d8c0000      /* addis %r12,%r12,xxx@ha */
+#define ORIS_R12_R12_0 0x658c0000      /* oris  %r12,%r12,xxx@hi */
+#define ORI_R12_R12_0  0x618c0000      /* ori   %r12,%r12,xxx@l  */
 #define LD_R12_0R12    0xe98c0000      /* ld    %r12,xxx@l(%r12) */
+#define SLDI_R12_R12_32        0x799c07c6      /* sldi  %r12,%r12,32     */
+#define LDX_R12_R11_R12 0x7d8b602a     /* ldx   %r12,%r11,%r12   */
+#define ADD_R12_R11_R12 0x7d8b6214     /* add   %r12,%r11,%r12   */
 
 /* __glink_PLTresolve stub instructions.  We enter with the index in R0.  */
 #define GLINK_PLTRESOLVE_SIZE(htab)                    \
-  (8u + (htab->opd_abi ? 11 * 4 : 14 * 4)              \
-   + (!htab->params->speculate_indirect_jumps ? 2 * 4 : 0))
+  (8u + (htab->opd_abi ? 11 * 4 : 14 * 4))
                                        /* 0:                           */
                                        /*  .quad plt0-1f               */
                                        /* __glink:                     */
@@ -275,7 +281,8 @@ set_abiversion (bfd *abfd, int ver)
 /* Relocation HOWTO's.  */
 static reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC64_max];
 
-static reloc_howto_type ppc64_elf_howto_raw[] = {
+static reloc_howto_type ppc64_elf_howto_raw[] =
+{
   /* This reloc does nothing.  */
   HOWTO (R_PPC64_NONE,         /* type */
         0,                     /* rightshift */
@@ -448,6 +455,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0x03fffffc,            /* dst_mask */
         TRUE),                 /* pcrel_offset */
 
+  /* A variant of R_PPC64_REL24, used when r2 is not the toc pointer.  */
+  HOWTO (R_PPC64_REL24_NOTOC,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        26,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        ppc64_elf_branch_reloc, /* special_function */
+        "R_PPC64_REL24_NOTOC", /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x03fffffc,            /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
   /* A relative 16 bit branch; the lower two bits must be zero.  */
   HOWTO (R_PPC64_REL14,                /* type */
         0,                     /* rightshift */
@@ -1339,6 +1361,8 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* Marker reloc for optimizing r2 save in prologue rather than on
+     each plt call stub.  */
   HOWTO (R_PPC64_TOCSAVE,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -1353,6 +1377,35 @@ static reloc_howto_type ppc64_elf_howto_raw[] = {
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
 
+  /* Marker relocs on inline plt call instructions.  */
+  HOWTO (R_PPC64_PLTSEQ,
+        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_PLTSEQ",      /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_PPC64_PLTCALL,
+        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_PLTCALL",     /* 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,
@@ -2236,7 +2289,7 @@ ppc_howto_init (void)
 }
 
 static reloc_howto_type *
-ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ppc64_elf_reloc_type_lookup (bfd *abfd,
                             bfd_reloc_code_real_type code)
 {
   enum elf_ppc64_reloc_type r = R_PPC64_NONE;
@@ -2248,6 +2301,9 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
   switch (code)
     {
     default:
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, (int) code);
+      bfd_set_error (bfd_error_bad_value);
       return NULL;
 
     case BFD_RELOC_NONE:                       r = R_PPC64_NONE;
@@ -2276,6 +2332,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       break;
     case BFD_RELOC_PPC_B26:                    r = R_PPC64_REL24;
       break;
+    case BFD_RELOC_PPC64_REL24_NOTOC:          r = R_PPC64_REL24_NOTOC;
+      break;
     case BFD_RELOC_PPC_B16:                    r = R_PPC64_REL14;
       break;
     case BFD_RELOC_PPC_B16_BRTAKEN:            r = R_PPC64_REL14_BRTAKEN;
@@ -2500,12 +2558,13 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
        && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0)
       return &ppc64_elf_howto_raw[i];
 
+  
   return NULL;
 }
 
 /* Set the howto pointer for a PowerPC ELF reloc.  */
 
-static void
+static bfd_boolean
 ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
                         Elf_Internal_Rela *dst)
 {
@@ -2519,11 +2578,22 @@ ppc64_elf_info_to_howto (bfd *abfd, arelent *cache_ptr,
   if (type >= ARRAY_SIZE (ppc64_elf_howto_table))
     {
       /* xgettext:c-format */
-      _bfd_error_handler (_("%B: invalid relocation type %d"),
-                         abfd, (int) type);
-      type = R_PPC64_NONE;
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                         abfd, type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
     }
   cache_ptr->howto = ppc64_elf_howto_table[type];
+  if (cache_ptr->howto == NULL || cache_ptr->howto->name == NULL)
+    {
+      /* xgettext:c-format */
+      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+                         abfd, type);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+  
+  return TRUE;
 }
 
 /* Handle the R_PPC64_ADDR16_HA and similar relocs.  */
@@ -2991,13 +3061,24 @@ ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type,
 
     case NT_PRPSINFO:
       {
-       char data[136];
+       char data[136] ATTRIBUTE_NONSTRING;
        va_list ap;
 
        va_start (ap, note_type);
        memset (data, 0, sizeof (data));
        strncpy (data + 40, va_arg (ap, const char *), 16);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_PUSH;
+       /* GCC 8.0 and 8.1 warn about 80 equals destination size with
+          -Wstringop-truncation:
+          https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85643
+        */
+       DIAGNOSTIC_IGNORE_STRINGOP_TRUNCATION;
+#endif
        strncpy (data + 56, va_arg (ap, const char *), 80);
+#if GCC_VERSION == 8000 || GCC_VERSION == 8001
+       DIAGNOSTIC_POP;
+#endif
        va_end (ap);
        return elfcore_write_note (abfd, buf, bufsiz,
                                   "CORE", note_type, data, sizeof (data));
@@ -3080,6 +3161,9 @@ struct _ppc64_elf_section_data
   /* Flag set when small branches are detected.  Used to
      select suitable defaults for the stub group size.  */
   unsigned int has_14bit_branch:1;
+
+  /* Flag set when PLTCALL relocs are detected.  */
+  unsigned int has_pltcall:1;
 };
 
 #define ppc64_elf_section_data(sec) \
@@ -3258,10 +3342,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
                                asymbol **ret)
 {
   asymbol *s;
-  long i;
-  long count;
+  size_t i, j, count;
   char *names;
-  long symcount, codesecsym, codesecsymend, secsymend, opdsymend;
+  size_t symcount, codesecsym, codesecsymend, secsymend, opdsymend;
   asection *opd = NULL;
   bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
   asymbol **syms;
@@ -3306,20 +3389,37 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       else
        memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
+      /* Trim uninteresting symbols.  Interesting symbols are section,
+        function, and notype symbols.  */
+      for (i = 0, j = 0; i < symcount; ++i)
+       if ((syms[i]->flags & (BSF_FILE | BSF_OBJECT | BSF_THREAD_LOCAL
+                              | BSF_RELC | BSF_SRELC)) == 0)
+         syms[j++] = syms[i];
+      symcount = j;
+
       synthetic_relocatable = relocatable;
       synthetic_opd = opd;
       qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
       if (!relocatable && symcount > 1)
        {
-         long j;
-         /* Trim duplicate syms, since we may have merged the normal and
-            dynamic symbols.  Actually, we only care about syms that have
-            different values, so trim any with the same value.  */
+         /* Trim duplicate syms, since we may have merged the normal
+            and dynamic symbols.  Actually, we only care about syms
+            that have different values, so trim any with the same
+            value.  Don't consider ifunc and ifunc resolver symbols
+            duplicates however, because GDB wants to know whether a
+            text symbol is an ifunc resolver.  */
          for (i = 1, j = 1; i < symcount; ++i)
-           if (syms[i - 1]->value + syms[i - 1]->section->vma
-               != syms[i]->value + syms[i]->section->vma)
-             syms[j++] = syms[i];
+           {
+             const asymbol *s0 = syms[i - 1];
+             const asymbol *s1 = syms[i];
+
+             if ((s0->value + s0->section->vma
+                  != s1->value + s1->section->vma)
+                 || ((s0->flags & BSF_GNU_INDIRECT_FUNCTION)
+                     != (s1->flags & BSF_GNU_INDIRECT_FUNCTION)))
+               syms[j++] = syms[i];
+           }
          symcount = j;
        }
 
@@ -3328,7 +3428,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
         sym->section directly.  With separate debug info files, the
         symbols will be extracted from the debug file while abfd passed
         to this function is the real binary.  */
-      if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
+      if (strcmp (syms[i]->section->name, ".opd") == 0)
        ++i;
       codesecsym = i;
 
@@ -3363,7 +3463,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
       arelent *r;
       size_t size;
-      long relcount;
+      size_t relcount;
 
       if (opdsymend == secsymend)
        goto done;
@@ -3462,7 +3562,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
       bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
       bfd_byte *contents = NULL;
       size_t size;
-      long plt_count = 0;
+      size_t plt_count = 0;
       bfd_vma glink_vma = 0, resolv_vma = 0;
       asection *dynamic, *glink = NULL, *relplt = NULL;
       arelent *p;
@@ -3599,7 +3699,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
-             long lo, hi;
+             size_t lo, hi;
              size_t len;
              asection *sec = abfd->sections;
 
@@ -3608,7 +3708,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              hi = codesecsymend;
              while (lo < hi)
                {
-                 long mid = (lo + hi) >> 1;
+                 size_t mid = (lo + hi) >> 1;
                  if (syms[mid]->section->vma < ent)
                    lo = mid + 1;
                  else if (syms[mid]->section->vma > ent)
@@ -3880,7 +3980,7 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    Used to call a function in a shared library.  If it so happens that
    the plt entry referenced crosses a 64k boundary, then an extra
    "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr".
-   .   std     %r2,40(%r1)
+   ppc_stub_plt_call_r2save starts with "std %r2,40(%r1)".
    .   addis   %r11,%r2,xxx@toc@ha
    .   ld      %r12,xxx+0@toc@l(%r11)
    .   mtctr   %r12
@@ -3905,18 +4005,98 @@ must_be_dyn_reloc (struct bfd_link_info *info,
    .   mtctr   %r12
    .   bctr
 
-   In cases where the "addis" instruction would add zero, the "addis" is
-   omitted and following instructions modified slightly in some cases.
-*/
+   All of the above stubs are shown as their ELFv1 variants.  ELFv2
+   variants exist too, simpler for plt calls since a new toc pointer
+   and static chain are not loaded by the stub.  In addition, ELFv2
+   has some more complex stubs to handle calls marked with NOTOC
+   relocs from functions where r2 is not a valid toc pointer.  These
+   come in two flavours, the ones shown below, and _both variants that
+   start with "std %r2,24(%r1)" to save r2 in the unlikely event that
+   one call is from a function where r2 is used as the toc pointer but
+   needs a toc adjusting stub for small-model multi-toc, and another
+   call is from a function where r2 is not valid.
+   ppc_stub_long_branch_notoc:
+   .   mflr    %r12
+   .   bcl     20,31,1f
+   .  1:
+   .   mflr    %r11
+   .   mtlr    %r12
+   .   lis     %r12,xxx-1b@highest
+   .   ori     %r12,xxx-1b@higher
+   .   sldi    %r12,%r12,32
+   .   oris    %r12,%r12,xxx-1b@hi
+   .   ori     %r12,%r12,xxx-1b@l
+   .   add     %r12,%r11,%r12
+   .   b       dest
+
+   ppc_stub_plt_branch_notoc:
+   .   mflr    %r12
+   .   bcl     20,31,1f
+   .  1:
+   .   mflr    %r11
+   .   mtlr    %r12
+   .   lis     %r12,xxx-1b@highest
+   .   ori     %r12,xxx-1b@higher
+   .   sldi    %r12,%r12,32
+   .   oris    %r12,%r12,xxx-1b@hi
+   .   ori     %r12,%r12,xxx-1b@l
+   .   add     %r12,%r11,%r12
+   .   mtctr   %r12
+   .   bctr
+
+   ppc_stub_plt_call_notoc:
+   .   mflr    %r12
+   .   bcl     20,31,1f
+   .  1:
+   .   mflr    %r11
+   .   mtlr    %r12
+   .   lis     %r12,xxx-1b@highest
+   .   ori     %r12,xxx-1b@higher
+   .   sldi    %r12,%r12,32
+   .   oris    %r12,%r12,xxx-1b@hi
+   .   ori     %r12,%r12,xxx-1b@l
+   .   ldx     %r12,%r11,%r12
+   .   mtctr   %r12
+   .   bctr
+
+   In cases where the high instructions would add zero, they are
+   omitted and following instructions modified in some cases.
+
+   For a given stub group (a set of sections all using the same toc
+   pointer value) there will be just one stub type used for any
+   particular function symbol.  For example, if printf is called from
+   code with the tocsave optimization (ie. r2 saved in function
+   prologue) and therefore calls use a ppc_stub_plt_call linkage stub,
+   and from other code without the tocsave optimization requiring a
+   ppc_stub_plt_call_r2save linkage stub, a single stub of the latter
+   type will be created.  Calls with the tocsave optimization will
+   enter this stub after the instruction saving r2.  A similar
+   situation exists when calls are marked with R_PPC64_REL24_NOTOC
+   relocations.  These require a ppc_stub_plt_call_notoc linkage stub
+   to call an external function like printf.  If other calls to printf
+   require a ppc_stub_plt_call linkage stub then a single
+   ppc_stub_plt_call_notoc linkage stub will be used for both types of
+   call.  If other calls to printf require a ppc_stub_plt_call_r2save
+   linkage stub then a single ppc_stub_plt_call_both linkage stub will
+   be created and calls not requiring r2 to be saved will enter the
+   stub after the r2 save instruction.  There is an analogous
+   hierarchy of long branch and plt branch stubs for local call
+   linkage.  */
 
 enum ppc_stub_type {
   ppc_stub_none,
   ppc_stub_long_branch,
   ppc_stub_long_branch_r2off,
+  ppc_stub_long_branch_notoc,
+  ppc_stub_long_branch_both, /* r2off and notoc variants both needed.  */
   ppc_stub_plt_branch,
   ppc_stub_plt_branch_r2off,
+  ppc_stub_plt_branch_notoc,
+  ppc_stub_plt_branch_both,
   ppc_stub_plt_call,
   ppc_stub_plt_call_r2save,
+  ppc_stub_plt_call_notoc,
+  ppc_stub_plt_call_both,
   ppc_stub_global_entry,
   ppc_stub_save_res
 };
@@ -3933,9 +4113,15 @@ struct map_stub
   /* Whether to emit a copy of register save/restore functions in this
      group.  */
   int needs_save_res;
-  /* The offset of the __tls_get_addr_opt plt stub bctrl in this group,
-     or -1u if no such stub with bctrl exists.  */
-  unsigned int tls_get_addr_opt_bctrl;
+  /* Current offset within stubs after the insn restoring lr in a
+     _notoc or _both stub using bcl for pc-relative addressing, or
+     after the insn restoring lr in a __tls_get_addr_opt plt stub.  */
+  unsigned int lr_restore;
+  /* Accumulated size of EH info emitted to describe return address
+     if stubs modify lr.  Does not include 17 byte FDE header.  */
+  unsigned int eh_size;
+  /* Offset in glink_eh_frame to the start of EH info for this group.  */
+  unsigned int eh_base;
 };
 
 struct ppc_stub_hash_entry {
@@ -3960,6 +4146,9 @@ struct ppc_stub_hash_entry {
   struct ppc_link_hash_entry *h;
   struct plt_entry *plt_ent;
 
+  /* Symbol type.  */
+  unsigned char symtype;
+
   /* Symbol st_other.  */
   unsigned char other;
 };
@@ -4029,22 +4218,30 @@ struct ppc_link_hash_entry
   unsigned int non_zero_localentry:1;
 
   /* Contexts in which symbol is used in the GOT (or TOC).
-     TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
-     corresponding relocs are encountered during check_relocs.
-     tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
-     indicate the corresponding GOT entry type is not needed.
-     tls_optimize may also set TLS_TPRELGD when a GD reloc turns into
-     a TPREL one.  We use a separate flag rather than setting TPREL
-     just for convenience in distinguishing the two cases.  */
-#define TLS_GD          1      /* GD reloc. */
-#define TLS_LD          2      /* LD reloc. */
-#define TLS_TPREL       4      /* TPREL reloc, => IE. */
-#define TLS_DTPREL      8      /* DTPREL reloc, => LD. */
-#define TLS_TLS                16      /* Any TLS reloc.  */
-#define TLS_EXPLICIT   32      /* Marks TOC section TLS relocs. */
+     Bits are or'd into the mask as the corresponding relocs are
+     encountered during check_relocs, with TLS_TLS being set when any
+     of the other TLS bits are set.  tls_optimize clears bits when
+     optimizing to indicate the corresponding GOT entry type is not
+     needed.  If set, TLS_TLS is never cleared.  tls_optimize may also
+     set TLS_TPRELGD when a GD reloc turns into a TPREL one.  We use a
+     separate flag rather than setting TPREL just for convenience in
+     distinguishing the two cases.
+     These flags are also kept for local symbols.  */
+#define TLS_TLS                 1      /* Any TLS reloc.  */
+#define TLS_GD          2      /* GD reloc. */
+#define TLS_LD          4      /* LD reloc. */
+#define TLS_TPREL       8      /* TPREL reloc, => IE. */
+#define TLS_DTPREL     16      /* DTPREL reloc, => LD. */
+#define TLS_MARK       32      /* __tls_get_addr call marked. */
 #define TLS_TPRELGD    64      /* TPREL reloc resulting from GD->IE. */
-#define PLT_IFUNC      128     /* STT_GNU_IFUNC.  */
+#define TLS_EXPLICIT   128     /* Marks TOC section TLS relocs. */
   unsigned char tls_mask;
+
+  /* The above field is also used to mark function symbols.  In which
+     case TLS_TLS will be 0.  */
+#define PLT_IFUNC       2      /* STT_GNU_IFUNC.  */
+#define PLT_KEEP        4      /* inline plt call requires plt entry.  */
+#define NON_GOT        256     /* local symbol plt, not stored.  */
 };
 
 /* ppc64 ELF linker hash table.  */
@@ -4100,6 +4297,8 @@ struct ppc_link_hash_table
   asection *glink;
   asection *global_entry;
   asection *sfpr;
+  asection *pltlocal;
+  asection *relpltlocal;
   asection *brlt;
   asection *relbrlt;
   asection *glink_eh_frame;
@@ -4129,6 +4328,9 @@ struct ppc_link_hash_table
   /* Set if tls optimization is enabled.  */
   unsigned int do_tls_opt:1;
 
+  /* Set if inline plt calls should be converted to direct calls.  */
+  unsigned int can_convert_all_inline_plt:1;
+
   /* Set on error.  */
   unsigned int stub_error:1;
 
@@ -4156,7 +4358,7 @@ struct ppc_link_hash_table
 /* 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.  */
+/* Nonzero if this section has an old-style call to __tls_get_addr.  */
 #define has_tls_get_addr_call sec_flg1
 
 /* Nonzero if this section has any toc or got relocs.  */
@@ -4481,18 +4683,31 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
       || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
     return FALSE;
 
+  /* Local plt entries, put in .branch_lt but a separate section for
+     convenience.  */
+  htab->pltlocal = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
+                                                      flags);
+  if (htab->pltlocal == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->pltlocal, 3))
+    return FALSE;
+
   if (!bfd_link_pic (info))
     return TRUE;
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
-                                                     ".rela.branch_lt",
-                                                     flags);
+  htab->relbrlt
+    = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
   if (htab->relbrlt == NULL
       || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
     return FALSE;
 
+  htab->relpltlocal
+    = bfd_make_section_anyway_with_flags (dynobj, ".rela.branch_lt", flags);
+  if (htab->relpltlocal == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->relpltlocal, 3))
+    return FALSE;
+
   return TRUE;
 }
 
@@ -4652,8 +4867,8 @@ ppc_add_stub (const char *stub_name,
   if (stub_entry == NULL)
     {
       /* xgettext:c-format */
-      info->callbacks->einfo (_("%P: %B: cannot create stub entry %s\n"),
-                             section->owner, stub_name);
+      _bfd_error_handler (_("%pB: cannot create stub entry %s"),
+                         section->owner, stub_name);
       return NULL;
     }
 
@@ -4942,11 +5157,6 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
                           asection **sec,
                           bfd_vma *value)
 {
-  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
-      && (ibfd->flags & DYNAMIC) == 0
-      && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
-    elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
-
   if (*sec != NULL
       && strcmp ((*sec)->name, ".opd") == 0)
     {
@@ -4983,8 +5193,8 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
        set_abiversion (ibfd, 2);
       else if (abiversion (ibfd) == 1)
        {
-         info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other"
-                                   " for ABI version 1\n"), name);
+         _bfd_error_handler (_("symbol '%s' has invalid st_other"
+                               " for ABI version 1"), *name);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -5051,7 +5261,7 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd,
   len = strlen (name);
   dot_name = bfd_alloc (abfd, len + 2);
   if (dot_name == NULL)
-    return (struct elf_link_hash_entry *) 0 - 1;
+    return (struct elf_link_hash_entry *) -1;
   dot_name[0] = '.';
   memcpy (dot_name + 1, name, len + 1);
   h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name);
@@ -5158,9 +5368,8 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
       else if (abiversion (ibfd) >= 2)
        {
          /* xgettext:c-format */
-         info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
-                                   " version %d\n"),
-                                 ibfd, abiversion (ibfd));
+         _bfd_error_handler (_("%pB .opd not allowed in ABI version %d"),
+                             ibfd, abiversion (ibfd));
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
        }
@@ -5321,7 +5530,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       elf_local_got_ents (abfd) = local_got_ents;
     }
 
-  if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0)
+  if ((tls_type & (NON_GOT | TLS_EXPLICIT)) == 0)
     {
       struct got_entry *ent;
 
@@ -5349,7 +5558,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 
   local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
   local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
-  local_got_tls_masks[r_symndx] |= tls_type;
+  local_got_tls_masks[r_symndx] |= tls_type & 0xff;
 
   return local_plt + r_symndx;
 }
@@ -5381,13 +5590,27 @@ static bfd_boolean
 is_branch_reloc (enum elf_ppc64_reloc_type r_type)
 {
   return (r_type == R_PPC64_REL24
+         || r_type == R_PPC64_REL24_NOTOC
          || 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);
+         || r_type == R_PPC64_ADDR14_BRNTAKEN
+         || r_type == R_PPC64_PLTCALL);
+}
+
+/* Relocs on inline plt call sequence insns prior to the call.  */
+
+static bfd_boolean
+is_plt_seq_reloc (enum elf_ppc64_reloc_type r_type)
+{
+  return (r_type == R_PPC64_PLT16_HA
+         || r_type == R_PPC64_PLT16_HI
+         || r_type == R_PPC64_PLT16_LO
+         || r_type == R_PPC64_PLT16_LO_DS
+         || r_type == R_PPC64_PLTSEQ);
 }
 
 /* Look through the relocs for a section during the first phase, and
@@ -5475,7 +5698,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          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);
+                                            rel->r_addend,
+                                            NON_GOT | PLT_IFUNC);
              if (ifunc == NULL)
                return FALSE;
            }
@@ -5488,6 +5712,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TLSLD:
          /* These special tls relocs tie a call to __tls_get_addr with
             its parameter symbol.  */
+         if (h != NULL)
+           ((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
+         else
+           if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                       rel->r_addend,
+                                       NON_GOT | TLS_TLS | TLS_MARK))
+             return FALSE;
+         sec->has_tls_reloc = 1;
          break;
 
        case R_PPC64_GOT_TLSLD16:
@@ -5591,6 +5823,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_PLT16_HA:
        case R_PPC64_PLT16_HI:
        case R_PPC64_PLT16_LO:
+       case R_PPC64_PLT16_LO_DS:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
          /* This symbol requires a procedure linkage table entry.  */
@@ -5601,20 +5834,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              if (h->root.root.string[0] == '.'
                  && h->root.root.string[1] != '\0')
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
+             ((struct ppc_link_hash_entry *) h)->tls_mask |= PLT_KEEP;
              plt_list = &h->plt.plist;
            }
          if (plt_list == NULL)
-           {
-             /* It does not make sense to have a procedure linkage
-                table entry for a non-ifunc local symbol.  */
-             info->callbacks->einfo
-               /* xgettext:c-format */
-               (_("%H: %s reloc against local symbol\n"),
-                abfd, sec, rel->r_offset,
-                ppc64_elf_howto_table[r_type]->name);
-             bfd_set_error (bfd_error_bad_value);
-             return FALSE;
-           }
+           plt_list = update_local_sym_info (abfd, symtab_hdr, r_symndx,
+                                             rel->r_addend,
+                                             NON_GOT | PLT_KEEP);
          if (!update_plt_info (abfd, plt_list, rel->r_addend))
            return FALSE;
          break;
@@ -5658,7 +5884,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                ppc_howto_init ();
              /* xgettext:c-format */
              info->callbacks->einfo (_("%H: %s reloc unsupported "
-                                       "in shared libraries and PIEs.\n"),
+                                       "in shared libraries and PIEs\n"),
                                      abfd, sec, rel->r_offset,
                                      ppc64_elf_howto_table[r_type]->name);
              bfd_set_error (bfd_error_bad_value);
@@ -5728,9 +5954,15 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
            if (dest != sec)
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
          }
+         goto rel24;
+
+       case R_PPC64_PLTCALL:
+         ppc64_elf_section_data (sec)->has_pltcall = 1;
          /* Fall through.  */
 
        case R_PPC64_REL24:
+       case R_PPC64_REL24_NOTOC:
+       rel24:
          plt_list = ifunc;
          if (h != NULL)
            {
@@ -6047,7 +6279,7 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
     {
       _bfd_error_handler
        /* xgettext:c-format */
-       (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
+       (_("%pB uses unknown e_flags 0x%lx"), ibfd, iflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
@@ -6055,18 +6287,17 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
     {
       _bfd_error_handler
        /* xgettext:c-format */
-       (_("%B: ABI version %ld is not compatible with ABI version %ld output"),
+       (_("%pB: ABI version %ld is not compatible with ABI version %ld output"),
         ibfd, iflags, oflags);
       bfd_set_error (bfd_error_bad_value);
       return FALSE;
     }
 
-  _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+  if (!_bfd_elf_ppc_merge_fp_attributes (ibfd, info))
+    return FALSE;
 
   /* Merge Tag_compatibility attributes and any common GNU ones.  */
-  _bfd_elf_merge_object_attributes (ibfd, info);
-
-  return TRUE;
+  return _bfd_elf_merge_object_attributes (ibfd, info);
 }
 
 static bfd_boolean
@@ -6650,7 +6881,7 @@ sfpr_define (struct bfd_link_info *info,
                {
                  s->root.type = bfd_link_hash_defined;
                  s->root.u.def.section = stub_sec;
-                 s->root.u.def.value = (stub_sec->size
+                 s->root.u.def.value = (stub_sec->size - htab->sfpr->size
                                         + h->elf.root.u.def.value);
                  s->ref_regular = 1;
                  s->def_regular = 1;
@@ -7168,7 +7399,11 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        if (ent->plt.refcount > 0)
          break;
       if (ent == NULL
-         || (h->type != STT_GNU_IFUNC && local))
+         || (h->type != STT_GNU_IFUNC
+             && local
+             && (htab->can_convert_all_inline_plt
+                 || (((struct ppc_link_hash_entry *) h)->tls_mask
+                     & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)))
        {
          h->plt.plist = NULL;
          h->needs_plt = 0;
@@ -7188,8 +7423,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
              if (!readonly_dynrelocs (h))
                {
                  h->pointer_equality_needed = 0;
-                 /* If we haven't seen a branch reloc then we don't need
-                    a plt entry.  */
+                 /* If we haven't seen a branch reloc and the symbol
+                    isn't an ifunc then we don't need a plt entry.  */
                  if (!h->needs_plt)
                    h->plt.plist = NULL;
                }
@@ -7205,8 +7440,8 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       else if (!h->needs_plt
               && !readonly_dynrelocs (h))
        {
-         /* If we haven't seen a branch reloc then we don't need a
-            plt entry.  */
+         /* If we haven't seen a branch reloc and the symbol isn't an
+            ifunc then we don't need a plt entry.  */
          h->plt.plist = NULL;
          h->pointer_equality_needed = 0;
          return TRUE;
@@ -7267,7 +7502,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
         sections.  Allow them to proceed, but warn that this might
         break at runtime.  */
       info->callbacks->einfo
-       (_("%P: copy reloc against `%T' requires lazy plt linking; "
+       (_("%P: copy reloc against `%pT' requires lazy plt linking; "
           "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
         h->root.root.string);
     }
@@ -7482,7 +7717,9 @@ get_tls_mask (unsigned char **tls_maskp,
   if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
     return 0;
 
-  if ((*tls_maskp != NULL && **tls_maskp != 0)
+  if ((*tls_maskp != NULL
+       && (**tls_maskp & TLS_TLS) != 0
+       && **tls_maskp != (TLS_TLS | TLS_MARK))
       || sec == NULL
       || ppc64_elf_section_data (sec) == NULL
       || ppc64_elf_section_data (sec)->sec_type != sec_toc)
@@ -7534,7 +7771,7 @@ tocsave_find (struct ppc_link_hash_table *htab,
   if (ent.sec == NULL || ent.sec->output_section == NULL)
     {
       _bfd_error_handler
-       (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd);
+       (_("%pB: undefined symbol on R_PPC64_TOCSAVE relocation"), ibfd);
       return NULL;
     }
 
@@ -7761,8 +7998,8 @@ dec_dynrel_count (bfd_vma r_info,
     }
 
   /* xgettext:c-format */
-  info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
-                         sec->owner, sec);
+  _bfd_error_handler (_("dynreloc miscount for %pB, section %pA"),
+                     sec->owner, sec);
   bfd_set_error (bfd_error_bad_value);
   return FALSE;
 }
@@ -7850,7 +8087,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
                 optimization for them!  */
            broken_opd:
              _bfd_error_handler
-               (_("%B: .opd is not a regular array of opd entries"), ibfd);
+               (_("%pB: .opd is not a regular array of opd entries"), ibfd);
              broken = TRUE;
              break;
            }
@@ -7860,7 +8097,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
            {
              _bfd_error_handler
                /* xgettext:c-format */
-               (_("%B: unexpected reloc type %u in .opd section"),
+               (_("%pB: unexpected reloc type %u in .opd section"),
                 ibfd, r_type);
              broken = TRUE;
              break;
@@ -7882,7 +8119,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
 
              _bfd_error_handler
                /* xgettext:c-format */
-               (_("%B: undefined sym `%s' in .opd section"),
+               (_("%pB: undefined sym `%s' in .opd section"),
                 ibfd, sym_name);
              broken = TRUE;
              break;
@@ -8180,6 +8417,153 @@ ppc64_elf_edit_opd (struct bfd_link_info *info)
   return TRUE;
 }
 
+/* Analyze inline PLT call relocations to see whether calls to locally
+   defined functions can be converted to direct calls.  */
+
+bfd_boolean
+ppc64_elf_inline_plt (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab;
+  bfd *ibfd;
+  asection *sec;
+  bfd_vma low_vma, high_vma, limit;
+
+  htab = ppc_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
+  /* A bl insn can reach -0x2000000 to 0x1fffffc.  The limit is
+     reduced somewhat to cater for possible stubs that might be added
+     between the call and its destination.  */
+  if (htab->params->group_size < 0)
+    {
+      limit = -htab->params->group_size;
+      if (limit == 1)
+       limit = 0x1e00000;
+    }
+  else
+    {
+      limit = htab->params->group_size;
+      if (limit == 1)
+       limit = 0x1c00000;
+    }
+
+  low_vma = -1;
+  high_vma = 0;
+  for (sec = info->output_bfd->sections; sec != NULL; sec = sec->next)
+    if ((sec->flags & (SEC_ALLOC | SEC_CODE)) == (SEC_ALLOC | SEC_CODE))
+      {
+       if (low_vma > sec->vma)
+         low_vma = sec->vma;
+       if (high_vma < sec->vma + sec->size)
+         high_vma = sec->vma + sec->size;
+      }
+
+  /* If a "bl" can reach anywhere in local code sections, then we can
+     convert all inline PLT sequences to direct calls when the symbol
+     is local.  */
+  if (high_vma - low_vma < limit)
+    {
+      htab->can_convert_all_inline_plt = 1;
+      return TRUE;
+    }
+
+  /* Otherwise, go looking through relocs for cases where a direct
+     call won't reach.  Mark the symbol on any such reloc to disable
+     the optimization and keep the PLT entry as it seems likely that
+     this will be better than creating trampolines.  Note that this
+     will disable the optimization for all inline PLT calls to a
+     particular symbol, not just those that won't reach.  The
+     difficulty in doing a more precise optimization is that the
+     linker needs to make a decision depending on whether a
+     particular R_PPC64_PLTCALL insn can be turned into a direct
+     call, for each of the R_PPC64_PLTSEQ and R_PPC64_PLT16* insns in
+     the sequence, and there is nothing that ties those relocs
+     together except their symbol.  */
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      local_syms = NULL;
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+
+      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+       if (ppc64_elf_section_data (sec)->has_pltcall
+           && !bfd_is_abs_section (sec->output_section))
+         {
+           Elf_Internal_Rela *relstart, *rel, *relend;
+
+           /* Read the relocations.  */
+           relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
+                                                 info->keep_memory);
+           if (relstart == NULL)
+             return FALSE;
+
+           relend = relstart + sec->reloc_count;
+           for (rel = relstart; rel < relend; )
+             {
+               enum elf_ppc64_reloc_type r_type;
+               unsigned long r_symndx;
+               asection *sym_sec;
+               struct elf_link_hash_entry *h;
+               Elf_Internal_Sym *sym;
+               unsigned char *tls_maskp;
+
+               r_type = ELF64_R_TYPE (rel->r_info);
+               if (r_type != R_PPC64_PLTCALL)
+                 continue;
+
+               r_symndx = ELF64_R_SYM (rel->r_info);
+               if (!get_sym_h (&h, &sym, &sym_sec, &tls_maskp, &local_syms,
+                               r_symndx, ibfd))
+                 {
+                   if (elf_section_data (sec)->relocs != relstart)
+                     free (relstart);
+                   if (local_syms != NULL
+                       && symtab_hdr->contents != (unsigned char *) local_syms)
+                     free (local_syms);
+                   return FALSE;
+                 }
+
+               if (sym_sec != NULL && sym_sec->output_section != NULL)
+                 {
+                   bfd_vma from, to;
+                   if (h != NULL)
+                     to = h->root.u.def.value;
+                   else
+                     to = sym->st_value;
+                   to += (rel->r_addend
+                          + sym_sec->output_offset
+                          + sym_sec->output_section->vma);
+                   from = (rel->r_offset
+                           + sec->output_offset
+                           + sec->output_section->vma);
+                   if (to - from + limit < 2 * limit)
+                     *tls_maskp &= ~PLT_KEEP;
+                 }
+             }
+           if (elf_section_data (sec)->relocs != relstart)
+             free (relstart);
+         }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
+
+  return TRUE;
+}
+
 /* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 asection *
@@ -8218,9 +8602,9 @@ ppc64_elf_tls_setup (struct bfd_link_info *info)
   if (htab->params->plt_localentry0
       && elf_link_hash_lookup (&htab->elf, "GLIBC_2.26",
                               FALSE, FALSE, FALSE) == NULL)
-    info->callbacks->einfo
-      (_("%P: warning: --plt-localentry is especially dangerous without "
-        "ld.so support to detect ABI violations.\n"));
+    _bfd_error_handler
+      (_("warning: --plt-localentry is especially dangerous without "
+        "ld.so support to detect ABI violations"));
 
   htab->tls_get_addr = ((struct ppc_link_hash_entry *)
                        elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
@@ -8532,6 +8916,33 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
 
                    case R_PPC64_TLSGD:
                    case R_PPC64_TLSLD:
+                     if (rel + 1 < relend
+                         && is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+                       {
+                         if (pass != 0
+                             && ELF64_R_TYPE (rel[1].r_info) != R_PPC64_PLTSEQ)
+                           {
+                             r_symndx = ELF64_R_SYM (rel[1].r_info);
+                             if (!get_sym_h (&h, NULL, NULL, NULL, &locsyms,
+                                 r_symndx, ibfd))
+                               goto err_free_rel;
+                             if (h != NULL)
+                               {
+                                 struct plt_entry *ent = NULL;
+
+                                 for (ent = h->plt.plist;
+                                      ent != NULL;
+                                      ent = ent->next)
+                                   if (ent->addend == rel[1].r_addend)
+                                     break;
+
+                                 if (ent != NULL
+                                     && ent->plt.refcount > 0)
+                                   ent->plt.refcount -= 1;
+                               }
+                           }
+                         continue;
+                       }
                      found_tls_get_addr_arg = 1;
                      /* Fall through.  */
 
@@ -8649,7 +9060,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                                goto err_free_rel;
                              if (toc_tls != NULL)
                                {
-                                 if ((*toc_tls & (TLS_GD | TLS_LD)) != 0)
+                                 if ((*toc_tls & TLS_TLS) != 0
+                                     && ((*toc_tls & (TLS_GD | TLS_LD)) != 0))
                                    found_tls_get_addr_arg = 1;
                                  if (retval > 1)
                                    toc_ref[toc_ref_index] = 1;
@@ -8658,9 +9070,6 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                          continue;
                        }
 
-                     if (expecting_tls_get_addr != 1)
-                       continue;
-
                      /* 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
@@ -8673,35 +9082,41 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      goto err_free_rel;
                    }
 
-                 if (expecting_tls_get_addr && htab->tls_get_addr != NULL)
+                 /* If we don't have old-style __tls_get_addr calls
+                    without TLSGD/TLSLD marker relocs, and we haven't
+                    found a new-style __tls_get_addr call with a
+                    marker for this symbol, then we either have a
+                    broken object file or an -mlongcall style
+                    indirect call to __tls_get_addr without a marker.
+                    Disable optimization in this case.  */
+                 if ((tls_clear & (TLS_GD | TLS_LD)) != 0
+                     && (tls_set & TLS_EXPLICIT) == 0
+                     && !sec->has_tls_get_addr_call
+                     && ((*tls_mask & (TLS_TLS | TLS_MARK))
+                         != (TLS_TLS | TLS_MARK)))
+                   continue;
+
+                 if (expecting_tls_get_addr)
                    {
-                     struct plt_entry *ent;
-                     for (ent = htab->tls_get_addr->elf.plt.plist;
-                          ent != NULL;
-                          ent = ent->next)
-                       if (ent->addend == 0)
-                         {
-                           if (ent->plt.refcount > 0)
-                             {
-                               ent->plt.refcount -= 1;
-                               expecting_tls_get_addr = 0;
-                             }
+                     struct plt_entry *ent = NULL;
+
+                     if (htab->tls_get_addr != NULL)
+                       for (ent = htab->tls_get_addr->elf.plt.plist;
+                            ent != NULL;
+                            ent = ent->next)
+                         if (ent->addend == 0)
                            break;
-                         }
-                   }
 
-                 if (expecting_tls_get_addr && htab->tls_get_addr_fd != NULL)
-                   {
-                     struct plt_entry *ent;
-                     for (ent = htab->tls_get_addr_fd->elf.plt.plist;
-                          ent != NULL;
-                          ent = ent->next)
-                       if (ent->addend == 0)
-                         {
-                           if (ent->plt.refcount > 0)
-                             ent->plt.refcount -= 1;
+                     if (ent == NULL && htab->tls_get_addr_fd != NULL)
+                       for (ent = htab->tls_get_addr_fd->elf.plt.plist;
+                            ent != NULL;
+                            ent = ent->next)
+                         if (ent->addend == 0)
                            break;
-                         }
+
+                     if (ent != NULL
+                         && ent->plt.refcount > 0)
+                       ent->plt.refcount -= 1;
                    }
 
                  if (tls_clear == 0)
@@ -9178,7 +9593,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                          info->callbacks->einfo
                            /* xgettext:c-format */
                            (_("%H: toc optimization is not supported for"
-                              " %s instruction.\n"),
+                              " %s instruction\n"),
                             ibfd, sec, rel->r_offset & ~3, str);
                        }
                    }
@@ -9632,7 +10047,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   eh = (struct ppc_link_hash_entry *) h;
   /* Run through the TLS GD got entries first if we're changing them
      to TPREL.  */
-  if ((eh->tls_mask & TLS_TPRELGD) != 0)
+  if ((eh->tls_mask & (TLS_TLS | TLS_TPRELGD)) == (TLS_TLS | TLS_TPRELGD))
     for (gent = h->got.glist; gent != NULL; gent = gent->next)
       if (gent->got.refcount > 0
          && (gent->tls_type & TLS_GD) != 0)
@@ -9775,9 +10190,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        }
     }
 
-  if ((htab->elf.dynamic_sections_created
-       && h->dynindx != -1)
-      || h->type == STT_GNU_IFUNC)
+  /* We might need a PLT entry when the symbol
+     a) is dynamic, or
+     b) is an ifunc, or
+     c) has plt16 relocs and has been processed by adjust_dynamic_symbol, or
+     d) has plt16 relocs and we are linking statically.  */
+  if ((htab->elf.dynamic_sections_created && h->dynindx != -1)
+      || h->type == STT_GNU_IFUNC
+      || (h->needs_plt && h->dynamic_adjusted)
+      || (h->needs_plt
+         && h->def_regular
+         && !htab->elf.dynamic_sections_created
+         && !htab->can_convert_all_inline_plt
+         && (((struct ppc_link_hash_entry *) h)->tls_mask
+             & (TLS_TLS | PLT_KEEP)) == PLT_KEEP))
     {
       struct plt_entry *pent;
       bfd_boolean doneone = FALSE;
@@ -9787,10 +10213,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            if (!htab->elf.dynamic_sections_created
                || h->dynindx == -1)
              {
-               s = htab->elf.iplt;
-               pent->plt.offset = s->size;
-               s->size += PLT_ENTRY_SIZE (htab);
-               s = htab->elf.irelplt;
+               if (h->type == STT_GNU_IFUNC)
+                 {
+                   s = htab->elf.iplt;
+                   pent->plt.offset = s->size;
+                   s->size += PLT_ENTRY_SIZE (htab);
+                   s = htab->elf.irelplt;
+                 }
+               else
+                 {
+                   s = htab->pltlocal;
+                   pent->plt.offset = s->size;
+                   s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+                   s = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+                 }
              }
            else
              {
@@ -9822,7 +10258,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                /* We also need to make an entry in the .rela.plt section.  */
                s = htab->elf.srelplt;
              }
-           s->size += sizeof (Elf64_External_Rela);
+           if (s != NULL)
+             s->size += sizeof (Elf64_External_Rela);
            doneone = TRUE;
          }
        else
@@ -9886,8 +10323,6 @@ size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
        unsigned int align_power;
 
        stub_size = 16;
-       if (!htab->params->speculate_indirect_jumps)
-         stub_size += 8;
        stub_off = s->size;
        if (htab->params->plt_stub_align >= 0)
          align_power = htab->params->plt_stub_align;
@@ -9940,7 +10375,7 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *inf)
 
       info->flags |= DF_TEXTREL;
       info->callbacks->minfo
-       (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"),
+       (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
         sec->owner, h->root.root.string, sec);
 
       /* Not an error, just cut short the traversal.  */
@@ -10060,7 +10495,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        rel_size *= 2;
                      }
                    s->size += ent_size;
-                   if ((*lgot_masks & PLT_IFUNC) != 0)
+                   if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
                      {
                        htab->elf.irelplt->size += rel_size;
                        htab->got_reli_size += rel_size;
@@ -10079,19 +10514,33 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
              *pent = ent->next;
        }
 
-      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
-      for (; local_plt < end_local_plt; ++local_plt)
+      /* Allocate space for plt calls to local syms.  */
+      lgot_masks = (unsigned char *) end_local_plt;
+      for (; local_plt < end_local_plt; ++local_plt, ++lgot_masks)
        {
          struct plt_entry *ent;
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
            if (ent->plt.refcount > 0)
              {
-               s = htab->elf.iplt;
-               ent->plt.offset = s->size;
-               s->size += PLT_ENTRY_SIZE (htab);
-
-               htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+               if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
+                 {
+                   s = htab->elf.iplt;
+                   ent->plt.offset = s->size;
+                   s->size += PLT_ENTRY_SIZE (htab);
+                   htab->elf.irelplt->size += sizeof (Elf64_External_Rela);
+                 }
+               else if (htab->can_convert_all_inline_plt
+                        || (*lgot_masks & (TLS_TLS | PLT_KEEP)) != PLT_KEEP)
+                 ent->plt.offset = (bfd_vma) -1;
+               else
+                 {
+                   s = htab->pltlocal;
+                   ent->plt.offset = s->size;
+                   s->size += LOCAL_PLT_ENTRY_SIZE (htab);
+                   if (bfd_link_pic (info))
+                     htab->relpltlocal->size += sizeof (Elf64_External_Rela);
+                 }
              }
            else
              ent->plt.offset = (bfd_vma) -1;
@@ -10154,6 +10603,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
       else if (s == htab->elf.sgot
               || s == htab->elf.splt
               || s == htab->elf.iplt
+              || s == htab->pltlocal
               || s == htab->glink
               || s == htab->global_entry
               || s == htab->elf.sdynbss
@@ -10408,7 +10858,9 @@ ppc_type_of_stub (asection *input_sec,
 
   /* Determine if a long branch stub is needed.  */
   max_branch_offset = 1 << 25;
-  if (r_type != R_PPC64_REL24)
+  if (r_type == R_PPC64_REL14
+      || r_type == R_PPC64_REL14_BRTAKEN
+      || r_type == R_PPC64_REL14_BRNTAKEN)
     max_branch_offset = 1 << 15;
 
   if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off)
@@ -10419,68 +10871,216 @@ ppc_type_of_stub (asection *input_sec,
   return ppc_stub_none;
 }
 
-/* With power7 weakly ordered memory model, it is possible for ld.so
-   to update a plt entry in one thread and have another thread see a
-   stale zero toc entry.  To avoid this we need some sort of acquire
-   barrier in the call stub.  One solution is to make the load of the
-   toc word seem to appear to depend on the load of the function entry
-   word.  Another solution is to test for r2 being zero, and branch to
-   the appropriate glink entry if so.
-
-   .   fake dep barrier        compare
-   .   ld 12,xxx(2)            ld 12,xxx(2)
-   .   mtctr 12                mtctr 12
-   .   xor 11,12,12            ld 2,xxx+8(2)
-   .   add 2,2,11              cmpldi 2,0
-   .   ld 2,xxx+8(2)           bnectr+
-   .   bctr                    b <glink_entry>
-
-   The solution involving the compare turns out to be faster, so
-   that's what we use unless the branch won't reach.  */
-
-#define ALWAYS_USE_FAKE_DEP 0
-#define ALWAYS_EMIT_R2SAVE 0
+/* Builds a 64-bit offset in r12 then adds it to r11 (LOAD false) or
+   loads r12 from r11+r12 (LOAD true).
+   .   lis     %r12,xxx-1b@highest
+   .   ori     %r12,xxx-1b@higher
+   .   sldi    %r12,%r12,32
+   .   oris    %r12,%r12,xxx-1b@hi
+   .   ori     %r12,%r12,xxx-1b@l
+   .   add     %r12,%r11,%r12  */
 
-static inline unsigned int
-plt_stub_size (struct ppc_link_hash_table *htab,
-              struct ppc_stub_hash_entry *stub_entry,
-              bfd_vma off)
+static bfd_byte *
+build_offset (bfd *abfd, bfd_byte *p, bfd_vma off, bfd_boolean load)
 {
-  unsigned size = 12;
-
-  if (ALWAYS_EMIT_R2SAVE
-      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-    size += 4;
-  if (PPC_HA (off) != 0)
-    size += 4;
-  if (!htab->params->speculate_indirect_jumps)
-    size += 8;
-  if (htab->opd_abi)
+  if (off + 0x8000 < 0x10000)
     {
-      size += 4;
-      if (htab->params->plt_static_chain)
-       size += 4;
-      if (htab->params->plt_thread_safe
-         && htab->elf.dynamic_sections_created
-         && stub_entry->h != NULL
-         && stub_entry->h->elf.dynindx != -1)
-       size += 8;
-      if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
-       size += 4;
+      if (load)
+       bfd_put_32 (abfd, LD_R12_0R11 + PPC_LO (off), p);
+      else
+       bfd_put_32 (abfd, ADDI_R12_R11 + PPC_LO (off), p);
+      p += 4;
     }
-  if (stub_entry->h != NULL
-      && (stub_entry->h == htab->tls_get_addr_fd
-         || stub_entry->h == htab->tls_get_addr)
-      && htab->params->tls_get_addr_opt)
+  else if (off + 0x80008000ULL < 0x100000000ULL)
     {
-      size += 7 * 4;
-      if (ALWAYS_EMIT_R2SAVE
-         || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+      bfd_put_32 (abfd, ADDIS_R12_R11 + PPC_HA (off), p);
+      p += 4;
+      if (load)
+       bfd_put_32 (abfd, LD_R12_0R12 + PPC_LO (off), p);
+      else
+       bfd_put_32 (abfd, ADDI_R12_R12 + PPC_LO (off), p);
+      p += 4;
+    }
+  else
+    {
+      if (off + 0x800000000000ULL < 0x1000000000000ULL)
+       {
+         bfd_put_32 (abfd, LI_R12_0 + ((off >> 32) & 0xffff), p);
+         p += 4;
+       }
+      else
+       {
+         bfd_put_32 (abfd, LIS_R12 + ((off >> 48) & 0xffff), p);
+         p += 4;
+         if (((off >> 32) & 0xffff) != 0)
+           {
+             bfd_put_32 (abfd, ORI_R12_R12_0 + ((off >> 32) & 0xffff), p);
+             p += 4;
+           }
+       }
+      if (((off >> 32) & 0xffffffffULL) != 0)
+       {
+         bfd_put_32 (abfd, SLDI_R12_R12_32, p);
+         p += 4;
+       }
+      if (PPC_HI (off) != 0)
+       {
+         bfd_put_32 (abfd, ORIS_R12_R12_0 + PPC_HI (off), p);
+         p += 4;
+       }
+      if (PPC_LO (off) != 0)
+       {
+         bfd_put_32 (abfd, ORI_R12_R12_0 + PPC_LO (off), p);
+         p += 4;
+       }
+      if (load)
+       bfd_put_32 (abfd, LDX_R12_R11_R12, p);
+      else
+       bfd_put_32 (abfd, ADD_R12_R11_R12, p);
+      p += 4;
+    }
+  return p;
+}
+
+static unsigned int
+size_offset (bfd_vma off)
+{
+  unsigned int size;
+  if (off + 0x8000 < 0x10000)
+    size = 4;
+  else if (off + 0x80008000ULL < 0x100000000ULL)
+    size = 8;
+  else
+    {
+      if (off + 0x800000000000ULL < 0x1000000000000ULL)
+       size = 4;
+      else
        {
-         size += 6 * 4;
-         if (!htab->params->speculate_indirect_jumps)
-           size -= 4;
+         size = 4;
+         if (((off >> 32) & 0xffff) != 0)
+           size += 4;
        }
+      if (((off >> 32) & 0xffffffffULL) != 0)
+       size += 4;
+      if (PPC_HI (off) != 0)
+       size += 4;
+      if (PPC_LO (off) != 0)
+       size += 4;
+      size += 4;
+    }
+  return size;
+}
+
+/* Emit .eh_frame opcode to advance pc by DELTA.  */
+
+static bfd_byte *
+eh_advance (bfd *abfd, bfd_byte *eh, unsigned int delta)
+{
+  delta /= 4;
+  if (delta < 64)
+    *eh++ = DW_CFA_advance_loc + delta;
+  else if (delta < 256)
+    {
+      *eh++ = DW_CFA_advance_loc1;
+      *eh++ = delta;
+    }
+  else if (delta < 65536)
+    {
+      *eh++ = DW_CFA_advance_loc2;
+      bfd_put_16 (abfd, delta, eh);
+      eh += 2;
+    }
+  else
+    {
+      *eh++ = DW_CFA_advance_loc4;
+      bfd_put_32 (abfd, delta, eh);
+      eh += 4;
+    }
+  return eh;
+}
+
+/* Size of required .eh_frame opcode to advance pc by DELTA.  */
+
+static unsigned int
+eh_advance_size (unsigned int delta)
+{
+  if (delta < 64 * 4)
+    /* DW_CFA_advance_loc+[1..63].  */
+    return 1;
+  if (delta < 256 * 4)
+    /* DW_CFA_advance_loc1, byte.  */
+    return 2;
+  if (delta < 65536 * 4)
+    /* DW_CFA_advance_loc2, 2 bytes.  */
+    return 3;
+  /* DW_CFA_advance_loc4, 4 bytes.  */
+  return 5;
+}
+
+/* With power7 weakly ordered memory model, it is possible for ld.so
+   to update a plt entry in one thread and have another thread see a
+   stale zero toc entry.  To avoid this we need some sort of acquire
+   barrier in the call stub.  One solution is to make the load of the
+   toc word seem to appear to depend on the load of the function entry
+   word.  Another solution is to test for r2 being zero, and branch to
+   the appropriate glink entry if so.
+
+   .   fake dep barrier        compare
+   .   ld 12,xxx(2)            ld 12,xxx(2)
+   .   mtctr 12                mtctr 12
+   .   xor 11,12,12            ld 2,xxx+8(2)
+   .   add 2,2,11              cmpldi 2,0
+   .   ld 2,xxx+8(2)           bnectr+
+   .   bctr                    b <glink_entry>
+
+   The solution involving the compare turns out to be faster, so
+   that's what we use unless the branch won't reach.  */
+
+#define ALWAYS_USE_FAKE_DEP 0
+#define ALWAYS_EMIT_R2SAVE 0
+
+static inline unsigned int
+plt_stub_size (struct ppc_link_hash_table *htab,
+              struct ppc_stub_hash_entry *stub_entry,
+              bfd_vma off)
+{
+  unsigned size;
+
+  if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+    {
+      size = 24 + size_offset (off);
+      if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
+       size += 4;
+      return size;
+    }
+
+  size = 12;
+  if (ALWAYS_EMIT_R2SAVE
+      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+    size += 4;
+  if (PPC_HA (off) != 0)
+    size += 4;
+  if (htab->opd_abi)
+    {
+      size += 4;
+      if (htab->params->plt_static_chain)
+       size += 4;
+      if (htab->params->plt_thread_safe
+         && htab->elf.dynamic_sections_created
+         && stub_entry->h != NULL
+         && stub_entry->h->elf.dynindx != -1)
+       size += 8;
+      if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
+       size += 4;
+    }
+  if (stub_entry->h != NULL
+      && (stub_entry->h == htab->tls_get_addr_fd
+         || stub_entry->h == htab->tls_get_addr)
+      && htab->params->tls_get_addr_opt)
+    {
+      size += 7 * 4;
+      if (stub_entry->stub_type == ppc_stub_plt_call_r2save)
+       size += 6 * 4;
     }
   return size;
 }
@@ -10497,7 +11097,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
              bfd_vma plt_off)
 {
   int stub_align;
-  unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
+  unsigned stub_size;
   bfd_vma stub_off = stub_entry->group->stub_sec->size;
 
   if (htab->params->plt_stub_align >= 0)
@@ -10509,32 +11109,13 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
     }
 
   stub_align = 1 << -htab->params->plt_stub_align;
+  stub_size = plt_stub_size (htab, stub_entry, plt_off);
   if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
       > ((stub_size - 1) & -stub_align))
     return stub_align - (stub_off & (stub_align - 1));
   return 0;
 }
 
-static inline bfd_byte *
-output_bctr (struct ppc_link_hash_table *htab, bfd *obfd, bfd_byte *p)
-{
-  if (!htab->params->speculate_indirect_jumps)
-    {
-      bfd_put_32 (obfd, CRSETEQ, p);
-      p += 4;
-      bfd_put_32 (obfd, BEQCTRM, p);
-      p += 4;
-      bfd_put_32 (obfd, B_DOT, p);
-      p += 4;
-    }
-  else
-    {
-      bfd_put_32 (obfd, BCTR, p);
-      p += 4;
-    }
-  return p;
-}
-
 /* Build a .plt call stub.  */
 
 static inline bfd_byte *
@@ -10555,7 +11136,6 @@ build_plt_stub (struct ppc_link_hash_table *htab,
   if (!ALWAYS_USE_FAKE_DEP
       && plt_load_toc
       && plt_thread_safe
-      && htab->params->speculate_indirect_jumps
       && !((stub_entry->h == htab->tls_get_addr_fd
            || stub_entry->h == htab->tls_get_addr)
           && htab->params->tls_get_addr_opt))
@@ -10710,7 +11290,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4;
     }
   else
-    p = output_bctr (htab, obfd, p);
+    bfd_put_32 (obfd, BCTR, p),                                        p += 4;
   return p;
 }
 
@@ -10734,6 +11314,7 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
                         bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 {
   bfd *obfd = htab->params->stub_bfd;
+  bfd_byte *loc = p;
 
   bfd_put_32 (obfd, LD_R11_0R3 + 0, p),                p += 4;
   bfd_put_32 (obfd, LD_R12_0R3 + 8, p),                p += 4;
@@ -10744,8 +11325,7 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   bfd_put_32 (obfd, MR_R3_R0, p),              p += 4;
   if (r != NULL)
     r[0].r_offset += 7 * 4;
-  if (!ALWAYS_EMIT_R2SAVE
-      && stub_entry->stub_type != ppc_stub_plt_call_r2save)
+  if (stub_entry->stub_type != ppc_stub_plt_call_r2save)
     return build_plt_stub (htab, stub_entry, p, offset, r);
 
   bfd_put_32 (obfd, MFLR_R11, p),              p += 4;
@@ -10754,19 +11334,33 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
   if (r != NULL)
     r[0].r_offset += 2 * 4;
   p = build_plt_stub (htab, stub_entry, p, offset, r);
-  if (!htab->params->speculate_indirect_jumps)
-    {
-      p -= 4;
-      bfd_put_32 (obfd, BEQCTRLM, p - 4);
-    }
-  else
-    bfd_put_32 (obfd, BCTRL, p - 4);
+  bfd_put_32 (obfd, BCTRL, p - 4);
 
   bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p),    p += 4;
   bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p),        p += 4;
   bfd_put_32 (obfd, MTLR_R11, p),              p += 4;
   bfd_put_32 (obfd, BLR, p),                   p += 4;
 
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0)
+    {
+      bfd_byte *base, *eh;
+      unsigned int lr_used, delta;
+
+      base = htab->glink_eh_frame->contents + stub_entry->group->eh_base + 17;
+      eh = base + stub_entry->group->eh_size;
+      lr_used = stub_entry->stub_offset + (p - 20 - loc);
+      delta = lr_used - stub_entry->group->lr_restore;
+      stub_entry->group->lr_restore = lr_used + 16;
+      eh = eh_advance (htab->elf.dynobj, eh, delta);
+      *eh++ = DW_CFA_offset_extended_sf;
+      *eh++ = 65;
+      *eh++ = -(STK_LINKER (htab) / 8) & 0x7f;
+      *eh++ = DW_CFA_advance_loc + 4;
+      *eh++ = DW_CFA_restore_extended;
+      *eh++ = 65;
+      stub_entry->group->eh_size = eh - base;
+    }
   return p;
 }
 
@@ -10820,7 +11414,7 @@ get_r2off (struct bfd_link_info *info,
       if (strcmp (opd->name, ".opd") != 0
          || opd->reloc_count != 0)
        {
-         info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"),
+         info->callbacks->einfo (_("%P: cannot find opd entry toc for `%pT'\n"),
                                  stub_entry->h->elf.root.root.string);
          bfd_set_error (bfd_error_bad_value);
          return (bfd_vma) -1;
@@ -10843,7 +11437,7 @@ 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;
-  bfd_vma dest, off;
+  bfd_vma targ, off;
   Elf_Internal_Rela *r;
   asection *plt;
 
@@ -10855,8 +11449,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   if (htab == NULL)
     return FALSE;
 
-  /* Make a note of the offset within the stubs for this entry.  */
-  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+  BFD_ASSERT (stub_entry->stub_offset >= stub_entry->group->stub_sec->size);
   loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset;
 
   htab->stub_count[stub_entry->stub_type - 1] += 1;
@@ -10865,16 +11458,16 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
     case ppc_stub_long_branch:
     case ppc_stub_long_branch_r2off:
       /* Branches are relative.  This is where we are going to.  */
-      dest = (stub_entry->target_value
+      targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
              + stub_entry->target_section->output_section->vma);
-      dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
-      off = dest;
+      targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
 
       /* And this is where we are coming from.  */
-      off -= (stub_entry->stub_offset
-             + stub_entry->group->stub_sec->output_offset
-             + stub_entry->group->stub_sec->output_section->vma);
+      off = (stub_entry->stub_offset
+            + stub_entry->group->stub_sec->output_offset
+            + stub_entry->group->stub_sec->output_section->vma);
+      off = targ - off;
 
       p = loc;
       if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
@@ -10907,8 +11500,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
 
       if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
-         info->callbacks->einfo
-           (_("%P: long branch stub `%s' offset overflow\n"),
+         _bfd_error_handler
+           (_("long branch stub `%s' offset overflow"),
             stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
@@ -10921,7 +11514,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            return FALSE;
          r->r_offset = p - 4 - stub_entry->group->stub_sec->contents;
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
-         r->r_addend = dest;
+         r->r_addend = targ;
          if (stub_entry->h != NULL)
            {
              struct elf_link_hash_entry **hashes;
@@ -10967,19 +11560,19 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                                         FALSE, FALSE);
       if (br_entry == NULL)
        {
-         info->callbacks->einfo (_("%P: can't find branch stub `%s'\n"),
-                                 stub_entry->root.string);
+         _bfd_error_handler (_("can't find branch stub `%s'"),
+                             stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
 
-      dest = (stub_entry->target_value
+      targ = (stub_entry->target_value
              + stub_entry->target_section->output_offset
              + stub_entry->target_section->output_section->vma);
       if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
-       dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
+       targ += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
 
-      bfd_put_64 (htab->brlt->owner, dest,
+      bfd_put_64 (htab->brlt->owner, targ,
                  htab->brlt->contents + br_entry->offset);
 
       if (br_entry->iter == htab->stub_iteration)
@@ -10996,7 +11589,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                               + htab->brlt->output_offset
                               + htab->brlt->output_section->vma);
              rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-             rela.r_addend = dest;
+             rela.r_addend = targ;
 
              rl = htab->relbrlt->contents;
              rl += (htab->relbrlt->reloc_count++
@@ -11016,22 +11609,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
                             + htab->brlt->output_offset
                             + htab->brlt->output_section->vma);
              r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
-             r->r_addend = dest;
+             r->r_addend = targ;
            }
        }
 
-      dest = (br_entry->offset
+      targ = (br_entry->offset
              + htab->brlt->output_offset
              + htab->brlt->output_section->vma);
 
-      off = (dest
-            - elf_gp (info->output_bfd)
-            - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+      off = (elf_gp (info->output_bfd)
+            + htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+      off = targ - off;
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
          info->callbacks->einfo
-           (_("%P: linkage table error against `%T'\n"),
+           (_("%P: linkage table error against `%pT'\n"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
@@ -11049,7 +11642,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
            r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
-         r[0].r_addend = dest;
+         r[0].r_addend = targ;
          if (PPC_HA (off) != 0)
            {
              r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
@@ -11113,7 +11706,106 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       p += 4;
       bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
       p += 4;
-      p = output_bctr (htab, htab->params->stub_bfd, p);
+      bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+      p += 4;
+      break;
+
+    case ppc_stub_long_branch_notoc:
+    case ppc_stub_long_branch_both:
+    case ppc_stub_plt_branch_notoc:
+    case ppc_stub_plt_branch_both:
+    case ppc_stub_plt_call_notoc:
+    case ppc_stub_plt_call_both:
+      p = loc;
+      off = (8 + stub_entry->stub_offset
+            + stub_entry->group->stub_sec->output_offset
+            + stub_entry->group->stub_sec->output_section->vma);
+      if (stub_entry->stub_type == ppc_stub_long_branch_both
+         || stub_entry->stub_type == ppc_stub_plt_branch_both
+         || stub_entry->stub_type == ppc_stub_plt_call_both)
+       {
+         off += 4;
+         bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+         p += 4;
+       }
+      if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+       {
+         targ = stub_entry->plt_ent->plt.offset & ~1;
+         if (targ >= (bfd_vma) -2)
+           abort ();
+
+         plt = htab->elf.splt;
+         if (!htab->elf.dynamic_sections_created
+             || stub_entry->h == NULL
+             || stub_entry->h->elf.dynindx == -1)
+           {
+             if (stub_entry->symtype == STT_GNU_IFUNC)
+               plt = htab->elf.iplt;
+             else
+               plt = htab->pltlocal;
+           }
+         targ += plt->output_offset + plt->output_section->vma;
+       }
+      else
+       targ = (stub_entry->target_value
+               + stub_entry->target_section->output_offset
+               + stub_entry->target_section->output_section->vma);
+      off = targ - off;
+      bfd_put_32 (htab->params->stub_bfd, MFLR_R12, p);
+      p += 4;
+      bfd_put_32 (htab->params->stub_bfd, BCL_20_31, p);
+      p += 4;
+      bfd_put_32 (htab->params->stub_bfd, MFLR_R11, p);
+      p += 4;
+      bfd_put_32 (htab->params->stub_bfd, MTLR_R12, p);
+      p += 4;
+      p = build_offset (htab->params->stub_bfd, p, off,
+                       stub_entry->stub_type >= ppc_stub_plt_call_notoc);
+      if (stub_entry->stub_type == ppc_stub_long_branch_notoc)
+       {
+         off += 8;
+         bfd_put_32 (htab->params->stub_bfd,
+                     B_DOT | ((off - (p - loc)) & 0x3fffffc), p);
+       }
+      else if (stub_entry->stub_type == ppc_stub_long_branch_both)
+       {
+         off += 12;
+         bfd_put_32 (htab->params->stub_bfd,
+                     B_DOT | ((off - (p - loc)) & 0x3fffffc), p);
+       }
+      else
+       {
+         bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+         p += 4;
+         bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+       }
+      p += 4;
+
+      if (htab->glink_eh_frame != NULL
+       && htab->glink_eh_frame->size != 0)
+       {
+         bfd_byte *base, *eh;
+         unsigned int lr_used, delta;
+
+         base = (htab->glink_eh_frame->contents
+                 + stub_entry->group->eh_base + 17);
+         eh = base + stub_entry->group->eh_size;
+         lr_used = stub_entry->stub_offset + 8;
+         if (stub_entry->stub_type == ppc_stub_long_branch_both
+             || stub_entry->stub_type == ppc_stub_plt_branch_both
+             || stub_entry->stub_type == ppc_stub_plt_call_both)
+           lr_used += 4;
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->lr_restore = lr_used + 8;
+         eh = eh_advance (htab->elf.dynobj, eh, delta);
+         *eh++ = DW_CFA_register;
+         *eh++ = 65;
+         *eh++ = 12;
+         *eh++ = DW_CFA_advance_loc + 2;
+         *eh++ = DW_CFA_restore_extended;
+         *eh++ = 65;
+         stub_entry->group->eh_size = eh - base;
+       }
       break;
 
     case ppc_stub_plt_call:
@@ -11133,50 +11825,31 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
        }
 
       /* Now build the stub.  */
-      dest = stub_entry->plt_ent->plt.offset & ~1;
-      if (dest >= (bfd_vma) -2)
+      targ = stub_entry->plt_ent->plt.offset & ~1;
+      if (targ >= (bfd_vma) -2)
        abort ();
 
       plt = htab->elf.splt;
       if (!htab->elf.dynamic_sections_created
          || stub_entry->h == NULL
          || stub_entry->h->elf.dynindx == -1)
-       plt = htab->elf.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;
-         if (htab->opd_abi)
-           rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+         if (stub_entry->symtype == STT_GNU_IFUNC)
+           plt = htab->elf.iplt;
          else
-           rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
-         rela.r_addend = (stub_entry->target_value
-                          + stub_entry->target_section->output_offset
-                          + stub_entry->target_section->output_section->vma);
-
-         rl = (htab->elf.irelplt->contents
-               + (htab->elf.irelplt->reloc_count++
-                  * sizeof (Elf64_External_Rela)));
-         bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
-         stub_entry->plt_ent->plt.offset |= 1;
-         htab->local_ifunc_resolver = 1;
+           plt = htab->pltlocal;
        }
+      targ += plt->output_offset + plt->output_section->vma;
 
-      off = (dest
-            - elf_gp (info->output_bfd)
-            - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+      off = (elf_gp (info->output_bfd)
+            + htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+      off = targ - off;
 
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
          info->callbacks->einfo
            /* xgettext:c-format */
-           (_("%P: linkage table error against `%T'\n"),
+           (_("%P: linkage table error against `%pT'\n"),
             stub_entry->h != NULL
             ? stub_entry->h->elf.root.root.string
             : "<local sym>");
@@ -11185,15 +11858,6 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          return FALSE;
        }
 
-      if (htab->params->plt_stub_align != 0)
-       {
-         unsigned pad = plt_stub_pad (htab, stub_entry, off);
-
-         stub_entry->group->stub_sec->size += pad;
-         stub_entry->stub_offset = stub_entry->group->stub_sec->size;
-         loc += pad;
-       }
-
       r = NULL;
       if (info->emitrelocations)
        {
@@ -11208,7 +11872,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
          r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
          if (bfd_big_endian (info->output_bfd))
            r[0].r_offset += 2;
-         r[0].r_addend = dest;
+         r[0].r_addend = targ;
        }
       if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
@@ -11227,7 +11891,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       return FALSE;
     }
 
-  stub_entry->group->stub_sec->size += p - loc;
+  stub_entry->group->stub_sec->size = stub_entry->stub_offset + (p - loc);
 
   if (htab->params->emit_stub_syms)
     {
@@ -11235,9 +11899,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       size_t len1, len2;
       char *name;
       const char *const stub_str[] = { "long_branch",
-                                      "long_branch_r2off",
+                                      "long_branch",
+                                      "long_branch",
+                                      "long_branch",
+                                      "plt_branch",
+                                      "plt_branch",
                                       "plt_branch",
-                                      "plt_branch_r2off",
+                                      "plt_branch",
+                                      "plt_call",
+                                      "plt_call",
                                       "plt_call",
                                       "plt_call" };
 
@@ -11279,7 +11949,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   struct ppc_stub_hash_entry *stub_entry;
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  bfd_vma off;
+  bfd_vma targ, off;
   int size;
 
   /* Massage our args to the form they really have.  */
@@ -11290,6 +11960,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
   if (htab == NULL)
     return FALSE;
 
+  /* Make a note of the offset within the stubs for this entry.  */
+  stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+
   if (stub_entry->h != NULL
       && stub_entry->h->save_res
       && stub_entry->h->elf.root.type == bfd_link_hash_defined
@@ -11302,44 +11975,100 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       return TRUE;
     }
 
-  if (stub_entry->stub_type == ppc_stub_plt_call
-      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+  if (stub_entry->stub_type >= ppc_stub_plt_call
+      && stub_entry->stub_type <= ppc_stub_plt_call_both)
     {
       asection *plt;
-      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
-      if (off >= (bfd_vma) -2)
+      targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
+      if (targ >= (bfd_vma) -2)
        abort ();
       plt = htab->elf.splt;
       if (!htab->elf.dynamic_sections_created
          || stub_entry->h == NULL
          || stub_entry->h->elf.dynindx == -1)
-       plt = htab->elf.iplt;
-      off += (plt->output_offset
-             + plt->output_section->vma
-             - elf_gp (info->output_bfd)
-             - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+       {
+         if (stub_entry->symtype == STT_GNU_IFUNC)
+           plt = htab->elf.iplt;
+         else
+           plt = htab->pltlocal;
+       }
+      targ += plt->output_offset + plt->output_section->vma;
+
+      if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+       {
+         off = (8 + stub_entry->stub_offset
+                + stub_entry->group->stub_sec->output_offset
+                + stub_entry->group->stub_sec->output_section->vma);
+         if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
+           off += 4;
+       }
+      else
+       off = (elf_gp (info->output_bfd)
+              + htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+
+      if (htab->params->plt_stub_align != 0)
+       {
+         unsigned pad = plt_stub_pad (htab, stub_entry, targ - off);
+
+         stub_entry->group->stub_sec->size += pad;
+         stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+         if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+           off += pad;
+       }
 
+      off = targ - off;
       size = plt_stub_size (htab, stub_entry, off);
-      if (stub_entry->h != NULL
-         && (stub_entry->h == htab->tls_get_addr_fd
-             || stub_entry->h == htab->tls_get_addr)
-         && htab->params->tls_get_addr_opt
-         && (ALWAYS_EMIT_R2SAVE
-             || stub_entry->stub_type == ppc_stub_plt_call_r2save))
-       stub_entry->group->tls_get_addr_opt_bctrl
-         = stub_entry->group->stub_sec->size + size - 5 * 4;
-
-      if (htab->params->plt_stub_align)
-       size += plt_stub_pad (htab, stub_entry, off);
-      if (info->emitrelocations)
+
+      if (stub_entry->stub_type >= ppc_stub_plt_call_notoc)
+       {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         unsigned int lr_used = stub_entry->stub_offset + 8;
+         unsigned int delta;
+         if (stub_entry->stub_type > ppc_stub_plt_call_notoc)
+           lr_used += 4;
+         /* The eh_frame info will consist of a DW_CFA_advance_loc or
+            variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
+            DW_CFA_restore_extended 65.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+       }
+      else
        {
-         stub_entry->group->stub_sec->reloc_count
-           += ((PPC_HA (off) != 0)
-               + (htab->opd_abi
-                  ? 2 + (htab->params->plt_static_chain
-                         && PPC_HA (off + 16) == PPC_HA (off))
-                  : 1));
-         stub_entry->group->stub_sec->flags |= SEC_RELOC;
+         if (stub_entry->h != NULL
+             && (stub_entry->h == htab->tls_get_addr_fd
+                 || stub_entry->h == htab->tls_get_addr)
+             && htab->params->tls_get_addr_opt
+             && stub_entry->stub_type == ppc_stub_plt_call_r2save)
+           {
+             /* After the bctrl, lr has been modified so we need to
+                emit .eh_frame info saying the return address is
+                on the stack.  In fact we put the EH info specifying
+                that the return address is on the stack *at* the
+                call rather than after it, because the EH info for a
+                call needs to be specified by that point.
+                See libgcc/unwind-dw2.c execute_cfa_program.  */
+             unsigned int lr_used = stub_entry->stub_offset + size - 20;
+             unsigned int delta;
+             /* The eh_frame info will consist of a DW_CFA_advance_loc
+                or variant, DW_CFA_offset_externed_sf, 65, -stackoff,
+                DW_CFA_advance_loc+4, DW_CFA_restore_extended, 65.  */
+             delta = lr_used - stub_entry->group->lr_restore;
+             stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+             stub_entry->group->lr_restore = size - 4;
+           }
+
+         if (info->emitrelocations)
+           {
+             stub_entry->group->stub_sec->reloc_count
+               += ((PPC_HA (off) != 0)
+                   + (htab->opd_abi
+                      ? 2 + (htab->params->plt_static_chain
+                             && PPC_HA (off + 16) == PPC_HA (off))
+                      : 1));
+             stub_entry->group->stub_sec->flags |= SEC_RELOC;
+           }
        }
     }
   else
@@ -11349,12 +12078,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       bfd_vma r2off = 0;
       bfd_vma local_off = 0;
 
-      off = (stub_entry->target_value
-            + stub_entry->target_section->output_offset
-            + stub_entry->target_section->output_section->vma);
-      off -= (stub_entry->group->stub_sec->size
-             + stub_entry->group->stub_sec->output_offset
-             + stub_entry->group->stub_sec->output_section->vma);
+      targ = (stub_entry->target_value
+             + stub_entry->target_section->output_offset
+             + stub_entry->target_section->output_section->vma);
+      off = (stub_entry->stub_offset
+            + stub_entry->group->stub_sec->output_offset
+            + stub_entry->group->stub_sec->output_section->vma);
 
       /* Reset the stub type from the plt variant in case we now
         can reach with a shorter stub.  */
@@ -11375,84 +12104,117 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
            size += 4;
          if (PPC_LO (r2off) != 0)
            size += 4;
-         off -= size - 4;
+         off += size - 4;
        }
-
-      local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
-
-      /* If the branch offset if too big, use a ppc_stub_plt_branch.
-        Do the same for -R objects without function descriptors.  */
-      if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
-         || (stub_entry->stub_type == ppc_stub_long_branch_r2off
-             && r2off == 0
-             && htab->sec_info[stub_entry->target_section->id].toc_off == 0))
+      else if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
        {
-         struct ppc_branch_hash_entry *br_entry;
+         size = 20 + size_offset (targ - (off + 8));
+         if (stub_entry->stub_type > ppc_stub_long_branch_notoc)
+           size += 4;
+         off += size - 4;
+       }
+      off = targ - off;
 
-         br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
-                                            stub_entry->root.string + 9,
-                                            TRUE, FALSE);
-         if (br_entry == NULL)
+      if (stub_entry->stub_type >= ppc_stub_long_branch_notoc)
+       {
+         /* After the bcl, lr has been modified so we need to emit
+            .eh_frame info saying the return address is in r12.  */
+         unsigned int lr_used = stub_entry->stub_offset + 8;
+         unsigned int delta;
+         if (stub_entry->stub_type > ppc_stub_long_branch_notoc)
+           lr_used += 4;
+         /* The eh_frame info will consist of a DW_CFA_advance_loc or
+            variant, DW_CFA_register, 65, 12, DW_CFA_advance_loc+2,
+            DW_CFA_restore_extended 65.  */
+         delta = lr_used - stub_entry->group->lr_restore;
+         stub_entry->group->eh_size += eh_advance_size (delta) + 6;
+         stub_entry->group->lr_restore = lr_used + 8;
+
+         if (off + (1 << 25) >= (bfd_vma) (1 << 26))
            {
-             info->callbacks->einfo (_("%P: can't build branch stub `%s'\n"),
-                                     stub_entry->root.string);
-             htab->stub_error = TRUE;
-             return FALSE;
+             stub_entry->stub_type += (ppc_stub_plt_branch_notoc
+                                       - ppc_stub_long_branch_notoc);
+             size += 4;
            }
-
-         if (br_entry->iter != htab->stub_iteration)
+       }
+      else
+       {
+         local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other);
+
+         /* If the branch offset is too big, use a ppc_stub_plt_branch.
+            Do the same for -R objects without function descriptors.  */
+         if ((stub_entry->stub_type == ppc_stub_long_branch_r2off
+              && r2off == 0
+              && htab->sec_info[stub_entry->target_section->id].toc_off == 0)
+             || off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off)
            {
-             br_entry->iter = htab->stub_iteration;
-             br_entry->offset = htab->brlt->size;
-             htab->brlt->size += 8;
+             struct ppc_branch_hash_entry *br_entry;
 
-             if (htab->relbrlt != NULL)
-               htab->relbrlt->size += sizeof (Elf64_External_Rela);
-             else if (info->emitrelocations)
+             br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
+                                                stub_entry->root.string + 9,
+                                                TRUE, FALSE);
+             if (br_entry == NULL)
                {
-                 htab->brlt->reloc_count += 1;
-                 htab->brlt->flags |= SEC_RELOC;
+                 _bfd_error_handler (_("can't build branch stub `%s'"),
+                                     stub_entry->root.string);
+                 htab->stub_error = TRUE;
+                 return FALSE;
                }
-           }
 
-         stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch;
-         off = (br_entry->offset
-                + htab->brlt->output_offset
-                + htab->brlt->output_section->vma
-                - elf_gp (info->output_bfd)
-                - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+             if (br_entry->iter != htab->stub_iteration)
+               {
+                 br_entry->iter = htab->stub_iteration;
+                 br_entry->offset = htab->brlt->size;
+                 htab->brlt->size += 8;
 
-         if (info->emitrelocations)
-           {
-             stub_entry->group->stub_sec->reloc_count
-               += 1 + (PPC_HA (off) != 0);
-             stub_entry->group->stub_sec->flags |= SEC_RELOC;
-           }
+                 if (htab->relbrlt != NULL)
+                   htab->relbrlt->size += sizeof (Elf64_External_Rela);
+                 else if (info->emitrelocations)
+                   {
+                     htab->brlt->reloc_count += 1;
+                     htab->brlt->flags |= SEC_RELOC;
+                   }
+               }
 
-         if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
-           {
-             size = 12;
-             if (PPC_HA (off) != 0)
-               size = 16;
+             targ = (br_entry->offset
+                     + htab->brlt->output_offset
+                     + htab->brlt->output_section->vma);
+             off = (elf_gp (info->output_bfd)
+                    + htab->sec_info[stub_entry->group->link_sec->id].toc_off);
+             off = targ - off;
+
+             if (info->emitrelocations)
+               {
+                 stub_entry->group->stub_sec->reloc_count
+                   += 1 + (PPC_HA (off) != 0);
+                 stub_entry->group->stub_sec->flags |= SEC_RELOC;
+               }
+
+             stub_entry->stub_type
+               += ppc_stub_plt_branch - ppc_stub_long_branch;
+             if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
+               {
+                 size = 12;
+                 if (PPC_HA (off) != 0)
+                   size = 16;
+               }
+             else
+               {
+                 size = 16;
+                 if (PPC_HA (off) != 0)
+                   size += 4;
+
+                 if (PPC_HA (r2off) != 0)
+                   size += 4;
+                 if (PPC_LO (r2off) != 0)
+                   size += 4;
+               }
            }
-         else
+         else if (info->emitrelocations)
            {
-             size = 16;
-             if (PPC_HA (off) != 0)
-               size += 4;
-
-             if (PPC_HA (r2off) != 0)
-               size += 4;
-             if (PPC_LO (r2off) != 0)
-               size += 4;
+             stub_entry->group->stub_sec->reloc_count += 1;
+             stub_entry->group->stub_sec->flags |= SEC_RELOC;
            }
-         if (!htab->params->speculate_indirect_jumps)
-           size += 8;
-       }
-      else if (info->emitrelocations)
-       {
-         stub_entry->group->stub_sec->reloc_count += 1;
-         stub_entry->group->stub_sec->flags |= SEC_RELOC;
        }
     }
 
@@ -11474,7 +12236,7 @@ ppc64_elf_setup_section_lists (struct bfd_link_info *info)
   if (htab == NULL)
     return -1;
 
-  htab->sec_info_arr_size = bfd_get_next_section_id ();
+  htab->sec_info_arr_size = _bfd_section_id;
   amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size);
   htab->sec_info = bfd_zmalloc (amt);
   if (htab->sec_info == NULL)
@@ -11721,12 +12483,14 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  rel_size *= 2;
                }
              s->size += ent_size;
-             if ((*lgot_masks & PLT_IFUNC) != 0)
+             if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
                {
                  htab->elf.irelplt->size += rel_size;
                  htab->got_reli_size += rel_size;
                }
-             else if (bfd_link_pic (info))
+             else if (bfd_link_pic (info)
+                      && !((ent->tls_type & TLS_TPREL) != 0
+                           && bfd_link_executable (info)))
                {
                  asection *srel = ppc64_elf_tdata (ibfd)->relgot;
                  srel->size += rel_size;
@@ -11858,9 +12622,11 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
 
          r_type = ELF64_R_TYPE (rel->r_info);
          if (r_type != R_PPC64_REL24
+             && r_type != R_PPC64_REL24_NOTOC
              && r_type != R_PPC64_REL14
              && r_type != R_PPC64_REL14_BRTAKEN
-             && r_type != R_PPC64_REL14_BRNTAKEN)
+             && r_type != R_PPC64_REL14_BRNTAKEN
+             && r_type != R_PPC64_PLTCALL)
            continue;
 
          r_symndx = ELF64_R_SYM (rel->r_info);
@@ -12169,7 +12935,7 @@ group_sections (struct bfd_link_info *info,
          big_sec = total > group_size;
          if (big_sec && !suppress_size_errors)
            /* xgettext:c-format */
-           _bfd_error_handler (_("%B section %A exceeds stub group size"),
+           _bfd_error_handler (_("%pB section %pA exceeds stub group size"),
                                tail->owner, tail);
          curr_toc = htab->sec_info[tail->id].toc_off;
 
@@ -12197,7 +12963,9 @@ group_sections (struct bfd_link_info *info,
          group->link_sec = curr;
          group->stub_sec = NULL;
          group->needs_save_res = 0;
-         group->tls_get_addr_opt_bctrl = -1u;
+         group->lr_restore = 0;
+         group->eh_size = 0;
+         group->eh_base = 0;
          group->next = htab->group;
          htab->group = group;
          do
@@ -12248,27 +13016,6 @@ static const unsigned char glink_eh_frame_cie[] =
   DW_CFA_def_cfa, 1, 0                 /* def_cfa: r1 offset 0.  */
 };
 
-static size_t
-stub_eh_frame_size (struct map_stub *group, size_t align)
-{
-  size_t this_size = 17;
-  if (group->tls_get_addr_opt_bctrl != -1u)
-    {
-      unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
-      if (to_bctrl < 64)
-       this_size += 1;
-      else if (to_bctrl < 256)
-       this_size += 2;
-      else if (to_bctrl < 65536)
-       this_size += 3;
-      else
-       this_size += 5;
-      this_size += 6;
-    }
-  this_size = (this_size + align - 1) & -align;
-  return this_size;
-}
-
 /* Stripping output sections is normally done before dynamic section
    symbols have been allocated.  This function is called later, and
    handles cases like htab->brlt which is mapped to its own output
@@ -12453,6 +13200,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
                  /* Only look for stubs on branch instructions.  */
                  if (r_type != R_PPC64_REL24
+                     && r_type != R_PPC64_REL24_NOTOC
                      && r_type != R_PPC64_REL14
                      && r_type != R_PPC64_REL14_BRTAKEN
                      && r_type != R_PPC64_REL14_BRNTAKEN)
@@ -12560,7 +13308,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                                                &plt_ent, destination,
                                                local_off);
 
-                 if (stub_type != ppc_stub_plt_call)
+                 if (r_type == R_PPC64_REL24_NOTOC)
+                   {
+                     if (stub_type == ppc_stub_plt_call)
+                       stub_type = ppc_stub_plt_call_notoc;
+                     else if (stub_type == ppc_stub_long_branch
+                              || (code_sec != NULL
+                                  && code_sec->output_section != NULL
+                                  && (((hash ? hash->elf.other : sym->st_other)
+                                       & STO_PPC64_LOCAL_MASK)
+                                      != 1 << STO_PPC64_LOCAL_BIT)))
+                       stub_type = ppc_stub_long_branch_notoc;
+                   }
+                 else if (stub_type != ppc_stub_plt_call)
                    {
                      /* Check whether we need a TOC adjusting stub.
                         Since the linker pastes together pieces from
@@ -12568,12 +13328,15 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                         _init and _fini functions, it may be that a
                         call to what looks like a local sym is in
                         fact a call needing a TOC adjustment.  */
-                     if (code_sec != NULL
-                         && code_sec->output_section != NULL
-                         && (htab->sec_info[code_sec->id].toc_off
-                             != htab->sec_info[section->id].toc_off)
-                         && (code_sec->has_toc_reloc
-                             || code_sec->makes_toc_func_call))
+                     if ((code_sec != NULL
+                          && code_sec->output_section != NULL
+                          && (htab->sec_info[code_sec->id].toc_off
+                              != htab->sec_info[section->id].toc_off)
+                          && (code_sec->has_toc_reloc
+                              || code_sec->makes_toc_func_call))
+                         || (((hash ? hash->elf.other : sym->st_other)
+                              & STO_PPC64_LOCAL_MASK)
+                             == 1 << STO_PPC64_LOCAL_BIT))
                        stub_type = ppc_stub_long_branch_r2off;
                    }
 
@@ -12582,6 +13345,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
 
                  /* __tls_get_addr calls might be eliminated.  */
                  if (stub_type != ppc_stub_plt_call
+                     && stub_type != ppc_stub_plt_call_notoc
                      && hash != NULL
                      && (hash == htab->tls_get_addr
                          || hash == htab->tls_get_addr_fd)
@@ -12594,7 +13358,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                      if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
                                         irela - 1, input_bfd))
                        goto error_ret_free_internal;
-                     if (*tls_mask != 0)
+                     if ((*tls_mask & TLS_TLS) != 0)
                        continue;
                    }
 
@@ -12629,9 +13393,71 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                                                     stub_name, FALSE, FALSE);
                  if (stub_entry != NULL)
                    {
-                     /* The proper stub has already been created.  */
+                     enum ppc_stub_type old_type;
+                     /* A stub has already been created, but it may
+                        not be the required type.  We shouldn't be
+                        transitioning from plt_call to long_branch
+                        stubs or vice versa, but we might be
+                        upgrading from plt_call to plt_call_r2save or
+                        from long_branch to long_branch_r2off.  */
                      free (stub_name);
-                     if (stub_type == ppc_stub_plt_call_r2save)
+                     old_type = stub_entry->stub_type;
+                     switch (old_type)
+                       {
+                       default:
+                         abort ();
+
+                       case ppc_stub_save_res:
+                         continue;
+
+                       case ppc_stub_plt_call:
+                       case ppc_stub_plt_call_r2save:
+                       case ppc_stub_plt_call_notoc:
+                       case ppc_stub_plt_call_both:
+                         if (stub_type == ppc_stub_plt_call)
+                           continue;
+                         else if (stub_type == ppc_stub_plt_call_r2save)
+                           {
+                             if (old_type == ppc_stub_plt_call_notoc)
+                               stub_type = ppc_stub_plt_call_both;
+                           }
+                         else if (stub_type == ppc_stub_plt_call_notoc)
+                           {
+                             if (old_type == ppc_stub_plt_call_r2save)
+                               stub_type = ppc_stub_plt_call_both;
+                           }
+                         else
+                           abort ();
+                         break;
+
+                       case ppc_stub_plt_branch:
+                       case ppc_stub_plt_branch_r2off:
+                       case ppc_stub_plt_branch_notoc:
+                       case ppc_stub_plt_branch_both:
+                         old_type += (ppc_stub_long_branch
+                                      - ppc_stub_plt_branch);
+                         /* Fall through.  */
+                       case ppc_stub_long_branch:
+                       case ppc_stub_long_branch_r2off:
+                       case ppc_stub_long_branch_notoc:
+                       case ppc_stub_long_branch_both:
+                         if (stub_type == ppc_stub_long_branch)
+                           continue;
+                         else if (stub_type == ppc_stub_long_branch_r2off)
+                           {
+                             if (old_type == ppc_stub_long_branch_notoc)
+                               stub_type = ppc_stub_long_branch_both;
+                           }
+                         else if (stub_type == ppc_stub_long_branch_notoc)
+                           {
+                             if (old_type == ppc_stub_long_branch_r2off)
+                               stub_type = ppc_stub_long_branch_both;
+                           }
+                         else
+                           abort ();
+                         break;
+                       }
+                     if (old_type < stub_type)
                        stub_entry->stub_type = stub_type;
                      continue;
                    }
@@ -12652,19 +13478,21 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
                    }
 
                  stub_entry->stub_type = stub_type;
-                 if (stub_type != ppc_stub_plt_call
-                     && stub_type != ppc_stub_plt_call_r2save)
+                 if (stub_type >= ppc_stub_plt_call
+                     && stub_type <= ppc_stub_plt_call_both)
                    {
-                     stub_entry->target_value = code_value;
-                     stub_entry->target_section = code_sec;
+                     stub_entry->target_value = sym_value;
+                     stub_entry->target_section = sym_sec;
                    }
                  else
                    {
-                     stub_entry->target_value = sym_value;
-                     stub_entry->target_section = sym_sec;
+                     stub_entry->target_value = code_value;
+                     stub_entry->target_section = code_sec;
                    }
                  stub_entry->h = hash;
                  stub_entry->plt_ent = plt_ent;
+                 stub_entry->symtype
+                   = hash ? hash->elf.type : ELF_ST_TYPE (sym->st_info);
                  stub_entry->other = hash ? hash->elf.other : sym->st_other;
 
                  if (stub_entry->h != NULL)
@@ -12689,19 +13517,26 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       /* We may have added some stubs.  Find out the new size of the
         stub sections.  */
       for (group = htab->group; group != NULL; group = group->next)
-       if (group->stub_sec != NULL)
-         {
-           asection *stub_sec = group->stub_sec;
-
-           if (htab->stub_iteration <= STUB_SHRINK_ITER
-               || stub_sec->rawsize < stub_sec->size)
-             /* Past STUB_SHRINK_ITER, rawsize is the max size seen.  */
-             stub_sec->rawsize = stub_sec->size;
-           stub_sec->size = 0;
-           stub_sec->reloc_count = 0;
-           stub_sec->flags &= ~SEC_RELOC;
-         }
+       {
+         group->lr_restore = 0;
+         group->eh_size = 0;
+         if (group->stub_sec != NULL)
+           {
+             asection *stub_sec = group->stub_sec;
+
+             if (htab->stub_iteration <= STUB_SHRINK_ITER
+                 || stub_sec->rawsize < stub_sec->size)
+               /* Past STUB_SHRINK_ITER, rawsize is the max size seen.  */
+               stub_sec->rawsize = stub_sec->size;
+             stub_sec->size = 0;
+             stub_sec->reloc_count = 0;
+             stub_sec->flags &= ~SEC_RELOC;
+           }
+       }
 
+      if (htab->stub_iteration <= STUB_SHRINK_ITER
+         || htab->brlt->rawsize < htab->brlt->size)
+       htab->brlt->rawsize = htab->brlt->size;
       htab->brlt->size = 0;
       htab->brlt->reloc_count = 0;
       htab->brlt->flags &= ~SEC_RELOC;
@@ -12728,8 +13563,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          size_t size = 0, align = 4;
 
          for (group = htab->group; group != NULL; group = group->next)
-           if (group->stub_sec != NULL)
-             size += stub_eh_frame_size (group, align);
+           if (group->eh_size != 0)
+             size += (group->eh_size + 17 + align - 1) & -align;
          if (htab->glink != NULL && htab->glink->size != 0)
            size += (24 + align - 1) & -align;
          if (size != 0)
@@ -12757,6 +13592,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
          break;
 
       if (group == NULL
+         && (htab->brlt->rawsize == htab->brlt->size
+             || (htab->stub_iteration > STUB_SHRINK_ITER
+                 && htab->brlt->rawsize > htab->brlt->size))
          && (htab->glink_eh_frame == NULL
              || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
        break;
@@ -12773,6 +13611,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       size_t last_fde_len, size, align, pad;
       struct map_stub *group;
 
+      /* It is necessary to at least have a rough outline of the
+        linker generated CIEs and FDEs written before
+        bfd_elf_discard_info is run, in order for these FDEs to be
+        indexed in .eh_frame_hdr.  */
       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
       if (p == NULL)
        return FALSE;
@@ -12787,10 +13629,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
       p += last_fde_len + 4;
 
       for (group = htab->group; group != NULL; group = group->next)
-       if (group->stub_sec != NULL)
+       if (group->eh_size != 0)
          {
+           group->eh_base = p - htab->glink_eh_frame->contents;
            last_fde = p;
-           last_fde_len = stub_eh_frame_size (group, align) - 4;
+           last_fde_len = ((group->eh_size + 17 + align - 1) & -align) - 4;
            /* FDE length.  */
            bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
            p += 4;
@@ -12805,39 +13648,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
            p += 4;
            /* Augmentation.  */
            p += 1;
-           if (group->tls_get_addr_opt_bctrl != -1u)
-             {
-               unsigned int to_bctrl = group->tls_get_addr_opt_bctrl / 4;
-
-               /* This FDE needs more than just the default.
-                  Describe __tls_get_addr_opt stub LR.  */
-               if (to_bctrl < 64)
-                 *p++ = DW_CFA_advance_loc + to_bctrl;
-               else if (to_bctrl < 256)
-                 {
-                   *p++ = DW_CFA_advance_loc1;
-                   *p++ = to_bctrl;
-                 }
-               else if (to_bctrl < 65536)
-                 {
-                   *p++ = DW_CFA_advance_loc2;
-                   bfd_put_16 (htab->elf.dynobj, to_bctrl, p);
-                   p += 2;
-                 }
-               else
-                 {
-                   *p++ = DW_CFA_advance_loc4;
-                   bfd_put_32 (htab->elf.dynobj, to_bctrl, p);
-                   p += 4;
-                 }
-               *p++ = DW_CFA_offset_extended_sf;
-               *p++ = 65;
-               *p++ = -(STK_LINKER (htab) / 8) & 0x7f;
-               *p++ = DW_CFA_advance_loc + 4;
-               *p++ = DW_CFA_restore_extended;
-               *p++ = 65;
-             }
-           /* Pad.  */
+           /* Make sure we don't have all nops.  This is enough for
+              elf-eh-frame.c to detect the last non-nop opcode.  */
+           p[group->eh_size - 1] = DW_CFA_advance_loc + 1;
            p = last_fde + last_fde_len + 4;
          }
       if (htab->glink != NULL && htab->glink->size != 0)
@@ -12997,34 +13810,119 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 }
 
 /* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to
-   write out any global entry stubs.  */
+   write out any global entry stubs, and PLT relocations.  */
 
 static bfd_boolean
-build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
+build_global_entry_stubs_and_plt (struct elf_link_hash_entry *h, void *inf)
 {
   struct bfd_link_info *info;
   struct ppc_link_hash_table *htab;
-  struct plt_entry *pent;
+  struct plt_entry *ent;
   asection *s;
 
   if (h->root.type == bfd_link_hash_indirect)
     return TRUE;
 
+  info = inf;
+  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.  */
+       Elf_Internal_Rela rela;
+       asection *plt, *relplt;
+       bfd_byte *loc;
+
+       if (!htab->elf.dynamic_sections_created
+           || h->dynindx == -1)
+         {
+           if (!(h->def_regular
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak)))
+             continue;
+           if (h->type == STT_GNU_IFUNC)
+             {
+               plt = htab->elf.iplt;
+               relplt = htab->elf.irelplt;
+               htab->local_ifunc_resolver = 1;
+               if (htab->opd_abi)
+                 rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+               else
+                 rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+             }
+           else
+             {
+               plt = htab->pltlocal;
+               if (bfd_link_pic (info))
+                 {
+                   relplt = htab->relpltlocal;
+                   if (htab->opd_abi)
+                     rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+                   else
+                     rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                 }
+               else
+                 relplt = NULL;
+             }
+           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);
+
+           if (relplt == NULL)
+             {
+               loc = plt->contents + ent->plt.offset;
+               bfd_put_64 (info->output_bfd, rela.r_addend, loc);
+               if (htab->opd_abi)
+                 {
+                   bfd_vma toc = elf_gp (info->output_bfd);
+                   toc += htab->sec_info[h->root.u.def.section->id].toc_off;
+                   bfd_put_64 (info->output_bfd, toc, loc + 8);
+                 }
+             }
+           else
+             {
+               rela.r_offset = (plt->output_section->vma
+                                + plt->output_offset
+                                + ent->plt.offset);
+               loc = relplt->contents + (relplt->reloc_count++
+                                         * sizeof (Elf64_External_Rela));
+               bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+             }
+         }
+       else
+         {
+           rela.r_offset = (htab->elf.splt->output_section->vma
+                            + htab->elf.splt->output_offset
+                            + ent->plt.offset);
+           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
+           rela.r_addend = ent->addend;
+           loc = (htab->elf.srelplt->contents
+                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
+                     / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
+           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
+             htab->maybe_local_ifunc_resolver = 1;
+           bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+         }
+      }
+
   if (!h->pointer_equality_needed)
     return TRUE;
 
   if (h->def_regular)
     return TRUE;
 
-  info = inf;
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
   s = htab->global_entry;
-  for (pent = h->plt.plist; pent != NULL; pent = pent->next)
-    if (pent->plt.offset != (bfd_vma) -1
-       && pent->addend == 0)
+  if (s == NULL || s->size == 0)
+    return TRUE;
+
+  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+    if (ent->plt.offset != (bfd_vma) -1
+       && ent->addend == 0)
       {
        bfd_byte *p;
        asection *plt;
@@ -13034,14 +13932,19 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
        plt = htab->elf.splt;
        if (!htab->elf.dynamic_sections_created
            || h->dynindx == -1)
-         plt = htab->elf.iplt;
-       off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
+         {
+           if (h->type == STT_GNU_IFUNC)
+             plt = htab->elf.iplt;
+           else
+             plt = htab->pltlocal;
+         }
+       off = ent->plt.offset + plt->output_offset + plt->output_section->vma;
        off -= h->root.u.def.value + s->output_offset + s->output_section->vma;
 
        if (off + 0x80008000 > 0xffffffff || (off & 3) != 0)
          {
            info->callbacks->einfo
-             (_("%P: linkage table error against `%T'\n"),
+             (_("%P: linkage table error against `%pT'\n"),
               h->root.root.string);
            bfd_set_error (bfd_error_bad_value);
            htab->stub_error = TRUE;
@@ -13074,18 +13977,132 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf)
              }
          }
 
-       if (PPC_HA (off) != 0)
-         {
-           bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p);
-           p += 4;
-         }
-       bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p);
-       p += 4;
-       bfd_put_32 (s->owner, MTCTR_R12, p);
-       p += 4;
-       output_bctr (htab, s->owner, p);
-       break;
-      }
+       if (PPC_HA (off) != 0)
+         {
+           bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p);
+           p += 4;
+         }
+       bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p);
+       p += 4;
+       bfd_put_32 (s->owner, MTCTR_R12, p);
+       p += 4;
+       bfd_put_32 (s->owner, BCTR, p);
+       break;
+      }
+  return TRUE;
+}
+
+/* Write PLT relocs for locals.  */
+
+static bfd_boolean
+write_plt_relocs_for_local_syms (struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+  bfd *ibfd;
+
+  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+    {
+      struct got_entry **lgot_ents, **end_lgot_ents;
+      struct plt_entry **local_plt, **lplt, **end_local_plt;
+      Elf_Internal_Shdr *symtab_hdr;
+      bfd_size_type locsymcount;
+      Elf_Internal_Sym *local_syms = NULL;
+      struct plt_entry *ent;
+
+      if (!is_ppc64_elf (ibfd))
+       continue;
+
+      lgot_ents = elf_local_got_ents (ibfd);
+      if (!lgot_ents)
+       continue;
+
+      symtab_hdr = &elf_symtab_hdr (ibfd);
+      locsymcount = symtab_hdr->sh_info;
+      end_lgot_ents = lgot_ents + locsymcount;
+      local_plt = (struct plt_entry **) end_lgot_ents;
+      end_local_plt = local_plt + locsymcount;
+      for (lplt = local_plt; lplt < end_local_plt; ++lplt)
+       for (ent = *lplt; ent != NULL; ent = ent->next)
+         if (ent->plt.offset != (bfd_vma) -1)
+           {
+             Elf_Internal_Sym *sym;
+             asection *sym_sec;
+             asection *plt, *relplt;
+             bfd_byte *loc;
+             bfd_vma val;
+
+             if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
+                             lplt - local_plt, ibfd))
+               {
+                 if (local_syms != NULL
+                     && symtab_hdr->contents != (unsigned char *) local_syms)
+                   free (local_syms);
+                 return FALSE;
+               }
+
+             val = sym->st_value + ent->addend;
+             val += PPC64_LOCAL_ENTRY_OFFSET (sym->st_other);
+             if (sym_sec != NULL && sym_sec->output_section != NULL)
+               val += sym_sec->output_offset + sym_sec->output_section->vma;
+
+             if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+               {
+                 htab->local_ifunc_resolver = 1;
+                 plt = htab->elf.iplt;
+                 relplt = htab->elf.irelplt;
+               }
+             else
+               {
+                 plt = htab->pltlocal;
+                 relplt = bfd_link_pic (info) ? htab->relpltlocal : NULL;
+               }
+
+             if (relplt == NULL)
+               {
+                 loc = plt->contents + ent->plt.offset;
+                 bfd_put_64 (info->output_bfd, val, loc);
+                 if (htab->opd_abi)
+                   {
+                     bfd_vma toc = elf_gp (ibfd);
+                     bfd_put_64 (info->output_bfd, toc, loc + 8);
+                   }
+               }
+             else
+               {
+                 Elf_Internal_Rela rela;
+                 rela.r_offset = (ent->plt.offset
+                                  + plt->output_offset
+                                  + plt->output_section->vma);
+                 if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                   {
+                     if (htab->opd_abi)
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
+                     else
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
+                   }
+                 else
+                   {
+                     if (htab->opd_abi)
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_SLOT);
+                     else
+                       rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
+                   }
+                 rela.r_addend = val;
+                 loc = relplt->contents + (relplt->reloc_count++
+                                           * sizeof (Elf64_External_Rela));
+                 bfd_elf64_swap_reloca_out (info->output_bfd, &rela, loc);
+               }
+           }
+
+      if (local_syms != NULL
+         && symtab_hdr->contents != (unsigned char *) local_syms)
+       {
+         if (!info->keep_memory)
+           free (local_syms);
+         else
+           symtab_hdr->contents = (unsigned char *) local_syms;
+       }
+    }
   return TRUE;
 }
 
@@ -13108,14 +14125,19 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
 
   /* Allocate memory to hold the linker stubs.  */
   for (group = htab->group; group != NULL; group = group->next)
-    if ((stub_sec = group->stub_sec) != NULL
-       && stub_sec->size != 0)
-      {
-       stub_sec->contents = bfd_zalloc (htab->params->stub_bfd, stub_sec->size);
-       if (stub_sec->contents == NULL)
-         return FALSE;
-       stub_sec->size = 0;
-      }
+    {
+      group->eh_size = 0;
+      group->lr_restore = 0;
+      if ((stub_sec = group->stub_sec) != NULL
+         && stub_sec->size != 0)
+       {
+         stub_sec->contents = bfd_zalloc (htab->params->stub_bfd,
+                                          stub_sec->size);
+         if (stub_sec->contents == NULL)
+           return FALSE;
+         stub_sec->size = 0;
+       }
+    }
 
   if (htab->glink != NULL && htab->glink->size != 0)
     {
@@ -13212,7 +14234,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
          bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p);
          p += 4;
        }
-      p = output_bctr (htab, htab->glink->owner, p);
+      bfd_put_32 (htab->glink->owner, BCTR, p);
+      p += 4;
       BFD_ASSERT (p == htab->glink->contents + GLINK_PLTRESOLVE_SIZE (htab));
 
       /* Build the .glink lazy link call stubs.  */
@@ -13242,9 +14265,11 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
        }
     }
 
-  /* Build .glink global entry stubs.  */
-  if (htab->global_entry != NULL && htab->global_entry->size != 0)
-    elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
+  /* Build .glink global entry stubs, and PLT relocs for globals.  */
+  elf_link_hash_traverse (&htab->elf, build_global_entry_stubs_and_plt, info);
+
+  if (!write_plt_relocs_for_local_syms (info))
+    return FALSE;
 
   if (htab->brlt != NULL && htab->brlt->size != 0)
     {
@@ -13264,12 +14289,27 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   /* Build the stubs as directed by the stub hash table.  */
   bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
+  for (group = htab->group; group != NULL; group = group->next)
+    if (group->needs_save_res)
+      group->stub_sec->size += htab->sfpr->size;
+
+  if (htab->relbrlt != NULL)
+    htab->relbrlt->reloc_count = 0;
+
+  if (htab->params->plt_stub_align != 0)
+    for (group = htab->group; group != NULL; group = group->next)
+      if ((stub_sec = group->stub_sec) != NULL)
+       {
+         int align = abs (htab->params->plt_stub_align);
+         stub_sec->size = (stub_sec->size + (1 << align) - 1) & -(1 << align);
+       }
+
   for (group = htab->group; group != NULL; group = group->next)
     if (group->needs_save_res)
       {
        stub_sec = group->stub_sec;
-       memcpy (stub_sec->contents + stub_sec->size, htab->sfpr->contents,
-               htab->sfpr->size);
+       memcpy (stub_sec->contents + stub_sec->size - htab->sfpr->size,
+               htab->sfpr->contents, htab->sfpr->size);
        if (htab->params->emit_stub_syms)
          {
            unsigned int i;
@@ -13278,19 +14318,56 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
              if (!sfpr_define (info, &save_res_funcs[i], stub_sec))
                return FALSE;
          }
-       stub_sec->size += htab->sfpr->size;
       }
 
-  if (htab->relbrlt != NULL)
-    htab->relbrlt->reloc_count = 0;
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0)
+    {
+      bfd_vma val;
+      size_t align = 4;
 
-  if (htab->params->plt_stub_align != 0)
-    for (group = htab->group; group != NULL; group = group->next)
-      if ((stub_sec = group->stub_sec) != NULL)
+      p = htab->glink_eh_frame->contents;
+      p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
+
+      for (group = htab->group; group != NULL; group = group->next)
+       if (group->eh_size != 0)
+         {
+           /* Offset to stub section.  */
+           val = (group->stub_sec->output_section->vma
+                  + group->stub_sec->output_offset);
+           val -= (htab->glink_eh_frame->output_section->vma
+                   + htab->glink_eh_frame->output_offset
+                   + (p + 8 - htab->glink_eh_frame->contents));
+           if (val + 0x80000000 > 0xffffffff)
+             {
+               _bfd_error_handler
+                 (_("%s offset too large for .eh_frame sdata4 encoding"),
+                  group->stub_sec->name);
+               return FALSE;
+             }
+           bfd_put_32 (htab->elf.dynobj, val, p + 8);
+           p += (group->eh_size + 17 + 3) & -4;
+         }
+      if (htab->glink != NULL && htab->glink->size != 0)
        {
-         int align = abs (htab->params->plt_stub_align);
-         stub_sec->size = (stub_sec->size + (1 << align) - 1) & -(1 << align);
+         /* Offset to .glink.  */
+         val = (htab->glink->output_section->vma
+                + htab->glink->output_offset
+                + 8);
+         val -= (htab->glink_eh_frame->output_section->vma
+                 + htab->glink_eh_frame->output_offset
+                 + (p + 8 - htab->glink_eh_frame->contents));
+         if (val + 0x80000000 > 0xffffffff)
+           {
+             _bfd_error_handler
+               (_("%s offset too large for .eh_frame sdata4 encoding"),
+                htab->glink->name);
+             return FALSE;
+           }
+         bfd_put_32 (htab->elf.dynobj, val, p + 8);
+         p += (24 + align - 1) & -align;
        }
+    }
 
   for (group = htab->group; group != NULL; group = group->next)
     if ((stub_sec = group->stub_sec) != NULL)
@@ -13305,7 +14382,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
   if (group != NULL)
     {
       htab->stub_error = TRUE;
-      info->callbacks->einfo (_("%P: stubs don't match calculated size\n"));
+      _bfd_error_handler (_("stubs don't match calculated size"));
     }
 
   if (htab->stub_error)
@@ -13323,19 +14400,31 @@ ppc64_elf_build_stubs (struct bfd_link_info *info,
                               "linker stubs in %u groups\n",
                               stub_sec_count),
                     stub_sec_count);
-      sprintf (*stats + len, _("  branch       %lu\n"
-                              "  toc adjust   %lu\n"
-                              "  long branch  %lu\n"
-                              "  long toc adj %lu\n"
-                              "  plt call     %lu\n"
-                              "  plt call toc %lu\n"
-                              "  global entry %lu"),
+      sprintf (*stats + len, _("  branch         %lu\n"
+                              "  branch toc adj %lu\n"
+                              "  branch notoc   %lu\n"
+                              "  branch both    %lu\n"
+                              "  long branch    %lu\n"
+                              "  long toc adj   %lu\n"
+                              "  long notoc     %lu\n"
+                              "  long both      %lu\n"
+                              "  plt call       %lu\n"
+                              "  plt call save  %lu\n"
+                              "  plt call notoc %lu\n"
+                              "  plt call both  %lu\n"
+                              "  global entry   %lu"),
               htab->stub_count[ppc_stub_long_branch - 1],
               htab->stub_count[ppc_stub_long_branch_r2off - 1],
+              htab->stub_count[ppc_stub_long_branch_notoc - 1],
+              htab->stub_count[ppc_stub_long_branch_both - 1],
               htab->stub_count[ppc_stub_plt_branch - 1],
               htab->stub_count[ppc_stub_plt_branch_r2off - 1],
+              htab->stub_count[ppc_stub_plt_branch_notoc - 1],
+              htab->stub_count[ppc_stub_plt_branch_both - 1],
               htab->stub_count[ppc_stub_plt_call - 1],
               htab->stub_count[ppc_stub_plt_call_r2save - 1],
+              htab->stub_count[ppc_stub_plt_call_notoc - 1],
+              htab->stub_count[ppc_stub_plt_call_both - 1],
               htab->stub_count[ppc_stub_global_entry - 1]);
     }
   return TRUE;
@@ -13452,7 +14541,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       unsigned char tls_mask, tls_gd, tls_type;
       unsigned char sym_type;
       bfd_vma relocation;
-      bfd_boolean unresolved_reloc;
+      bfd_boolean unresolved_reloc, save_unresolved_reloc;
       bfd_boolean warned;
       enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
       unsigned int insn;
@@ -13604,7 +14693,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            (local_plt + symtab_hdr->sh_info);
          tls_mask = lgot_masks[r_symndx];
        }
-      if (tls_mask == 0
+      if (((tls_mask & TLS_TLS) == 0 || tls_mask == (TLS_TLS | TLS_MARK))
          && (r_type == R_PPC64_TLS
              || r_type == R_PPC64_TLSGD
              || r_type == R_PPC64_TLSLD))
@@ -13632,7 +14721,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || (sym_type == STT_SECTION
                      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
        {
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (r_type == R_PPC64_TLS
                  || r_type == R_PPC64_TLSGD
                  || r_type == R_PPC64_TLSLD))
@@ -13642,9 +14731,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            info->callbacks->einfo
              (!IS_PPC64_TLS_RELOC (r_type)
               /* xgettext:c-format */
-              ? _("%H: %s used with TLS symbol `%T'\n")
+              ? _("%H: %s used with TLS symbol `%pT'\n")
               /* xgettext:c-format */
-              : _("%H: %s used with non-TLS symbol `%T'\n"),
+              : _("%H: %s used with non-TLS symbol `%pT'\n"),
               input_bfd, input_section, rel->r_offset,
               ppc64_elf_howto_table[r_type]->name,
               sym_name);
@@ -13698,7 +14787,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (r_type == R_PPC64_TOC16_DS
                    || r_type == R_PPC64_TOC16_LO_DS)
                  {
-                   if (tls_mask != 0
+                   if ((tls_mask & TLS_TLS) != 0
                        && (tls_mask & (TLS_DTPREL | TLS_TPREL)) == 0)
                      goto toctprel;
                  }
@@ -13709,12 +14798,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    if (retval == 2)
                      {
                        tls_gd = TLS_TPRELGD;
-                       if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+                       if ((tls_mask & TLS_TLS) != 0
+                           && (tls_mask & TLS_GD) == 0)
                          goto tls_ldgd_opt;
                      }
                    else if (retval == 3)
                      {
-                       if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+                       if ((tls_mask & TLS_TLS) != 0
+                           && (tls_mask & TLS_LD) == 0)
                          goto tls_ldgd_opt;
                      }
                  }
@@ -13724,7 +14815,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
              rel->r_offset -= d_offset;
@@ -13736,7 +14827,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_GOT_TPREL16_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
            toctprel:
@@ -13761,7 +14852,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_TLS:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
              insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
@@ -13789,13 +14880,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSGD16_HI:
        case R_PPC64_GOT_TLSGD16_HA:
          tls_gd = TLS_TPRELGD;
-         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_gdld_hi;
          break;
 
        case R_PPC64_GOT_TLSLD16_HI:
        case R_PPC64_GOT_TLSLD16_HA:
-         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
            {
            tls_gdld_hi:
              if ((tls_mask & tls_gd) != 0)
@@ -13814,13 +14905,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_GOT_TLSGD16:
        case R_PPC64_GOT_TLSGD16_LO:
          tls_gd = TLS_TPRELGD;
-         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_ldgd_opt;
          break;
 
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
-         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
            {
              unsigned int insn1, insn2;
              bfd_vma offset;
@@ -13913,11 +15004,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_TLSGD:
-         if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+             && rel + 1 < relend)
            {
              unsigned int insn2;
              bfd_vma offset = rel->r_offset;
 
+             if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+               {
+                 bfd_put_32 (output_bfd, NOP, contents + offset);
+                 rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+                 break;
+               }
+
+             if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+               bfd_put_32 (output_bfd, NOP, contents + offset + 4);
+
              if ((tls_mask & TLS_TPRELGD) != 0)
                {
                  /* IE */
@@ -13947,11 +15049,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_TLSLD:
-         if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+         if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+             && rel + 1 < relend)
            {
              unsigned int insn2;
              bfd_vma offset = rel->r_offset;
 
+             if (is_plt_seq_reloc (ELF64_R_TYPE (rel[1].r_info)))
+               {
+                 bfd_put_32 (output_bfd, NOP, contents + offset);
+                 rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
+                 break;
+               }
+
+             if (ELF64_R_TYPE (rel[1].r_info) == R_PPC64_PLTCALL)
+               bfd_put_32 (output_bfd, NOP, contents + offset + 4);
+
              if (toc_symndx)
                sec = local_sections[toc_symndx];
              for (r_symndx = 0;
@@ -14143,6 +15256,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          /* Fall through.  */
 
        case R_PPC64_REL24:
+       case R_PPC64_REL24_NOTOC:
+       case R_PPC64_PLTCALL:
          /* Calls to functions with a different TOC, such as calls to
             shared objects, need to alter the TOC pointer.  This is
             done using a linkage stub.  A REL24 branching to these
@@ -14156,11 +15271,20 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            fdh = ppc_follow_link (h->oh);
          stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
                                           htab);
+         if (r_type == R_PPC64_PLTCALL
+             && stub_entry != NULL
+             && stub_entry->stub_type >= ppc_stub_plt_call
+             && stub_entry->stub_type <= ppc_stub_plt_call_both)
+           stub_entry = NULL;
+
          if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
                  || stub_entry->stub_type == ppc_stub_plt_call_r2save
+                 || stub_entry->stub_type == ppc_stub_plt_call_both
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
-                 || stub_entry->stub_type == ppc_stub_long_branch_r2off))
+                 || stub_entry->stub_type == ppc_stub_plt_branch_both
+                 || stub_entry->stub_type == ppc_stub_long_branch_r2off
+                 || stub_entry->stub_type == ppc_stub_long_branch_both))
            {
              bfd_boolean can_plt_call = FALSE;
 
@@ -14172,6 +15296,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  /* The function doesn't use or change r2.  */
                  can_plt_call = TRUE;
                }
+             else if (r_type == R_PPC64_REL24_NOTOC)
+               {
+                 /* NOTOC calls don't need to restore r2.  */
+                 can_plt_call = TRUE;
+               }
 
              /* All of these stubs may modify r2, so there must be a
                 branch and link followed by a nop.  The nop is
@@ -14188,8 +15317,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
                      nop = bfd_get_32 (input_bfd,
                                        contents + rel->r_offset + 4);
-                     if (nop == NOP
-                         || nop == CROR_151515 || nop == CROR_313131)
+                     if (nop == LD_R2_0R1 + STK_TOC (htab))
+                       can_plt_call = TRUE;
+                     else if (nop == NOP
+                              || nop == CROR_151515
+                              || nop == CROR_313131)
                        {
                          if (h != NULL
                              && (h == htab->tls_get_addr_fd
@@ -14250,17 +15382,17 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
              if (!can_plt_call)
                {
-                 if (stub_entry->stub_type == ppc_stub_plt_call
-                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+                 if (stub_entry->stub_type >= ppc_stub_plt_call
+                     && stub_entry->stub_type <= ppc_stub_plt_call_both)
                    info->callbacks->einfo
                      /* xgettext:c-format */
-                     (_("%H: call to `%T' lacks nop, can't restore toc; "
+                     (_("%H: call to `%pT' lacks nop, can't restore toc; "
                         "recompile with -fPIC\n"),
                       input_bfd, input_section, rel->r_offset, sym_name);
                  else
                    info->callbacks->einfo
                      /* xgettext:c-format */
-                     (_("%H: call to `%T' lacks nop, can't restore toc; "
+                     (_("%H: call to `%pT' lacks nop, can't restore toc; "
                         "(-mcmodel=small toc adjust stub)\n"),
                       input_bfd, input_section, rel->r_offset, sym_name);
 
@@ -14269,8 +15401,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              if (can_plt_call
-                 && (stub_entry->stub_type == ppc_stub_plt_call
-                     || stub_entry->stub_type == ppc_stub_plt_call_r2save))
+                 && stub_entry->stub_type >= ppc_stub_plt_call
+                 && stub_entry->stub_type <= ppc_stub_plt_call_both)
                unresolved_reloc = FALSE;
            }
 
@@ -14312,6 +15444,28 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            /* Don't use the stub if this branch is in range.  */
            stub_entry = NULL;
 
+         if (stub_entry != NULL
+             && (stub_entry->stub_type == ppc_stub_long_branch_notoc
+                 || stub_entry->stub_type == ppc_stub_long_branch_both
+                 || stub_entry->stub_type == ppc_stub_plt_branch_notoc
+                 || stub_entry->stub_type == ppc_stub_plt_branch_both)
+             && (r_type != R_PPC64_REL24_NOTOC
+                 || ((fdh ? fdh->elf.other : sym->st_other)
+                     & STO_PPC64_LOCAL_MASK) == 1 << STO_PPC64_LOCAL_BIT)
+             && (relocation + addend - from + max_br_offset
+                 < 2 * max_br_offset))
+           stub_entry = NULL;
+
+         if (stub_entry != NULL
+             && (stub_entry->stub_type == ppc_stub_long_branch_r2off
+                 || stub_entry->stub_type == ppc_stub_long_branch_both
+                 || stub_entry->stub_type == ppc_stub_plt_branch_r2off
+                 || stub_entry->stub_type == ppc_stub_plt_branch_both)
+             && r_type == R_PPC64_REL24_NOTOC
+             && (relocation + addend - from + max_br_offset
+                 < 2 * max_br_offset))
+           stub_entry = NULL;
+
          if (stub_entry != NULL)
            {
              /* Munge up the value and addend so that we call the stub
@@ -14331,14 +15485,23 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              addend = 0;
              reloc_dest = DEST_STUB;
 
-             if ((stub_entry->stub_type == ppc_stub_plt_call
-                  || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-                 && (ALWAYS_EMIT_R2SAVE
-                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+             if (((stub_entry->stub_type == ppc_stub_plt_call
+                   && ALWAYS_EMIT_R2SAVE)
+                  || stub_entry->stub_type == ppc_stub_plt_call_r2save
+                  || stub_entry->stub_type == ppc_stub_plt_call_both)
+                 && !(h != NULL
+                      && (h == htab->tls_get_addr_fd
+                          || h == htab->tls_get_addr)
+                      && htab->params->tls_get_addr_opt)
                  && rel + 1 < relend
                  && rel[1].r_offset == rel->r_offset + 4
                  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
                relocation += 4;
+             else if ((stub_entry->stub_type == ppc_stub_long_branch_both
+                       || stub_entry->stub_type == ppc_stub_plt_branch_both
+                       || stub_entry->stub_type == ppc_stub_plt_call_both)
+                      && r_type == R_PPC64_REL24_NOTOC)
+               relocation += 4;
            }
 
          if (insn != 0)
@@ -14371,7 +15534,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          else if (h != NULL
                   && h->elf.root.type == bfd_link_hash_undefweak
                   && h->elf.dynindx == -1
-                  && r_type == R_PPC64_REL24
+                  && (r_type == R_PPC64_REL24
+                      || r_type == R_PPC64_REL24_NOTOC)
                   && relocation == 0
                   && addend == 0)
            {
@@ -14383,13 +15547,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
       /* Set `addend'.  */
       tls_type = 0;
+      save_unresolved_reloc = unresolved_reloc;
       switch (r_type)
        {
        default:
-         info->callbacks->einfo
-           /* xgettext:c-format */
-           (_("%P: %B: unknown relocation type %d for `%T'\n"),
-            input_bfd, (int) r_type, sym_name);
+         /* xgettext:c-format */
+         _bfd_error_handler (_("%pB: %s unsupported"),
+                             input_bfd, ppc64_elf_howto_table[r_type]->name);
 
          bfd_set_error (bfd_error_bad_value);
          ret = FALSE;
@@ -14639,10 +15803,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_PLT16_HA:
        case R_PPC64_PLT16_HI:
        case R_PPC64_PLT16_LO:
+       case R_PPC64_PLT16_LO_DS:
        case R_PPC64_PLT32:
        case R_PPC64_PLT64:
+       case R_PPC64_PLTSEQ:
+       case R_PPC64_PLTCALL:
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
+         unresolved_reloc = TRUE;
          {
            struct plt_entry **plt_list = NULL;
            if (h != NULL)
@@ -14651,10 +15819,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              {
                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)
-                 plt_list = local_plt + r_symndx;
+               plt_list = local_plt + r_symndx;
              }
            if (plt_list)
              {
@@ -14665,15 +15830,32 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      && ent->addend == orig_rel.r_addend)
                    {
                      asection *plt;
+                     bfd_vma got;
 
                      plt = htab->elf.splt;
                      if (!htab->elf.dynamic_sections_created
                          || h == NULL
                          || h->elf.dynindx == -1)
-                       plt = htab->elf.iplt;
+                       {
+                         if (h != NULL
+                             ? h->elf.type == STT_GNU_IFUNC
+                             : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+                           plt = htab->elf.iplt;
+                         else
+                           plt = htab->pltlocal;
+                       }
                      relocation = (plt->output_section->vma
                                    + plt->output_offset
                                    + ent->plt.offset);
+                     if (r_type == R_PPC64_PLT16_HA
+                         || r_type ==R_PPC64_PLT16_HI
+                         || r_type ==R_PPC64_PLT16_LO
+                         || r_type ==R_PPC64_PLT16_LO_DS)
+                       {
+                         got = (elf_gp (output_bfd)
+                                + htab->sec_info[input_section->id].toc_off);
+                         relocation -= got;
+                       }
                      addend = 0;
                      unresolved_reloc = FALSE;
                      break;
@@ -14730,6 +15912,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
+       case R_PPC64_REL24_NOTOC:
          break;
 
        case R_PPC64_TPREL16:
@@ -14938,7 +16121,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          info->callbacks->einfo
                            /* xgettext:c-format */
                            (_("%H: %s for indirect "
-                              "function `%T' unsupported\n"),
+                              "function `%pT' unsupported\n"),
                             input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
                             sym_name);
@@ -15049,7 +16232,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
          info->callbacks->einfo
            /* xgettext:c-format */
-           (_("%P: %B: %s is not supported for `%T'\n"),
+           (_("%P: %pB: %s is not supported for `%pT'\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
@@ -15061,7 +16244,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       /* 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;  */
-      howto = ppc64_elf_howto_table[(int) r_type];
       switch (r_type)
        {
        default:
@@ -15082,6 +16264,35 @@ ppc64_elf_relocate_section (bfd *output_bfd,
             insn.  */
          break;
 
+       case R_PPC64_PLTCALL:
+         if (unresolved_reloc)
+           {
+             /* No plt entry.  Make this into a direct call.  */
+             bfd_byte *p = contents + rel->r_offset;
+             insn = bfd_get_32 (input_bfd, p);
+             insn &= 1;
+             bfd_put_32 (input_bfd, B_DOT | insn, p);
+             bfd_put_32 (input_bfd, NOP, p + 4);
+             unresolved_reloc = save_unresolved_reloc;
+             r_type = R_PPC64_REL24;
+           }
+         break;
+
+       case R_PPC64_PLTSEQ:
+         if (unresolved_reloc)
+           {
+             unresolved_reloc = FALSE;
+             goto nop_it;
+           }
+         break;
+
+       case R_PPC64_PLT16_HA:
+         if (unresolved_reloc)
+           {
+             unresolved_reloc = FALSE;
+             goto nop_it;
+           }
+         /* Fall through.  */
        case R_PPC64_GOT_TLSLD16_HA:
        case R_PPC64_GOT_TLSGD16_HA:
        case R_PPC64_GOT_TPREL16_HA:
@@ -15091,11 +16302,22 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
              && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
            {
-             bfd_byte *p = contents + (rel->r_offset & ~3);
+             bfd_byte *p;
+           nop_it:
+             p = contents + (rel->r_offset & ~3);
              bfd_put_32 (input_bfd, NOP, p);
+             goto copy_reloc;
            }
          break;
 
+       case R_PPC64_PLT16_LO:
+       case R_PPC64_PLT16_LO_DS:
+         if (unresolved_reloc)
+           {
+             unresolved_reloc = FALSE;
+             goto nop_it;
+           }
+         /* Fall through.  */
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSGD16_LO:
        case R_PPC64_GOT_TPREL16_LO_DS:
@@ -15134,9 +16356,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                /* xgettext:c-format */
                info->callbacks->minfo
                  (_("%H: warning: %s unexpected insn %#x.\n"),
-                  input_bfd, input_section, rel->r_offset, howto->name, insn);
+                  input_bfd, input_section, rel->r_offset,
+                  ppc64_elf_howto_table[r_type]->name, insn);
              else
-               bfd_put_32 (input_bfd, NOP, p);
+               {
+                 bfd_put_32 (input_bfd, NOP, p);
+                 goto copy_reloc;
+               }
            }
          break;
 
@@ -15234,7 +16460,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                /* xgettext:c-format */
                (_("%H: error: %s not a multiple of %u\n"),
                 input_bfd, input_section, rel->r_offset,
-                howto->name,
+                ppc64_elf_howto_table[r_type]->name,
                 mask + 1);
              bfd_set_error (bfd_error_bad_value);
              ret = FALSE;
@@ -15246,6 +16472,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
         because such sections are not SEC_ALLOC and thus ld.so will
         not process them.  */
+      howto = ppc64_elf_howto_table[(int) r_type];
       if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->elf.def_dynamic)
@@ -15254,7 +16481,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        {
          info->callbacks->einfo
            /* xgettext:c-format */
-           (_("%H: unresolvable %s against `%T'\n"),
+           (_("%H: unresolvable %s against `%pT'\n"),
             input_bfd, input_section, rel->r_offset,
             howto->name,
             h->elf.root.root.string);
@@ -15351,7 +16578,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              info->callbacks->einfo
                /* xgettext:c-format */
-               (_("%H: %s against `%T': error %d\n"),
+               (_("%H: %s against `%pT': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
                 reloc_name, sym_name, (int) r);
              ret = FALSE;
@@ -15446,85 +16673,41 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
 {
   struct ppc_link_hash_table *htab;
   struct plt_entry *ent;
-  Elf_Internal_Rela rela;
-  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->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->elf.iplt->output_section->vma
-                            + htab->elf.iplt->output_offset
-                            + ent->plt.offset);
-           if (htab->opd_abi)
-             rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
-           else
-             rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
-           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->elf.irelplt->contents
-                  + (htab->elf.irelplt->reloc_count++
-                     * sizeof (Elf64_External_Rela)));
-           htab->local_ifunc_resolver = 1;
-         }
-       else
-         {
-           rela.r_offset = (htab->elf.splt->output_section->vma
-                            + htab->elf.splt->output_offset
-                            + ent->plt.offset);
-           rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
-           rela.r_addend = ent->addend;
-           loc = (htab->elf.srelplt->contents
-                  + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab))
-                     / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela)));
-           if (h->type == STT_GNU_IFUNC && is_static_defined (h))
-             htab->maybe_local_ifunc_resolver = 1;
-         }
-       bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
-
-       if (!htab->opd_abi)
-         {
-           if (!h->def_regular)
-             {
-               /* Mark the symbol as undefined, rather than as
-                  defined in glink.  Leave the value if there were
-                  any relocations where pointer equality matters
-                  (this is a clue for the dynamic linker, to make
-                  function pointer comparisons work between an
-                  application and shared library), otherwise set it
-                  to zero.  */
-               sym->st_shndx = SHN_UNDEF;
-               if (!h->pointer_equality_needed)
-                 sym->st_value = 0;
-               else if (!h->ref_regular_nonweak)
-                 {
-                   /* This breaks function pointer comparisons, but
-                      that is better than breaking tests for a NULL
-                      function pointer.  */
-                   sym->st_value = 0;
-                 }
-             }
-         }
-      }
+  if (!htab->opd_abi && !h->def_regular)
+    for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+      if (ent->plt.offset != (bfd_vma) -1)
+       {
+         /* Mark the symbol as undefined, rather than as
+            defined in glink.  Leave the value if there were
+            any relocations where pointer equality matters
+            (this is a clue for the dynamic linker, to make
+            function pointer comparisons work between an
+            application and shared library), otherwise set it
+            to zero.  */
+         sym->st_shndx = SHN_UNDEF;
+         if (!h->pointer_equality_needed)
+           sym->st_value = 0;
+         else if (!h->ref_regular_nonweak)
+           {
+             /* This breaks function pointer comparisons, but
+                that is better than breaking tests for a NULL
+                function pointer.  */
+             sym->st_value = 0;
+           }
+         break;
+       }
 
   if (h->needs_copy)
     {
       /* This symbol needs a copy reloc.  Set it up.  */
+      Elf_Internal_Rela rela;
       asection *srel;
+      bfd_byte *loc;
 
       if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
@@ -15718,62 +16901,14 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
                                       NULL))
     return FALSE;
 
-  if (htab->glink_eh_frame != NULL
-      && htab->glink_eh_frame->size != 0)
-    {
-      bfd_vma val;
-      bfd_byte *p;
-      struct map_stub *group;
-      size_t align = 4;
-
-      p = htab->glink_eh_frame->contents;
-      p += (sizeof (glink_eh_frame_cie) + align - 1) & -align;
-
-      for (group = htab->group; group != NULL; group = group->next)
-       if (group->stub_sec != NULL)
-         {
-           /* Offset to stub section.  */
-           val = (group->stub_sec->output_section->vma
-                  + group->stub_sec->output_offset);
-           val -= (htab->glink_eh_frame->output_section->vma
-                   + htab->glink_eh_frame->output_offset
-                   + (p + 8 - htab->glink_eh_frame->contents));
-           if (val + 0x80000000 > 0xffffffff)
-             {
-               info->callbacks->einfo
-                 (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
-                  group->stub_sec->name);
-               return FALSE;
-             }
-           bfd_put_32 (dynobj, val, p + 8);
-           p += stub_eh_frame_size (group, align);
-         }
-      if (htab->glink != NULL && htab->glink->size != 0)
-       {
-         /* Offset to .glink.  */
-         val = (htab->glink->output_section->vma
-                + htab->glink->output_offset
-                + 8);
-         val -= (htab->glink_eh_frame->output_section->vma
-                 + htab->glink_eh_frame->output_offset
-                 + (p + 8 - htab->glink_eh_frame->contents));
-         if (val + 0x80000000 > 0xffffffff)
-           {
-             info->callbacks->einfo
-               (_("%P: %s offset too large for .eh_frame sdata4 encoding"),
-                htab->glink->name);
-             return FALSE;
-           }
-         bfd_put_32 (dynobj, val, p + 8);
-         p += (24 + align - 1) & -align;
-       }
 
-      if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
-         && !_bfd_elf_write_section_eh_frame (output_bfd, info,
-                                              htab->glink_eh_frame,
-                                              htab->glink_eh_frame->contents))
-       return FALSE;
-    }
+  if (htab->glink_eh_frame != NULL
+      && htab->glink_eh_frame->size != 0
+      && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
+      && !_bfd_elf_write_section_eh_frame (output_bfd, info,
+                                          htab->glink_eh_frame,
+                                          htab->glink_eh_frame->contents))
+    return FALSE;
 
   /* We need to handle writing out multiple GOT sections ourselves,
      since we didn't add them to DYNOBJ.  We know dynobj is the first
This page took 0.096876 seconds and 4 git commands to generate.