2013-08-21 Tristan Gingold <gingold@adacore.com>
[deliverable/binutils-gdb.git] / bfd / elf64-ppc.c
index 482cf4d0fb32eb6c89e82086b9f9d7f9e1f880ac..349f9b3fd43748a3655c2b36e7f6e4ae608a5da5 100644 (file)
@@ -55,7 +55,7 @@ static bfd_reloc_status_type ppc64_elf_toc64_reloc
 static bfd_reloc_status_type ppc64_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_vma opd_entry_value
-  (asection *, bfd_vma, asection **, bfd_vma *);
+  (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
 
 #define TARGET_LITTLE_SYM      bfd_elf64_powerpcle_vec
 #define TARGET_LITTLE_NAME     "elf64-powerpcle"
@@ -2347,7 +2347,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
     {
       bfd_vma dest = opd_entry_value (symbol->section,
                                      symbol->value + reloc_entry->addend,
-                                     NULL, NULL);
+                                     NULL, NULL, FALSE);
       if (dest != (bfd_vma) -1)
        reloc_entry->addend = dest - (symbol->value
                                      + symbol->section->output_section->vma
@@ -2472,7 +2472,7 @@ ppc64_elf_toc_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 
   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
   if (TOCstart == 0)
-    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+    TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
 
   /* Subtract the TOC base address.  */
   reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
@@ -2495,7 +2495,7 @@ ppc64_elf_toc_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 
   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
   if (TOCstart == 0)
-    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+    TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
 
   /* Subtract the TOC base address.  */
   reloc_entry->addend -= TOCstart + TOC_BASE_OFF;
@@ -2522,7 +2522,7 @@ ppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
 
   TOCstart = _bfd_get_gp_value (input_section->output_section->owner);
   if (TOCstart == 0)
-    TOCstart = ppc64_elf_toc (input_section->output_section->owner);
+    TOCstart = ppc64_elf_set_toc (NULL, input_section->output_section->owner);
 
   octets = reloc_entry->address * bfd_octets_per_byte (abfd);
   bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets);
@@ -2615,8 +2615,13 @@ struct ppc64_elf_obj_tdata
      sections means we potentially need one of these for each input bfd.  */
   struct got_entry tlsld_got;
 
-  /* A copy of relocs before they are modified for --emit-relocs.  */
-  Elf_Internal_Rela *opd_relocs;
+  union {
+    /* A copy of relocs before they are modified for --emit-relocs.  */
+    Elf_Internal_Rela *relocs;
+
+    /* Section contents.  */
+    bfd_byte *contents;
+  } opd;
 
   /* Nonzero if this bfd has small toc/got relocs, ie. that expect
      the reloc to be in the range -32768 to 32767.  */
@@ -2677,10 +2682,10 @@ ppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
     return FALSE;
 
   /* pr_cursig */
-  elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+  elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
 
   /* pr_pid */
-  elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
+  elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32);
 
   /* pr_reg */
   offset = 112;
@@ -2697,11 +2702,11 @@ ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
   if (note->descsz != 136)
     return FALSE;
 
-  elf_tdata (abfd)->core_pid
+  elf_tdata (abfd)->core->pid
     = bfd_get_32 (abfd, note->descdata + 24);
-  elf_tdata (abfd)->core_program
+  elf_tdata (abfd)->core->program
     = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
-  elf_tdata (abfd)->core_command
+  elf_tdata (abfd)->core->command
     = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
 
   return TRUE;
@@ -3259,7 +3264,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd,
              slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
              if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
                goto free_contents_and_exit;
-       
+
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
              size += plt_count * sizeof (asymbol);
 
