PR binutils/12720
[binutils-gdb.git] / bfd / elf32-ppc.c
index 2b457d6d9bfe43e6a89151c7121fa4a1c0c4d254..c7363753d497ecb28c75b615aa76cb4cd0cb0ded 100644 (file)
@@ -2785,6 +2785,7 @@ ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ppc_elf_hash_entry (entry)->linker_section_pointer = NULL;
       ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
       ppc_elf_hash_entry (entry)->tls_mask = 0;
+      ppc_elf_hash_entry (entry)->has_sda_refs = 0;
     }
 
   return entry;
@@ -3112,8 +3113,9 @@ ppc_elf_add_symbol_hook (bfd *abfd,
     }
 
   if ((abfd->flags & DYNAMIC) == 0
-      && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
-    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
+      && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+         || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
+    elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
 
   return TRUE;
 }
@@ -4630,10 +4632,15 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
     return TRUE;
 
   htab = ppc_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+
   /* Make two passes through the relocs.  First time check that tls
      relocs involved in setting up a tls_get_addr call are indeed
-     followed by such a call.  If they are not, exclude them from
-     the optimizations done on the second pass.  */
+     followed by such a call.  If they are not, don't do any tls
+     optimization.  On the second pass twiddle tls_mask flags to
+     notify relocate_section that optimization can be done, and
+     adjust got and plt refcounts.  */
   for (pass = 0; pass < 2; ++pass)
     for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
       {
@@ -4645,6 +4652,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
            {
              Elf_Internal_Rela *relstart, *rel, *relend;
+             int expecting_tls_get_addr = 0;
 
              /* Read the relocations.  */
              relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -4661,7 +4669,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  char *tls_mask;
                  char tls_set, tls_clear;
                  bfd_boolean is_local;
-                 int expecting_tls_get_addr;
                  bfd_signed_vma *got_count;
 
                  r_symndx = ELF32_R_SYM (rel->r_info);
@@ -4676,13 +4683,34 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                        h = (struct elf_link_hash_entry *) h->root.u.i.link;
                    }
 
-                 expecting_tls_get_addr = 0;
                  is_local = FALSE;
                  if (h == NULL
                      || !h->def_dynamic)
                    is_local = TRUE;
 
                  r_type = ELF32_R_TYPE (rel->r_info);
+                 /* If this section has old-style __tls_get_addr calls
+                    without marker relocs, then check that each
+                    __tls_get_addr call reloc is preceded by a reloc
+                    that conceivably belongs to the __tls_get_addr arg
+                    setup insn.  If we don't find matching arg setup
+                    relocs, don't do any tls optimization.  */
+                 if (pass == 0
+                     && sec->has_tls_get_addr_call
+                     && h != NULL
+                     && h == htab->tls_get_addr
+                     && !expecting_tls_get_addr
+                     && is_branch_reloc (r_type))
+                   {
+                     info->callbacks->minfo ("%C __tls_get_addr lost arg, "
+                                             "TLS optimization disabled\n",
+                                             ibfd, sec, rel->r_offset);
+                     if (elf_section_data (sec)->relocs != relstart)
+                       free (relstart);
+                     return TRUE;
+                   }
+
+                 expecting_tls_get_addr = 0;
                  switch (r_type)
                    {
                    case R_PPC_GOT_TLSLD16:
@@ -4759,9 +4787,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
-                        the entire section.  */
-                     sec->has_tls_reloc = 0;
-                     break;
+                        the entire optimization.  */
+                     info->callbacks->minfo (_("%C arg lost __tls_get_addr, "
+                                               "TLS optimization disabled\n"),
+                                             ibfd, sec, rel->r_offset);
+                     if (elf_section_data (sec)->relocs != relstart)
+                       free (relstart);
+                     return TRUE;
                    }
 
                  if (expecting_tls_get_addr)
@@ -6391,6 +6423,7 @@ ppc_elf_relax_section (bfd *abfd,
     {
       /* Append sufficient NOP relocs so we can write out relocation
         information for the trampolines.  */
+      Elf_Internal_Shdr *rel_hdr;
       Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count)
                                                  * sizeof (*new_relocs));
       unsigned ix;
@@ -6409,8 +6442,8 @@ ppc_elf_relax_section (bfd *abfd,
        free (internal_relocs);
       elf_section_data (isec)->relocs = new_relocs;
       isec->reloc_count += changes;
-      elf_section_data (isec)->rel_hdr.sh_size
-       += changes * elf_section_data (isec)->rel_hdr.sh_entsize;
+      rel_hdr = _bfd_elf_single_rel_hdr (isec);
+      rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
     }
   else if (elf_section_data (isec)->relocs != internal_relocs)
     free (internal_relocs);
@@ -6816,10 +6849,8 @@ ppc_elf_relocate_section (bfd *output_bfd,
          howto = NULL;
          if (r_type < R_PPC_max)
            howto = ppc_elf_howto_table[r_type];
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
+         RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+                                          rel, relend, howto, contents);
        }
 
       if (info->relocatable)