@@ -3618,9 +3623,6 @@ struct ppc_stub_hash_entry {
   struct ppc_link_hash_entry *h;
   struct plt_entry *plt_ent;
 
-  /* And the reloc addend that this was derived from.  */
-  bfd_vma addend;
-
   /* Where this stub is being called from, or, in the case of combined
      stub sections, the first input section in the group.  */
   asection *id_sec;
@@ -3638,6 +3640,21 @@ struct ppc_branch_hash_entry {
   unsigned int iter;
 };
 
+/* Used to track dynamic relocations for local symbols.  */
+struct ppc_dyn_relocs
+{
+  struct ppc_dyn_relocs *next;
+
+  /* The input section of the reloc.  */
+  asection *sec;
+
+  /* Total number of relocs copied for the input section.  */
+  unsigned int count : 31;
+
+  /* Whether this entry is for STT_GNU_IFUNC symbols.  */
+  unsigned int ifunc : 1;
+};
+
 struct ppc_link_hash_entry
 {
   struct elf_link_hash_entry elf;
@@ -4040,12 +4057,89 @@ ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
   bfd_hash_table_free (&htab->branch_hash_table);
   if (htab->tocsave_htab)
     htab_delete (htab->tocsave_htab);
-  _bfd_generic_link_hash_table_free (hash);
+  _bfd_elf_link_hash_table_free (hash);
+}
+
+/* Create sections for linker generated code.  */
+
+static bfd_boolean
+create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
+{
+  struct ppc_link_hash_table *htab;
+  flagword flags;
+
+  htab = ppc_hash_table (info);
+
+  /* Create .sfpr for code to save and restore fp regs.  */
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+                                                  flags);
+  if (htab->sfpr == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
+    return FALSE;
+
+  /* Create .glink for lazy dynamic linking support.  */
+  htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
+                                                   flags);
+  if (htab->glink == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
+    return FALSE;
+
+  if (!info->no_ld_generated_unwind_info)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
+                                                                ".eh_frame",
+                                                                flags);
+      if (htab->glink_eh_frame == NULL
+         || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
+       return FALSE;
+    }
+
+  flags = SEC_ALLOC | SEC_LINKER_CREATED;
+  htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
+  if (htab->iplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
+    return FALSE;
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
+                                                     ".rela.iplt",
+                                                     flags);
+  if (htab->reliplt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
+    return FALSE;
+
+  /* Create branch lookup table for plt_branch stubs.  */
+  flags = (SEC_ALLOC | SEC_LOAD
+          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+  htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
+                                                  flags);
+  if (htab->brlt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
+    return FALSE;
+
+  if (!info->shared)
+    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);
+  if (htab->relbrlt == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+    return FALSE;
+
+  return TRUE;
 }
 
 /* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
 
-void
+bfd_boolean
 ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab;
@@ -4057,9 +4151,14 @@ ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
    the start of the output TOC section.  */
   htab = ppc_hash_table (info);
   if (htab == NULL)
-    return;
+    return FALSE;
   htab->stub_bfd = abfd;
   htab->elf.dynobj = abfd;
+
+  if (info->relocatable)
+    return TRUE;
+
+  return create_linkage_sections (htab->elf.dynobj, info);
 }
 
 /* Build a name for an entry in the stub hash table.  */
@@ -4071,7 +4170,7 @@ ppc_stub_name (const asection *input_section,
               const Elf_Internal_Rela *rel)
 {
   char *stub_name;
-  bfd_size_type len;
+  ssize_t len;
 
   /* rel->r_addend is actually 64 bit, but who uses more than +/- 2^31
      offsets from a sym as a branch target?  In fact, we could
@@ -4085,10 +4184,10 @@ ppc_stub_name (const asection *input_section,
       if (stub_name == NULL)
        return stub_name;
 
-      sprintf (stub_name, "%08x.%s+%x",
-              input_section->id & 0xffffffff,
-              h->elf.root.root.string,
-              (int) rel->r_addend & 0xffffffff);
+      len = sprintf (stub_name, "%08x.%s+%x",
+                    input_section->id & 0xffffffff,
+                    h->elf.root.root.string,
+                    (int) rel->r_addend & 0xffffffff);
     }
   else
     {
@@ -4097,13 +4196,13 @@ ppc_stub_name (const asection *input_section,
       if (stub_name == NULL)
        return stub_name;
 
-      sprintf (stub_name, "%08x.%x:%x+%x",
-              input_section->id & 0xffffffff,
-              sym_sec->id & 0xffffffff,
-              (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
-              (int) rel->r_addend & 0xffffffff);
+      len = sprintf (stub_name, "%08x.%x:%x+%x",
+                    input_section->id & 0xffffffff,
+                    sym_sec->id & 0xffffffff,
+                    (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
+                    (int) rel->r_addend & 0xffffffff);
     }
-  if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
+  if (len > 2 && stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
     stub_name[len - 2] = 0;
   return stub_name;
 }
@@ -4209,85 +4308,6 @@ ppc_add_stub (const char *stub_name,
   return stub_entry;
 }
 
-/* Create sections for linker generated code.  */
-
-static bfd_boolean
-create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
-{
-  struct ppc_link_hash_table *htab;
-  flagword flags;
-
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-
-  /* Create .sfpr for code to save and restore fp regs.  */
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
-                                                  flags);
-  if (htab->sfpr == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
-    return FALSE;
-
-  /* Create .glink for lazy dynamic linking support.  */
-  htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
-                                                   flags);
-  if (htab->glink == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
-    return FALSE;
-
-  if (!info->no_ld_generated_unwind_info)
-    {
-      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
-              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-      htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
-                                                                ".eh_frame",
-                                                                flags);
-      if (htab->glink_eh_frame == NULL
-         || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
-       return FALSE;
-    }
-
-  flags = SEC_ALLOC | SEC_LINKER_CREATED;
-  htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
-  if (htab->iplt == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
-    return FALSE;
-
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
-                                                     ".rela.iplt",
-                                                     flags);
-  if (htab->reliplt == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
-    return FALSE;
-
-  /* Create branch lookup table for plt_branch stubs.  */
-  flags = (SEC_ALLOC | SEC_LOAD
-          | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
-  htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
-                                                  flags);
-  if (htab->brlt == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
-    return FALSE;
-
-  if (!info->shared)
-    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);
-  if (htab->relbrlt == NULL
-      || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
-    return FALSE;
-
-  return TRUE;
-}
-
 /* Create .got and .rela.got sections in ABFD, and .got in dynobj if
    not already done.  */
 
@@ -4308,7 +4328,7 @@ create_got_section (bfd *abfd, struct bfd_link_info *info)
       if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
        return FALSE;
 
-      htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got");
+      htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got");
       if (!htab->got)
        abort ();
     }
@@ -4347,12 +4367,12 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
     return FALSE;
 
   if (!htab->got)
-    htab->got = bfd_get_section_by_name (dynobj, ".got");
-  htab->plt = bfd_get_section_by_name (dynobj, ".plt");
-  htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt");
-  htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+    htab->got = bfd_get_linker_section (dynobj, ".got");
+  htab->plt = bfd_get_linker_section (dynobj, ".plt");
+  htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt");
+  htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
   if (!info->shared)
-    htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+    htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
 
   if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
       || (!info->shared && !htab->relbss))
@@ -4485,7 +4505,7 @@ ppc64_elf_copy_indirect_symbol (struct bfd_link_info *info,
   /* If we were called to copy over info for a weak sym, that's all.
      You might think dyn_relocs need not be copied over;  After all,
      both syms will be dynamic or both non-dynamic so we're just
-     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS 
+     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS
      code in ppc64_elf_adjust_dynamic_symbol needs to check for
      dyn_relocs in read-only sections, and it does so on what is the
      DIR sym here.  */
@@ -4753,7 +4773,12 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
       while ((eh = *p) != NULL)
        {
          *p = NULL;
-         if (!add_symbol_adjust (eh, info))
+         if (&eh->elf == htab->elf.hgot)
+           ;
+         else if (htab->elf.hgot == NULL
+                  && strcmp (eh->elf.root.root.string, ".TOC.") == 0)
+           htab->elf.hgot = &eh->elf;
+         else if (!add_symbol_adjust (eh, info))
            return FALSE;
          p = &eh->u.next_dot_sym;
        }
@@ -4965,10 +4990,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       ppc64_elf_section_data (sec)->sec_type = sec_opd;
     }
 
-  if (htab->sfpr == NULL
-      && !create_linkage_sections (htab->elf.dynobj, info))
-    return FALSE;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
@@ -4986,6 +5007,13 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = elf_follow_link (h);
+
+         /* PR15323, ref flags aren't set for references in the same
+            object.  */
+         h->root.non_ir_ref = 1;
+
+         if (h == htab->elf.hgot)
+           sec->has_toc_reloc = 1;
        }
 
       tls_type = 0;
@@ -5434,7 +5462,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if ((info->shared
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
-                      && (! info->symbolic
+                      && (!SYMBOLIC_BIND (info, h)
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
@@ -5445,9 +5473,6 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
              || (!info->shared
                  && ifunc != NULL))
            {
-             struct elf_dyn_relocs *p;
-             struct elf_dyn_relocs **head;
-
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
                 this reloc.  */
@@ -5464,13 +5489,34 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                 relocations we need for this symbol.  */
              if (h != NULL)
                {
+                 struct elf_dyn_relocs *p;
+                 struct elf_dyn_relocs **head;
+
                  head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+                 p = *head;
+                 if (p == NULL || p->sec != sec)
+                   {
+                     p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+                     if (p == NULL)
+                       return FALSE;
+                     p->next = *head;
+                     *head = p;
+                     p->sec = sec;
+                     p->count = 0;
+                     p->pc_count = 0;
+                   }
+                 p->count += 1;
+                 if (!must_be_dyn_reloc (info, r_type))
+                   p->pc_count += 1;
                }
              else
                {
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     easily.  Oh well.  */
+                 struct ppc_dyn_relocs *p;
+                 struct ppc_dyn_relocs **head;
+                 bfd_boolean is_ifunc;
                  asection *s;
                  void *vpp;
                  Elf_Internal_Sym *isym;
@@ -5485,25 +5531,24 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
                    s = sec;
 
                  vpp = &elf_section_data (s)->local_dynrel;
-                 head = (struct elf_dyn_relocs **) vpp;
-               }
-
-             p = *head;
-             if (p == NULL || p->sec != sec)
-               {
-                 p = bfd_alloc (htab->elf.dynobj, sizeof *p);
-                 if (p == NULL)
-                   return FALSE;
-                 p->next = *head;
-                 *head = p;
-                 p->sec = sec;
-                 p->count = 0;
-                 p->pc_count = 0;
+                 head = (struct ppc_dyn_relocs **) vpp;
+                 is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+                 p = *head;
+                 if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
+                   p = p->next;
+                 if (p == NULL || p->sec != sec || p->ifunc != is_ifunc)
+                   {
+                     p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+                     if (p == NULL)
+                       return FALSE;
+                     p->next = *head;
+                     *head = p;
+                     p->sec = sec;
+                     p->ifunc = is_ifunc;
+                     p->count = 0;
+                   }
+                 p->count += 1;
                }
-
-             p->count += 1;
-             if (!must_be_dyn_reloc (info, r_type))
-               p->pc_count += 1;
            }
          break;
 
@@ -5522,7 +5567,8 @@ static bfd_vma
 opd_entry_value (asection *opd_sec,
                 bfd_vma offset,
                 asection **code_sec,
-                bfd_vma *code_off)
+                bfd_vma *code_off,
+                bfd_boolean in_code_sec)
 {
   bfd *opd_bfd = opd_sec->owner;
   Elf_Internal_Rela *relocs;
@@ -5533,51 +5579,48 @@ opd_entry_value (asection *opd_sec,
      at a final linked executable with addr2line or somesuch.  */
   if (opd_sec->reloc_count == 0)
     {
-      /* PR 13897: Cache the loaded section to speed up the search.  */
-      static asection * buf_sec = NULL;
-      static char       buf[8];
-      static bfd_vma    buf_val = 0;
-      static asection * buf_likely = NULL;
-      
-      if (buf_sec == opd_sec)
-       {
-         if (code_sec != NULL)
-           * code_sec = buf_likely;
-         if (code_off != NULL && buf_likely != NULL)
-           * code_off = buf_val - buf_likely->vma;
-         return buf_val;
-       }
-   
-      if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
-       return (bfd_vma) -1;
-      buf_sec = opd_sec;
-
-      buf_val = bfd_get_64 (opd_bfd, buf);
+      bfd_byte *contents = ppc64_elf_tdata (opd_bfd)->opd.contents;
+
+      if (contents == NULL)
+       {
+         if (!bfd_malloc_and_get_section (opd_bfd, opd_sec, &contents))
+           return (bfd_vma) -1;
+         ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
+       }
+
+      val = bfd_get_64 (opd_bfd, contents + offset);
       if (code_sec != NULL)
        {
-         asection *sec;
+         asection *sec, *likely = NULL;
 
-         buf_likely = NULL;
-         for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
-           if (sec->vma <= buf_val
-               && (sec->flags & SEC_LOAD) != 0
-               && (sec->flags & SEC_ALLOC) != 0)
-             buf_likely = sec;
-         if (buf_likely != NULL)
+         if (in_code_sec)
            {
-             *code_sec = buf_likely;
+             sec = *code_sec;
+             if (sec->vma <= val
+                 && val < sec->vma + sec->size)
+               likely = sec;
+             else
+               val = -1;
+           }
+         else
+           for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
+             if (sec->vma <= val
+                 && (sec->flags & SEC_LOAD) != 0
+                 && (sec->flags & SEC_ALLOC) != 0)
+               likely = sec;
+         if (likely != NULL)
+           {
+             *code_sec = likely;
              if (code_off != NULL)
-               *code_off = buf_val - buf_likely->vma;
+               *code_off = val - likely->vma;
            }
        }
-      else
-       buf_likely = NULL;
-      return buf_val;
+      return val;
     }
 
   BFD_ASSERT (is_ppc64_elf (opd_bfd));
 
-  relocs = ppc64_elf_tdata (opd_bfd)->opd_relocs;
+  relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
   if (relocs == NULL)
     relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
 
@@ -5633,17 +5676,41 @@ opd_entry_value (asection *opd_sec,
 
                  sym_hashes = elf_sym_hashes (opd_bfd);
                  rh = sym_hashes[symndx - symtab_hdr->sh_info];
-                 rh = elf_follow_link (rh);
-                 BFD_ASSERT (rh->root.type == bfd_link_hash_defined
-                             || rh->root.type == bfd_link_hash_defweak);
-                 val = rh->root.u.def.value;
-                 sec = rh->root.u.def.section;
+                 if (rh != NULL)
+                   {
+                     rh = elf_follow_link (rh);
+                     BFD_ASSERT (rh->root.type == bfd_link_hash_defined
+                                 || rh->root.type == bfd_link_hash_defweak);
+                     val = rh->root.u.def.value;
+                     sec = rh->root.u.def.section;
+                   }
+                 else
+                   {
+                     /* Handle the odd case where we can be called
+                        during bfd_elf_link_add_symbols before the
+                        symbol hashes have been fully populated.  */
+                     Elf_Internal_Sym *sym;
+
+                     sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 1,
+                                                 symndx, NULL, NULL, NULL);
+                     if (sym == NULL)
+                       break;
+
+                     val = sym->st_value;
+                     sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
+                     free (sym);
+                   }
                }
              val += look->r_addend;
              if (code_off != NULL)
                *code_off = val;
              if (code_sec != NULL)
-               *code_sec = sec;
+               {
+                 if (in_code_sec && *code_sec != sec)
+                   return -1;
+                 else
+                   *code_sec = sec;
+               }
              if (sec != NULL && sec->output_section != NULL)
                val += sec->output_section->vma + sec->output_offset;
            }
@@ -5654,20 +5721,53 @@ opd_entry_value (asection *opd_sec,
   return val;
 }
 
-/* Return TRUE iff the ELF symbol SYM might be a function.  Set *CODE_SEC
-   and *CODE_OFF to the function's entry point.  */
+/* If the ELF symbol SYM might be a function in SEC, return the
+   function size and set *CODE_OFF to the function's entry point,
+   otherwise return zero.  */
 
-static bfd_boolean
-ppc64_elf_maybe_function_sym (const asymbol *sym,
-                             asection **code_sec, bfd_vma *code_off)
+static bfd_size_type
+ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                             bfd_vma *code_off)
 {
-  if (_bfd_elf_maybe_function_sym (sym, code_sec, code_off))
+  bfd_size_type size;
+
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
+    return 0;
+
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+
+  if (strcmp (sym->section->name, ".opd") == 0)
     {
-      if (strcmp (sym->section->name, ".opd") == 0)
-       opd_entry_value (sym->section, sym->value, code_sec, code_off);
-      return TRUE;
+      if (opd_entry_value (sym->section, sym->value,
+                          &sec, code_off, TRUE) == (bfd_vma) -1)
+       return 0;
+      /* An old ABI binary with dot-syms has a size of 24 on the .opd
+        symbol.  This size has nothing to do with the code size of the
+        function, which is what we're supposed to return, but the
+        code size isn't available without looking up the dot-sym.
+        However, doing that would be a waste of time particularly
+        since elf_find_function will look at the dot-sym anyway.
+        Now, elf_find_function will keep the largest size of any
+        function sym found at the code address of interest, so return
+        1 here to avoid it incorrectly caching a larger function size
+        for a small function.  This does mean we return the wrong
+        size for a new-ABI function of size 24, but all that does is
+        disable caching for such functions.  */
+      if (size == 24)
+       size = 1;
     }
-  return FALSE;
+  else
+    {
+      if (sym->section != sec)
+       return 0;
+      *code_off = sym->value;
+    }
+  if (size == 0)
+    size = 1;
+  return size;
 }
 
 /* Return true if symbol is defined in a regular object file.  */
@@ -5747,7 +5847,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &sec, NULL) != (bfd_vma) -1)
+                                  &sec, NULL, FALSE) != (bfd_vma) -1)
        sec->flags |= SEC_KEEP;
 
       sec = eh->elf.root.u.def.section;
@@ -5798,7 +5898,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
       else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
-                                  &code_sec, NULL) != (bfd_vma) -1)
+                                  &code_sec, NULL, FALSE) != (bfd_vma) -1)
        code_sec->flags |= SEC_KEEP;
     }
 
@@ -5858,7 +5958,7 @@ ppc64_elf_gc_mark_hook (asection *sec,
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                       && opd_entry_value (eh->elf.root.u.def.section,
                                           eh->elf.root.u.def.value,
-                                          &rsec, NULL) != (bfd_vma) -1)
+                                          &rsec, NULL, FALSE) != (bfd_vma) -1)
                eh->elf.root.u.def.section->gc_mark = 1;
              else
                rsec = h->root.u.def.section;
@@ -6327,7 +6427,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
       && opd_entry_value (fdh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
                          &fh->elf.root.u.def.section,
-                         &fh->elf.root.u.def.value) != (bfd_vma) -1)
+                         &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1)
     {
       fh->elf.root.type = fdh->elf.root.type;
       fh->elf.forced_local = 1;
@@ -6436,7 +6536,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
 {
   struct ppc_link_hash_table *htab;
   unsigned int i;
-  const struct sfpr_def_parms funcs[] =
+  static const struct sfpr_def_parms funcs[] =
     {
       { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
       { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
@@ -6456,15 +6556,20 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
   if (htab == NULL)
     return FALSE;
 
+  if (!info->relocatable
+      && htab->elf.hgot != NULL)
+    _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
+
   if (htab->sfpr == NULL)
     /* We don't have any relocs.  */
     return TRUE;
 
   /* Provide any missing _save* and _rest* functions.  */
   htab->sfpr->size = 0;
-  for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
-    if (!sfpr_define (info, &funcs[i]))
-      return FALSE;
+  if (!info->relocatable)
+    for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
+      if (!sfpr_define (info, &funcs[i]))
+       return FALSE;
 
   elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
 
@@ -6575,7 +6680,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 `%s' requires lazy plt linking; "
+       (_("%P: copy reloc against `%T' requires lazy plt linking; "
           "avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
         h->root.root.string);
     }
@@ -6915,7 +7020,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
 }
 
 /* Handles decrementing dynamic reloc counts for the reloc specified by
-   R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM_SEC
+   R_INFO in section SEC.  If LOCAL_SYMS is NULL, then H and SYM
    have already been determined.  */
 
 static bfd_boolean
@@ -6924,11 +7029,10 @@ dec_dynrel_count (bfd_vma r_info,
                  struct bfd_link_info *info,
                  Elf_Internal_Sym **local_syms,
                  struct elf_link_hash_entry *h,
-                 asection *sym_sec)
+                 Elf_Internal_Sym *sym)
 {
   enum elf_ppc64_reloc_type r_type;
-  struct elf_dyn_relocs *p;
-  struct elf_dyn_relocs **pp;
+  asection *sym_sec = NULL;
 
   /* Can this reloc be dynamic?  This switch, and later tests here
      should be kept in sync with the code in check_relocs.  */
@@ -6983,7 +7087,6 @@ dec_dynrel_count (bfd_vma r_info,
   if (local_syms != NULL)
     {
       unsigned long r_symndx;
-      Elf_Internal_Sym *sym;
       bfd *ibfd = sec->owner;
 
       r_symndx = ELF64_R_SYM (r_info);
@@ -6994,7 +7097,7 @@ dec_dynrel_count (bfd_vma r_info,
   if ((info->shared
        && (must_be_dyn_reloc (info, r_type)
           || (h != NULL
-              && (!info->symbolic
+              && (!SYMBOLIC_BIND (info, h)
                   || h->root.type == bfd_link_hash_defweak
                   || !h->def_regular))))
       || (ELIMINATE_COPY_RELOCS
@@ -7007,39 +7110,62 @@ dec_dynrel_count (bfd_vma r_info,
     return TRUE;
 
   if (h != NULL)
-    pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
-  else
     {
-      if (sym_sec != NULL)
-       {
-         void *vpp = &elf_section_data (sym_sec)->local_dynrel;
-         pp = (struct elf_dyn_relocs **) vpp;
-       }
-      else
-       {
-         void *vpp = &elf_section_data (sec)->local_dynrel;
-         pp = (struct elf_dyn_relocs **) vpp;
-       }
+      struct elf_dyn_relocs *p;
+      struct elf_dyn_relocs **pp;
+      pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
 
       /* elf_gc_sweep may have already removed all dyn relocs associated
-        with local syms for a given section.  Don't report a dynreloc
-        miscount.  */
-      if (*pp == NULL)
+        with local syms for a given section.  Also, symbol flags are
+        changed by elf_gc_sweep_symbol, confusing the test above.  Don't
+        report a dynreloc miscount.  */
+      if (*pp == NULL && info->gc_sections)
        return TRUE;
-    }
 
-  while ((p = *pp) != NULL)
+      while ((p = *pp) != NULL)
+       {
+         if (p->sec == sec)
+           {
+             if (!must_be_dyn_reloc (info, r_type))
+               p->pc_count -= 1;
+             p->count -= 1;
+             if (p->count == 0)
+               *pp = p->next;
+             return TRUE;
+           }
+         pp = &p->next;
+       }
+    }
+  else
     {
-      if (p->sec == sec)
+      struct ppc_dyn_relocs *p;
+      struct ppc_dyn_relocs **pp;
+      void *vpp;
+      bfd_boolean is_ifunc;
+
+      if (local_syms == NULL)
+       sym_sec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+      if (sym_sec == NULL)
+       sym_sec = sec;
+
+      vpp = &elf_section_data (sym_sec)->local_dynrel;
+      pp = (struct ppc_dyn_relocs **) vpp;
+
+      if (*pp == NULL && info->gc_sections)
+       return TRUE;
+
+      is_ifunc = ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC;
+      while ((p = *pp) != NULL)
        {
-         if (!must_be_dyn_reloc (info, r_type))
-           p->pc_count -= 1;
-         p->count -= 1;
-         if (p->count == 0)
-           *pp = p->next;
-         return TRUE;
+         if (p->sec == sec && p->ifunc == is_ifunc)
+           {
+             p->count -= 1;
+             if (p->count == 0)
+               *pp = p->next;
+             return TRUE;
+           }
+         pp = &p->next;
        }
-      pp = &p->next;
     }
 
   info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
@@ -7372,7 +7498,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping)
                  if (!NO_OPD_RELOCS
                      && !info->relocatable
                      && !dec_dynrel_count (rel->r_info, sec, info,
-                                           NULL, h, sym_sec))
+                                           NULL, h, sym))
                    goto error_ret;
                }
              else
@@ -7979,13 +8105,13 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                      /* If we got rid of a DTPMOD/DTPREL reloc pair then
                         we'll lose one or two dyn relocs.  */
                      if (!dec_dynrel_count (rel->r_info, sec, info,
-                                            NULL, h, sym_sec))
+                                            NULL, h, sym))
                        return FALSE;
 
                      if (tls_set == (TLS_EXPLICIT | TLS_GD))
                        {
                          if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
-                                                NULL, h, sym_sec))
+                                                NULL, h, sym))
                            return FALSE;
                        }
                    }
@@ -8217,7 +8343,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
         .  addi ry,rx,addr@toc@l
         when addr is within 2G of the toc pointer.  This then means
         that the word storing "addr" in the toc is no longer needed.  */
-        
+
       if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
          && toc->output_section->rawsize < (bfd_vma) 1 << 31
          && toc->reloc_count != 0)
@@ -8339,150 +8465,156 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
            goto error_ret;
 
          /* Mark toc entries referenced as used.  */
-         repeat = 0;
          do
-           for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
-             {
-               enum elf_ppc64_reloc_type r_type;
-               unsigned long r_symndx;
-               asection *sym_sec;
-               struct elf_link_hash_entry *h;
-               Elf_Internal_Sym *sym;
-               bfd_vma val;
-               enum {no_check, check_lo, check_ha} insn_check;
-
-               r_type = ELF64_R_TYPE (rel->r_info);
-               switch (r_type)
-                 {
-                 default:
-                   insn_check = no_check;
-                   break;
+           {
+             repeat = 0;
+             for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+               {
+                 enum elf_ppc64_reloc_type r_type;
+                 unsigned long r_symndx;
+                 asection *sym_sec;
+                 struct elf_link_hash_entry *h;
+                 Elf_Internal_Sym *sym;
+                 bfd_vma val;
+                 enum {no_check, check_lo, check_ha} insn_check;
 
-                 case R_PPC64_GOT_TLSLD16_HA:
-                 case R_PPC64_GOT_TLSGD16_HA:
-                 case R_PPC64_GOT_TPREL16_HA:
-                 case R_PPC64_GOT_DTPREL16_HA:
-                 case R_PPC64_GOT16_HA:
-                 case R_PPC64_TOC16_HA:
-                   insn_check = check_ha;
-                   break;
+                 r_type = ELF64_R_TYPE (rel->r_info);
+                 switch (r_type)
+                   {
+                   default:
+                     insn_check = no_check;
+                     break;
 
-                 case R_PPC64_GOT_TLSLD16_LO:
-                 case R_PPC64_GOT_TLSGD16_LO:
-                 case R_PPC64_GOT_TPREL16_LO_DS:
-                 case R_PPC64_GOT_DTPREL16_LO_DS:
-                 case R_PPC64_GOT16_LO:
-                 case R_PPC64_GOT16_LO_DS:
-                 case R_PPC64_TOC16_LO:
-                 case R_PPC64_TOC16_LO_DS:
-                   insn_check = check_lo;
-                   break;
-                 }
+                   case R_PPC64_GOT_TLSLD16_HA:
+                   case R_PPC64_GOT_TLSGD16_HA:
+                   case R_PPC64_GOT_TPREL16_HA:
+                   case R_PPC64_GOT_DTPREL16_HA:
+                   case R_PPC64_GOT16_HA:
+                   case R_PPC64_TOC16_HA:
+                     insn_check = check_ha;
+                     break;
 
-               if (insn_check != no_check)
-                 {
-                   bfd_vma off = rel->r_offset & ~3;
-                   unsigned char buf[4];
-                   unsigned int insn;
+                   case R_PPC64_GOT_TLSLD16_LO:
+                   case R_PPC64_GOT_TLSGD16_LO:
+                   case R_PPC64_GOT_TPREL16_LO_DS:
+                   case R_PPC64_GOT_DTPREL16_LO_DS:
+                   case R_PPC64_GOT16_LO:
+                   case R_PPC64_GOT16_LO_DS:
+                   case R_PPC64_TOC16_LO:
+                   case R_PPC64_TOC16_LO_DS:
+                     insn_check = check_lo;
+                     break;
+                   }
 
-                   if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
-                     {
-                       free (used);
-                       goto error_ret;
-                     }
-                   insn = bfd_get_32 (ibfd, buf);
-                   if (insn_check == check_lo
-                       ? !ok_lo_toc_insn (insn)
-                       : ((insn & ((0x3f << 26) | 0x1f << 16))
-                          != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
-                     {
-                       char str[12];
-
-                       ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
-                       sprintf (str, "%#08x", insn);
-                       info->callbacks->einfo
-                         (_("%P: %H: toc optimization is not supported for"
-                            " %s instruction.\n"),
-                          ibfd, sec, rel->r_offset & ~3, str);
-                     }
-                 }
+                 if (insn_check != no_check)
+                   {
+                     bfd_vma off = rel->r_offset & ~3;
+                     unsigned char buf[4];
+                     unsigned int insn;
 
-               switch (r_type)
-                 {
-                 case R_PPC64_TOC16:
-                 case R_PPC64_TOC16_LO:
-                 case R_PPC64_TOC16_HI:
-                 case R_PPC64_TOC16_HA:
-                 case R_PPC64_TOC16_DS:
-                 case R_PPC64_TOC16_LO_DS:
-                   /* In case we're taking addresses of toc entries.  */
-                 case R_PPC64_ADDR64:
-                   break;
+                     if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+                       {
+                         free (used);
+                         goto error_ret;
+                       }
+                     insn = bfd_get_32 (ibfd, buf);
+                     if (insn_check == check_lo
+                         ? !ok_lo_toc_insn (insn)
+                         : ((insn & ((0x3f << 26) | 0x1f << 16))
+                            != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+                       {
+                         char str[12];
 
-                 default:
-                   continue;
-                 }
+                         ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+                         sprintf (str, "%#08x", insn);
+                         info->callbacks->einfo
+                           (_("%P: %H: toc optimization is not supported for"
+                              " %s instruction.\n"),
+                            ibfd, sec, rel->r_offset & ~3, str);
+                       }
+                   }
 
-               r_symndx = ELF64_R_SYM (rel->r_info);
-               if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
-                               r_symndx, ibfd))
-                 {
-                   free (used);
-                   goto error_ret;
-                 }
+                 switch (r_type)
+                   {
+                   case R_PPC64_TOC16:
+                   case R_PPC64_TOC16_LO:
+                   case R_PPC64_TOC16_HI:
+                   case R_PPC64_TOC16_HA:
+                   case R_PPC64_TOC16_DS:
+                   case R_PPC64_TOC16_LO_DS:
+                     /* In case we're taking addresses of toc entries.  */
+                   case R_PPC64_ADDR64:
+                     break;
 
-               if (sym_sec != toc)
-                 continue;
+                   default:
+                     continue;
+                   }
 
-               if (h != NULL)
-                 val = h->root.u.def.value;
-               else
-                 val = sym->st_value;
-               val += rel->r_addend;
+                 r_symndx = ELF64_R_SYM (rel->r_info);
+                 if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+                                 r_symndx, ibfd))
+                   {
+                     free (used);
+                     goto error_ret;
+                   }
 
-               if (val >= toc->size)
-                 continue;
+                 if (sym_sec != toc)
+                   continue;
 
-               if ((skip[val >> 3] & can_optimize) != 0)
-                 {
-                   bfd_vma off;
-                   unsigned char opc;
+                 if (h != NULL)
+                   val = h->root.u.def.value;
+                 else
+                   val = sym->st_value;
+                 val += rel->r_addend;
 
-                   switch (r_type)
-                     {
-                     case R_PPC64_TOC16_HA:
-                       break;
+                 if (val >= toc->size)
+                   continue;
 
-                     case R_PPC64_TOC16_LO_DS:
-                       off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
-                       if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
-                         {
-                           free (used);
-                           goto error_ret;
-                         }
-                       if ((opc & (0x3f << 2)) == (58u << 2))
+                 if ((skip[val >> 3] & can_optimize) != 0)
+                   {
+                     bfd_vma off;
+                     unsigned char opc;
+
+                     switch (r_type)
+                       {
+                       case R_PPC64_TOC16_HA:
                          break;
-                       /* Fall thru */
 
-                     default:
-                       /* Wrong sort of reloc, or not a ld.  We may
-                          as well clear ref_from_discarded too.  */
-                       skip[val >> 3] = 0;
-                     }
-                 }
+                       case R_PPC64_TOC16_LO_DS:
+                         off = rel->r_offset;
+                         off += (bfd_big_endian (ibfd) ? -2 : 3);
+                         if (!bfd_get_section_contents (ibfd, sec, &opc,
+                                                        off, 1))
+                           {
+                             free (used);
+                             goto error_ret;
+                           }
+                         if ((opc & (0x3f << 2)) == (58u << 2))
+                           break;
+                         /* Fall thru */
 
-               /* For the toc section, we only mark as used if
-                  this entry itself isn't unused.  */
-               if (sec == toc
-                   && !used[val >> 3]
-                   && (used[rel->r_offset >> 3]
-                       || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
-                 /* Do all the relocs again, to catch reference
-                    chains.  */
-                 repeat = 1;
-
-               used[val >> 3] = 1;
-             }
+                       default:
+                         /* Wrong sort of reloc, or not a ld.  We may
+                            as well clear ref_from_discarded too.  */
+                         skip[val >> 3] = 0;
+                       }
+                   }
+
+                 if (sec != toc)
+                   used[val >> 3] = 1;
+                 /* For the toc section, we only mark as used if this
+                    entry itself isn't unused.  */
+                 else if ((used[rel->r_offset >> 3]
+                           || !(skip[rel->r_offset >> 3] & ref_from_discarded))
+                          && !used[val >> 3])
+                   {
+                     /* Do all the relocs again, to catch reference
+                        chains.  */
+                     repeat = 1;
+                     used[val >> 3] = 1;
+                   }
+               }
+           }
          while (repeat);
 
          if (elf_section_data (sec)->relocs != relstart)
@@ -8624,7 +8756,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info)
                          if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
                            ppc_howto_init ();
                          info->callbacks->einfo
-                           (_("%P: %H: %s relocation references "
+                           (_("%P: %H: %s references "
                               "optimized away TOC entry\n"),
                             ibfd, sec, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name);
@@ -8771,19 +8903,18 @@ allocate_got (struct elf_link_hash_entry *h,
   got->size += entsize;
 
   dyn = htab->elf.dynamic_sections_created;
-  if ((info->shared
-       || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
-           && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-               || h->root.type != bfd_link_hash_undefweak))
+  if (h->type == STT_GNU_IFUNC)
     {
-      asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
-      relgot->size += rentsize;
+      htab->reliplt->size += rentsize;
+      htab->got_reli_size += rentsize;
     }
-  else if (h->type == STT_GNU_IFUNC)
+  else if ((info->shared
+           || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+          && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+              || h->root.type != bfd_link_hash_undefweak))
     {
-      asection *relgot = htab->reliplt;
+      asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
       relgot->size += rentsize;
-      htab->got_reli_size += rentsize;
     }
 }
 
@@ -9047,7 +9178,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   for (p = eh->dyn_relocs; p != NULL; p = p->next)
     {
       asection *sreloc = elf_section_data (p->sec)->sreloc;
-      if (!htab->elf.dynamic_sections_created)
+      if (eh->elf.type == STT_GNU_IFUNC)
        sreloc = htab->reliplt;
       sreloc->size += p->count * sizeof (Elf64_External_Rela);
     }
@@ -9107,7 +9238,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       /* Set the contents of the .interp section to the interpreter.  */
       if (info->executable)
        {
-         s = bfd_get_section_by_name (dynobj, ".interp");
+         s = bfd_get_linker_section (dynobj, ".interp");
          if (s == NULL)
            abort ();
          s->size = sizeof ELF_DYNAMIC_INTERPRETER;
@@ -9126,14 +9257,13 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       unsigned char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
-      asection *srel;
 
       if (!is_ppc64_elf (ibfd))
        continue;
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct elf_dyn_relocs *p;
+         struct ppc_dyn_relocs *p;
 
          for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
            {
@@ -9147,8 +9277,8 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                }
              else if (p->count != 0)
                {
-                 srel = elf_section_data (p->sec)->sreloc;
-                 if (!htab->elf.dynamic_sections_created)
+                 asection *srel = elf_section_data (p->sec)->sreloc;
+                 if (p->ifunc)
                    srel = htab->reliplt;
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
@@ -9168,7 +9298,6 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (unsigned char *) end_local_plt;
       s = ppc64_elf_tdata (ibfd)->got;
-      srel = ppc64_elf_tdata (ibfd)->relgot;
       for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
        {
          struct got_entry **pent, *ent;
@@ -9184,19 +9313,25 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                  }
                else
                  {
-                   unsigned int num = 1;
+                   unsigned int ent_size = 8;
+                   unsigned int rel_size = sizeof (Elf64_External_Rela);
+
                    ent->got.offset = s->size;
                    if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
-                     num = 2;
-                   s->size += num * 8;
-                   if (info->shared)
-                     srel->size += num * sizeof (Elf64_External_Rela);
-                   else if ((*lgot_masks & PLT_IFUNC) != 0)
                      {
-                       htab->reliplt->size
-                         += num * sizeof (Elf64_External_Rela);
-                       htab->got_reli_size
-                         += num * sizeof (Elf64_External_Rela);
+                       ent_size *= 2;
+                       rel_size *= 2;
+                     }
+                   s->size += ent_size;
+                   if ((*lgot_masks & PLT_IFUNC) != 0)
+                     {
+                       htab->reliplt->size += rel_size;
+                       htab->got_reli_size += rel_size;
+                     }
+                   else if (info->shared)
+                     {
+                       asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+                       srel->size += rel_size;
                      }
                    pent = &ent->next;
                  }
@@ -9611,8 +9746,8 @@ build_plt_stub (struct ppc_link_hash_table *htab,
       bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
       bfd_vma to, from;
 
-      if (pltindex > 32767)
-       glinkoff += (pltindex - 32767) * 4;
+      if (pltindex > 32768)
+       glinkoff += (pltindex - 32768) * 4;
       to = (glinkoff
            + htab->glink->output_offset
            + htab->glink->output_section->vma);
@@ -9730,7 +9865,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
     {
       bfd_put_32 (obfd, CMPLDI_R2_0, p),                       p += 4;
       bfd_put_32 (obfd, BNECTR_P4, p),                         p += 4;
-      bfd_put_32 (obfd, B_DOT + cmp_branch_off, p),            p += 4;
+      bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4;
     }
   else
     bfd_put_32 (obfd, BCTR, p),                                        p += 4;
@@ -9831,7 +9966,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 %s\n"),
+         info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"),
                                  stub_entry->h->elf.root.root.string);
          bfd_set_error (bfd_error_bad_value);
          return 0;
@@ -9913,8 +10048,9 @@ 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"),
-                                 stub_entry->root.string);
+         info->callbacks->einfo
+           (_("%P: long branch stub `%s' offset overflow\n"),
+            stub_entry->root.string);
          htab->stub_error = TRUE;
          return FALSE;
        }
@@ -10034,7 +10170,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
          info->callbacks->einfo
-           (_("%P: linkage table error against `%s'\n"),
+           (_("%P: linkage table error against `%T'\n"),
             stub_entry->root.string);
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
@@ -10177,7 +10313,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
       if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
          info->callbacks->einfo
-           (_("%P: linkage table error against `%s'\n"),
+           (_("%P: linkage table error against `%T'\n"),
             stub_entry->h != NULL
             ? stub_entry->h->elf.root.root.string
             : "<local sym>");
@@ -10444,9 +10580,6 @@ ppc64_elf_setup_section_lists
   htab->add_stub_section = add_stub_section;
   htab->layout_sections_again = layout_sections_again;
 
-  if (htab->brlt == NULL)
-    return 0;
-
   /* Find the top input section id.  */
   for (input_bfd = info->input_bfds, top_id = 3;
        input_bfd != NULL;
@@ -10499,8 +10632,7 @@ ppc64_elf_start_multitoc_partition (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  elf_gp (info->output_bfd) = ppc64_elf_toc (info->output_bfd);
-  htab->toc_curr = elf_gp (info->output_bfd);
+  htab->toc_curr = ppc64_elf_set_toc (info, info->output_bfd);
   htab->toc_bfd = NULL;
   htab->toc_first_sec = NULL;
 }
@@ -10521,7 +10653,9 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
   if (!htab->second_toc_pass)
     {
       /* Keep track of the first .toc or .got section for this input bfd.  */
-      if (htab->toc_bfd != isec->owner)
+      bfd_boolean new_bfd = htab->toc_bfd != isec->owner;
+
+      if (new_bfd)
        {
          htab->toc_bfd = isec->owner;
          htab->toc_first_sec = isec;
@@ -10549,7 +10683,8 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
 
       /* Die if someone uses a linker script that doesn't keep input
         file .toc and .got together.  */
-      if (elf_gp (isec->owner) != 0
+      if (new_bfd
+         && elf_gp (isec->owner) != 0
          && elf_gp (isec->owner) != off)
        return FALSE;
 
@@ -10691,7 +10826,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       unsigned char *lgot_masks;
       bfd_size_type locsymcount;
       Elf_Internal_Shdr *symtab_hdr;
-      asection *s, *srel;
+      asection *s;
 
       if (!is_ppc64_elf (ibfd))
        continue;
@@ -10707,26 +10842,31 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
       end_local_plt = local_plt + locsymcount;
       lgot_masks = (unsigned char *) end_local_plt;
       s = ppc64_elf_tdata (ibfd)->got;
-      srel = ppc64_elf_tdata (ibfd)->relgot;
       for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
        {
          struct got_entry *ent;
 
          for (ent = *lgot_ents; ent != NULL; ent = ent->next)
            {
-             unsigned int num = 1;
+             unsigned int ent_size = 8;
+             unsigned int rel_size = sizeof (Elf64_External_Rela);
+
              ent->got.offset = s->size;
              if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
-               num = 2;
-             s->size += num * 8;
-             if (info->shared)
-               srel->size += num * sizeof (Elf64_External_Rela);
-             else if ((*lgot_masks & PLT_IFUNC) != 0)
                {
-                 htab->reliplt->size
-                   += num * sizeof (Elf64_External_Rela);
-                 htab->got_reli_size
-                   += num * sizeof (Elf64_External_Rela);
+                 ent_size *= 2;
+                 rel_size *= 2;
+               }
+             s->size += ent_size;
+             if ((*lgot_masks & PLT_IFUNC) != 0)
+               {
+                 htab->reliplt->size += rel_size;
+                 htab->got_reli_size += rel_size;
+               }
+             else if (info->shared)
+               {
+                 asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+                 srel->size += rel_size;
                }
            }
        }
@@ -10918,7 +11058,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
                  sym_value += adjust;
                }
 
-             dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
+             dest = opd_entry_value (sym_sec, sym_value,
+                                     &sym_sec, NULL, FALSE);
              if (dest == (bfd_vma) -1)
                continue;
            }
@@ -11257,6 +11398,7 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec)
 {
   if (isec->size == 0
       && isec->output_section->size == 0
+      && !(isec->output_section->flags & SEC_KEEP)
       && !bfd_section_removed_from_list (info->output_bfd,
                                         isec->output_section)
       && elf_section_data (isec->output_section)->dynindx == 0)
@@ -11287,9 +11429,11 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 
   htab->plt_static_chain = plt_static_chain;
   htab->plt_stub_align = plt_stub_align;
+  if (plt_thread_safe == -1 && !info->executable)
+    plt_thread_safe = 1;
   if (plt_thread_safe == -1)
     {
-      const char *const thread_starter[] =
+      static const char *const thread_starter[] =
        {
          "pthread_create",
          /* libstdc++ */
@@ -11305,7 +11449,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
          "GOMP_parallel_loop_dynamic_start",
          "GOMP_parallel_loop_guided_start",
          "GOMP_parallel_loop_runtime_start",
-         "GOMP_parallel_sections_start", 
+         "GOMP_parallel_sections_start",
        };
       unsigned i;
 
@@ -11493,7 +11637,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                          sym_value += adjust;
                        }
                      dest = opd_entry_value (sym_sec, sym_value,
-                                             &code_sec, &code_value);
+                                             &code_sec, &code_value, FALSE);
                      if (dest != (bfd_vma) -1)
                        {
                          destination = dest;
@@ -11611,7 +11755,6 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                    }
                  stub_entry->h = hash;
                  stub_entry->plt_ent = plt_ent;
-                 stub_entry->addend = irela->r_addend;
 
                  if (stub_entry->h != NULL)
                    htab->stub_globals += 1;
@@ -11662,9 +11805,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
 
       if (htab->glink_eh_frame != NULL
          && !bfd_is_abs_section (htab->glink_eh_frame->output_section)
-         && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0)
+         && htab->glink_eh_frame->output_section->size != 0)
        {
-         bfd_size_type size = 0;
+         size_t size = 0, align;
 
          for (stub_sec = htab->stub_bfd->sections;
               stub_sec != NULL;
@@ -11675,6 +11818,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
            size += 24;
          if (size != 0)
            size += sizeof (glink_eh_frame_cie);
+         align = 1;
+         align <<= htab->glink_eh_frame->output_section->alignment_power;
+         align -= 1;
+         size = (size + align) & ~align;
          htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
          htab->glink_eh_frame->size = size;
        }
@@ -11716,7 +11863,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
    move, we'll be called again.  Provide a value for TOCstart.  */
 
 bfd_vma
-ppc64_elf_toc (bfd *obfd)
+ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
 {
   asection *s;
   bfd_vma TOCstart;
@@ -11767,6 +11914,21 @@ ppc64_elf_toc (bfd *obfd)
   if (s != NULL)
     TOCstart = s->output_section->vma + s->output_offset;
 
+  _bfd_set_gp_value (obfd, TOCstart);
+
+  if (info != NULL && s != NULL && is_ppc64_elf (obfd))
+    {
+      struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+      if (htab != NULL
+         && htab->elf.hgot != NULL)
+       {
+         htab->elf.hgot->type = STT_OBJECT;
+         htab->elf.hgot->root.type = bfd_link_hash_defined;
+         htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
+         htab->elf.hgot->root.u.def.section = s;
+       }
+    }
   return TOCstart;
 }
 
@@ -11916,17 +12078,21 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
       && htab->glink_eh_frame->size != 0)
     {
       bfd_vma val;
+      bfd_byte *last_fde;
+      size_t last_fde_len, size, align, pad;
 
       p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
       if (p == NULL)
        return FALSE;
       htab->glink_eh_frame->contents = p;
+      last_fde = p;
 
       htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
 
       memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
       /* CIE length (rewrite in case little-endian).  */
-      bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
+      last_fde_len = sizeof (glink_eh_frame_cie) - 4;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
       p += sizeof (glink_eh_frame_cie);
 
       for (stub_sec = htab->stub_bfd->sections;
@@ -11934,6 +12100,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
          {
+           last_fde = p;
+           last_fde_len = 16;
            /* FDE length.  */
            bfd_put_32 (htab->elf.dynobj, 16, p);
            p += 4;
@@ -11966,6 +12134,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
          }
       if (htab->glink != NULL && htab->glink->size != 0)
        {
+         last_fde = p;
+         last_fde_len = 20;
          /* FDE length.  */
          bfd_put_32 (htab->elf.dynobj, 20, p);
          p += 4;
@@ -12003,7 +12173,16 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
          *p++ = DW_CFA_restore_extended;
          *p++ = 65;
        }
-      htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents;
+      /* Subsume any padding into the last FDE if user .eh_frame
+        sections are aligned more than glink_eh_frame.  Otherwise any
+        zero padding will be seen as a terminator.  */
+      size = p - htab->glink_eh_frame->contents;
+      align = 1;
+      align <<= htab->glink_eh_frame->output_section->alignment_power;
+      align -= 1;
+      pad = ((size + align) & ~align) - size;
+      htab->glink_eh_frame->size = size + pad;
+      bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
     }
 
   /* Build the stubs as directed by the stub hash table.  */
@@ -12191,7 +12370,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
   for (; rel < relend; rel++)
     {
       enum elf_ppc64_reloc_type r_type;
-      bfd_vma addend, orig_addend;
+      bfd_vma addend;
       bfd_reloc_status_type r;
       Elf_Internal_Sym *sym;
       asection *sec;
@@ -12206,11 +12385,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       bfd_vma relocation;
       bfd_boolean unresolved_reloc;
       bfd_boolean warned;
+      enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
       unsigned int insn;
       unsigned int mask;
       struct ppc_stub_hash_entry *stub_entry;
       bfd_vma max_br_offset;
       bfd_vma from;
+      const Elf_Internal_Rela orig_rel = *rel;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -12230,7 +12411,6 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       sym_name = NULL;
       unresolved_reloc = FALSE;
       warned = FALSE;
-      orig_addend = rel->r_addend;
 
       if (r_symndx < symtab_hdr->sh_info)
        {
@@ -12270,6 +12450,33 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                   unresolved_reloc, warned);
          sym_name = h_elf->root.root.string;
          sym_type = h_elf->type;
+         if (sec != NULL
+             && sec->owner == output_bfd
+             && strcmp (sec->name, ".opd") == 0)
+           {
+             /* This is a symbol defined in a linker script.  All
+                such are defined in output sections, even those
+                defined by simple assignment from a symbol defined in
+                an input section.  Transfer the symbol to an
+                appropriate input .opd section, so that a branch to
+                this symbol will be mapped to the location specified
+                by the opd entry.  */
+             struct bfd_link_order *lo;
+             for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
+               if (lo->type == bfd_indirect_link_order)
+                 {
+                   asection *isec = lo->u.indirect.section;
+                   if (h_elf->root.u.def.value >= isec->output_offset
+                       && h_elf->root.u.def.value < (isec->output_offset
+                                                     + isec->size))
+                     {
+                       h_elf->root.u.def.value -= isec->output_offset;
+                       h_elf->root.u.def.section = isec;
+                       sec = isec;
+                       break;
+                     }
+                 }
+           }
        }
       h = (struct ppc_link_hash_entry *) h_elf;
 
@@ -12282,6 +12489,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       if (info->relocatable)
        continue;
 
+      if (h != NULL && &h->elf == htab->elf.hgot)
+       {
+         relocation = (TOCstart
+                       + htab->stub_group[input_section->id].toc_off);
+         sec = bfd_abs_section_ptr;
+         unresolved_reloc = FALSE;
+       }
+
       /* TLS optimizations.  Replace instruction sequences and relocs
         based on information we collected in tls_optimize.  We edit
         RELOCS so that --emit-relocs will output something sensible
@@ -12336,8 +12551,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          else
            info->callbacks->einfo
              (!IS_PPC64_TLS_RELOC (r_type)
-              ? _("%P: %H: %s used with TLS symbol %s\n")
-              : _("%P: %H: %s used with non-TLS symbol %s\n"),
+              ? _("%P: %H: %s used with TLS symbol `%T'\n")
+              : _("%P: %H: %s used with non-TLS symbol `%T'\n"),
               input_bfd, input_section, rel->r_offset,
               ppc64_elf_howto_table[r_type]->name,
               sym_name);
@@ -12743,6 +12958,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       insn = 0;
       max_br_offset = 1 << 25;
       addend = rel->r_addend;
+      reloc_dest = DEST_NORMAL;
       switch (r_type)
        {
        default:
@@ -12792,7 +13008,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              && h->oh != NULL
              && h->oh->is_func_descriptor)
            fdh = ppc_follow_link (h->oh);
-         stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
+         stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
+                                          htab);
          if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
                  || stub_entry->stub_type == ppc_stub_plt_call_r2save
@@ -12801,74 +13018,89 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              bfd_boolean can_plt_call = FALSE;
 
+             /* All of these stubs will modify r2, so there must be a
+                branch and link followed by a nop.  The nop is
+                replaced by an insn to restore r2.  */
              if (rel->r_offset + 8 <= input_section->size)
                {
-                 unsigned long nop;
-                 nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
-                 if (nop == NOP
-                     || nop == CROR_151515 || nop == CROR_313131)
+                 unsigned long br;
+
+                 br = bfd_get_32 (input_bfd,
+                                  contents + rel->r_offset);
+                 if ((br & 1) != 0)
                    {
-                     if (h != NULL
-                         && (h == htab->tls_get_addr_fd
-                             || h == htab->tls_get_addr)
-                         && !htab->no_tls_get_addr_opt)
+                     unsigned long nop;
+
+                     nop = bfd_get_32 (input_bfd,
+                                       contents + rel->r_offset + 4);
+                     if (nop == NOP
+                         || nop == CROR_151515 || nop == CROR_313131)
                        {
-                         /* Special stub used, leave nop alone.  */
+                         if (h != NULL
+                             && (h == htab->tls_get_addr_fd
+                                 || h == htab->tls_get_addr)
+                             && !htab->no_tls_get_addr_opt)
+                           {
+                             /* Special stub used, leave nop alone.  */
+                           }
+                         else
+                           bfd_put_32 (input_bfd, LD_R2_40R1,
+                                       contents + rel->r_offset + 4);
+                         can_plt_call = TRUE;
                        }
-                     else
-                       bfd_put_32 (input_bfd, LD_R2_40R1,
-                                   contents + rel->r_offset + 4);
-                     can_plt_call = TRUE;
                    }
                }
 
-             if (!can_plt_call)
+             if (!can_plt_call && h != NULL)
                {
-                 if (stub_entry->stub_type == ppc_stub_plt_call
-                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
-                   {
-                     /* If this is a plain branch rather than a branch
-                        and link, don't require a nop.  However, don't
-                        allow tail calls in a shared library as they
-                        will result in r2 being corrupted.  */
-                     unsigned long br;
-                     br = bfd_get_32 (input_bfd, contents + rel->r_offset);
-                     if (info->executable && (br & 1) == 0)
-                       can_plt_call = TRUE;
-                     else
-                       stub_entry = NULL;
-                   }
-                 else if (h != NULL
-                          && strcmp (h->elf.root.root.string,
-                                     ".__libc_start_main") == 0)
+                 const char *name = h->elf.root.root.string;
+
+                 if (*name == '.')
+                   ++name;
+
+                 if (strncmp (name, "__libc_start_main", 17) == 0
+                     && (name[17] == 0 || name[17] == '@'))
                    {
-                     /* Allow crt1 branch to go via a toc adjusting stub.  */
+                     /* Allow crt1 branch to go via a toc adjusting
+                        stub.  Other calls that never return could do
+                        the same, if we could detect such.  */
                      can_plt_call = TRUE;
                    }
-                 else
+               }
+
+             if (!can_plt_call)
+               {
+                 /* g++ as of 20130507 emits self-calls without a
+                    following nop.  This is arguably wrong since we
+                    have conflicting information.  On the one hand a
+                    global symbol and on the other a local call
+                    sequence, but don't error for this special case.
+                    It isn't possible to cheaply verify we have
+                    exactly such a call.  Allow all calls to the same
+                    section.  */
+                 asection *code_sec = sec;
+
+                 if (get_opd_info (sec) != NULL)
                    {
-                     if (strcmp (input_section->output_section->name,
-                                 ".init") == 0
-                         || strcmp (input_section->output_section->name,
-                                    ".fini") == 0)
-                       info->callbacks->einfo
-                         (_("%P: %H: automatic multiple TOCs "
-                            "not supported using your crt files; "
-                            "recompile with -mminimal-toc or upgrade gcc\n"),
-                          input_bfd, input_section, rel->r_offset);
-                     else
-                       info->callbacks->einfo
-                         (_("%P: %H: sibling call optimization to `%s' "
-                            "does not allow automatic multiple TOCs; "
-                            "recompile with -mminimal-toc or "
-                            "-fno-optimize-sibling-calls, "
-                            "or make `%s' extern\n"),
-                          input_bfd, input_section, rel->r_offset,
-                          sym_name,
-                          sym_name);
-                     bfd_set_error (bfd_error_bad_value);
-                     ret = FALSE;
+                     bfd_vma off = (relocation + addend
+                                    - sec->output_section->vma
+                                    - sec->output_offset);
+
+                     opd_entry_value (sec, off, &code_sec, NULL, FALSE);
                    }
+                 if (code_sec == input_section)
+                   can_plt_call = TRUE;
+               }
+
+             if (!can_plt_call)
+               {
+                 info->callbacks->einfo
+                   (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
+                      "recompile with -fPIC"),
+                    input_bfd, input_section, rel->r_offset, sym_name);
+
+                 bfd_set_error (bfd_error_bad_value);
+                 ret = FALSE;
                }
 
              if (can_plt_call
@@ -12886,11 +13118,12 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              bfd_vma off = (relocation + addend
                             - sec->output_section->vma
                             - sec->output_offset);
-             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
+             bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE);
              if (dest != (bfd_vma) -1)
                {
                  relocation = dest;
                  addend = 0;
+                 reloc_dest = DEST_OPD;
                }
            }
 
@@ -12918,6 +13151,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                            + stub_entry->stub_sec->output_offset
                            + stub_entry->stub_sec->output_section->vma);
              addend = 0;
+             reloc_dest = DEST_STUB;
 
              if ((stub_entry->stub_type == ppc_stub_plt_call
                   || stub_entry->stub_type == ppc_stub_plt_call_r2save)
@@ -12975,7 +13209,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
        {
        default:
          info->callbacks->einfo
-           (_("%P: %B: unknown relocation type %d for symbol %s\n"),
+           (_("%P: %B: unknown relocation type %d for `%T'\n"),
             input_bfd, (int) r_type, sym_name);
 
          bfd_set_error (bfd_error_bad_value);
@@ -13060,6 +13294,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                      ;
                    else
                      {
+                       BFD_ASSERT (h->elf.dynindx != -1);
                        indx = h->elf.dynindx;
                        unresolved_reloc = FALSE;
                      }
@@ -13073,7 +13308,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  }
 
                for (; ent != NULL; ent = ent->next)
-                 if (ent->addend == orig_addend
+                 if (ent->addend == orig_rel.r_addend
                      && ent->owner == input_bfd
                      && ent->tls_type == tls_type)
                    break;
@@ -13107,15 +13342,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                ifunc = (h != NULL
                         ? h->elf.type == STT_GNU_IFUNC
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
-               if ((info->shared || indx != 0)
-                   && (h == NULL
-                       || (tls_type == (TLS_TLS | TLS_LD)
-                           && !h->elf.def_dynamic)
-                       || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
-                       || h->elf.root.type != bfd_link_hash_undefweak))
-                 relgot = ppc64_elf_tdata (ent->owner)->relgot;
-               else if (ifunc)
+               if (ifunc)
                  relgot = htab->reliplt;
+               else if ((info->shared || indx != 0)
+                        && (h == NULL
+                            || (tls_type == (TLS_TLS | TLS_LD)
+                                && !h->elf.def_dynamic)
+                            || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
+                            || h->elf.root.type != bfd_link_hash_undefweak))
+                 relgot = ppc64_elf_tdata (ent->owner)->relgot;
                if (relgot != NULL)
                  {
                    outrel.r_offset = (got->output_section->vma
@@ -13226,7 +13461,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            {
              struct plt_entry *ent;
              for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
-               if (ent->addend == orig_addend
+               if (ent->addend == orig_rel.r_addend
                    && ent->plt.offset != (bfd_vma) -1)
                  {
                    relocation = (htab->plt->output_section->vma
@@ -13432,7 +13667,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
              else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
                       && !is_opd
                       && r_type != R_PPC64_TOC)
-               outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+               {
+                 BFD_ASSERT (h->elf.dynindx != -1);
+                 outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+               }
              else
                {
                  /* This symbol is local, or marked to become local,
@@ -13481,8 +13719,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                        {
                          info->callbacks->einfo
-                           (_("%P: %H: relocation %s for indirect "
-                              "function %s unsupported\n"),
+                           (_("%P: %H: %s for indirect "
+                              "function `%T' unsupported\n"),
                             input_bfd, input_section, rel->r_offset,
                             ppc64_elf_howto_table[r_type]->name,
                             sym_name);
@@ -13526,7 +13764,9 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              sreloc = elf_section_data (input_section)->sreloc;
-             if (!htab->elf.dynamic_sections_created)
+             if (h != NULL
+                 ? h->elf.type == STT_GNU_IFUNC
+                 : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
                sreloc = htab->reliplt;
              if (sreloc == NULL)
                abort ();
@@ -13586,7 +13826,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          /* These ones haven't been implemented yet.  */
 
          info->callbacks->einfo
-           (_("%P: %B: relocation %s is not supported for symbol %s\n"),
+           (_("%P: %B: %s is not supported for `%T'\n"),
             input_bfd,
             ppc64_elf_howto_table[r_type]->name, sym_name);
 
@@ -13756,7 +13996,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                                      rel->r_offset) != (bfd_vma) -1)
        {
          info->callbacks->einfo
-           (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
+           (_("%P: %H: unresolvable %s against `%T'\n"),
             input_bfd, input_section, rel->r_offset,
             ppc64_elf_howto_table[(int) r_type]->name,
             h->elf.root.root.string);
@@ -13773,8 +14013,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
       if (r != bfd_reloc_ok)
        {
-         if (sym_name == NULL)
-           sym_name = "(null)";
+         char *more_info = NULL;
+         const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
+
+         if (reloc_dest != DEST_NORMAL)
+           {
+             more_info = bfd_malloc (strlen (reloc_name) + 8);
+             if (more_info != NULL)
+               {
+                 strcpy (more_info, reloc_name);
+                 strcat (more_info, (reloc_dest == DEST_OPD
+                                     ? " (OPD)" : " (stub)"));
+                 reloc_name = more_info;
+               }
+           }
+
          if (r == bfd_reloc_overflow)
            {
              if (warned)
@@ -13793,21 +14046,21 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                }
 
              if (!((*info->callbacks->reloc_overflow)
-                   (info, (h ? &h->elf.root : NULL), sym_name,
-                    ppc64_elf_howto_table[r_type]->name,
-                    orig_addend, input_bfd, input_section, rel->r_offset)))
+                   (info, &h->elf.root, sym_name,
+                    reloc_name, orig_rel.r_addend,
+                    input_bfd, input_section, rel->r_offset)))
                return FALSE;
            }
          else
            {
              info->callbacks->einfo
-               (_("%P: %H: %s reloc against `%s': error %d\n"),
+               (_("%P: %H: %s against `%T': error %d\n"),
                 input_bfd, input_section, rel->r_offset,
-                ppc64_elf_howto_table[r_type]->name,
-                sym_name,
-                (int) r);
+                reloc_name, sym_name, (int) r);
              ret = FALSE;
            }
+         if (more_info != NULL)
+           free (more_info);
        }
     }
 
@@ -13821,8 +14074,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
       bfd_size_type amt;
       amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
       rel = bfd_alloc (input_bfd, amt);
-      BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd_relocs == NULL);
-      ppc64_elf_tdata (input_bfd)->opd_relocs = rel;
+      BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd.relocs == NULL);
+      ppc64_elf_tdata (input_bfd)->opd.relocs = rel;
       if (rel == NULL)
        return FALSE;
       memcpy (rel, relocs, amt);
@@ -13945,9 +14198,15 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
    dynamic linker, before writing them out.  */
 
 static enum elf_reloc_type_class
-ppc64_elf_reloc_type_class (const Elf_Internal_Rela *rela)
+ppc64_elf_reloc_type_class (const struct bfd_link_info *info,
+                           const asection *rel_sec,
+                           const Elf_Internal_Rela *rela)
 {
   enum elf_ppc64_reloc_type r_type;
+  struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+  if (rel_sec == htab->reliplt)
+    return reloc_class_ifunc;
 
   r_type = ELF64_R_TYPE (rela->r_info);
   switch (r_type)
@@ -13978,7 +14237,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
     return FALSE;
 
   dynobj = htab->elf.dynobj;
-  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  sdyn = bfd_get_linker_section (dynobj, ".dynamic");
 
   if (htab->elf.dynamic_sections_created)
     {
This page took 0.117515 seconds and 4 git commands to generate.