bfd/
authorAlan Modra <amodra@gmail.com>
Sun, 14 Mar 2010 07:05:36 +0000 (07:05 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 14 Mar 2010 07:05:36 +0000 (07:05 +0000)
PR ld/11378
* elf64-ppc.h (ppc64_elf_check_init_fini): Declare.
* elf64-ppc.c (call_check_done): Define.
(ppc64_elf_add_symbol_hook): Substitute bfd_get_section_name macro.
(ppc64_elf_check_relocs, ppc64_elf_size_dynamic_sections): Likewise.
(ppc64_elf_finish_multitoc_partition): Remove unnecessary check.
(toc_adjusting_stub_needed): Use call_check_done rather than toc_off.
Simplify return logic.  Iterate over all .init and .fini fragments
by recursion.  Set makes_toc_func_call here..
(ppc64_elf_next_input_section): ..rather than here.
(check_pasted_section, ppc64_elf_check_init_fini): New functions.
ld/
PR ld/11378
* emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation): Call
ppc64_elf_check_init_fini and warn if .init/.fini use different TOCs.

bfd/ChangeLog
bfd/elf64-ppc.c
bfd/elf64-ppc.h
ld/ChangeLog
ld/emultempl/ppc64elf.em

index 27a3327e63d3d37b58f65e5de900d940af1af95e..e0260f763347107c19df952c2a6395d1fe0dabdb 100644 (file)
@@ -1,3 +1,17 @@
+2010-03-14  Alan Modra  <amodra@gmail.com>
+
+       PR ld/11378
+       * elf64-ppc.h (ppc64_elf_check_init_fini): Declare.
+       * elf64-ppc.c (call_check_done): Define.
+       (ppc64_elf_add_symbol_hook): Substitute bfd_get_section_name macro.
+       (ppc64_elf_check_relocs, ppc64_elf_size_dynamic_sections): Likewise.
+       (ppc64_elf_finish_multitoc_partition): Remove unnecessary check.
+       (toc_adjusting_stub_needed): Use call_check_done rather than toc_off.
+       Simplify return logic.  Iterate over all .init and .fini fragments
+       by recursion.  Set makes_toc_func_call here..
+       (ppc64_elf_next_input_section): ..rather than here.
+       (check_pasted_section, ppc64_elf_check_init_fini): New functions.
+
 2010-03-13  Alan Modra  <amodra@gmail.com>
 
        PR ld/11375
index 5696838502ad1fa42ddec02e56a12e8ffe160732..1834e22527cef8a2c16dd184768b9ace137b17bb 100644 (file)
@@ -3820,6 +3820,7 @@ struct ppc_link_hash_table
 
 /* Recursion protection when determining above flag.  */
 #define call_check_in_progress sec_flg4
+#define call_check_done sec_flg5
 
 /* Get the ppc64 ELF linker hash table from a link_info structure.  */
 
@@ -4573,7 +4574,7 @@ ppc64_elf_add_symbol_hook (bfd *ibfd,
   else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
     ;
   else if (*sec != NULL
-          && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
+          && strcmp ((*sec)->name, ".opd") == 0)
     isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
   return TRUE;
@@ -4880,7 +4881,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   sreloc = NULL;
   opd_sym_map = NULL;
-  if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0)
+  if (strcmp (sec->name, ".opd") == 0)
     {
       /* Garbage collection needs some extra help with .opd sections.
         We don't want to necessarily keep everything referenced by
@@ -8811,7 +8812,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
+      else if (CONST_STRNEQ (s->name, ".rela"))
        {
          if (s->size != 0)
            {
@@ -10125,9 +10126,6 @@ ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
 {
   struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
-  if (htab == NULL)
-    return;
-
   /* After the second pass, toc_curr tracks the TOC offset used
      for code sections below in ppc64_elf_next_input_section.  */
   htab->toc_curr = TOC_BASE_OFF;
@@ -10144,10 +10142,10 @@ ppc64_elf_finish_multitoc_partition (struct bfd_link_info *info)
 static int
 toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
 {
-  Elf_Internal_Rela *relstart, *rel;
-  Elf_Internal_Sym *local_syms;
   int ret;
-  struct ppc_link_hash_table *htab;
+
+  /* Mark this section as checked.  */
+  isec->call_check_done = 1;
 
   /* We know none of our code bearing sections will need toc stubs.  */
   if ((isec->flags & SEC_LINKER_CREATED) != 0)
@@ -10159,179 +10157,189 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec)
   if (isec->output_section == NULL)
     return 0;
 
-  if (isec->reloc_count == 0)
-    return 0;
-
-  relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
-                                       info->keep_memory);
-  if (relstart == NULL)
-    return -1;
-
-  /* Look for branches to outside of this section.  */
-  local_syms = NULL;
   ret = 0;
-  htab = ppc_hash_table (info);
-  if (htab == NULL)
-    return -1;
-
-  for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
+  if (isec->reloc_count != 0)
     {
-      enum elf_ppc64_reloc_type r_type;
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
-      struct ppc_link_hash_entry *eh;
-      Elf_Internal_Sym *sym;
-      asection *sym_sec;
-      struct _opd_sec_data *opd;
-      bfd_vma sym_value;
-      bfd_vma dest;
-
-      r_type = ELF64_R_TYPE (rel->r_info);
-      if (r_type != R_PPC64_REL24
-         && r_type != R_PPC64_REL14
-         && r_type != R_PPC64_REL14_BRTAKEN
-         && r_type != R_PPC64_REL14_BRNTAKEN)
-       continue;
-
-      r_symndx = ELF64_R_SYM (rel->r_info);
-      if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx,
-                     isec->owner))
-       {
-         ret = -1;
-         break;
-       }
-
-      /* Calls to dynamic lib functions go through a plt call stub
-        that uses r2.  */
-      eh = (struct ppc_link_hash_entry *) h;
-      if (eh != NULL
-         && (eh->elf.plt.plist != NULL
-             || (eh->oh != NULL
-                 && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
-       {
-         ret = 1;
-         break;
-       }
+      Elf_Internal_Rela *relstart, *rel;
+      Elf_Internal_Sym *local_syms;
+      struct ppc_link_hash_table *htab;
 
-      if (sym_sec == NULL)
-       /* Ignore other undefined symbols.  */
-       continue;
+      relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL,
+                                           info->keep_memory);
+      if (relstart == NULL)
+       return -1;
 
-      /* Assume branches to other sections not included in the link need
-        stubs too, to cover -R and absolute syms.  */
-      if (sym_sec->output_section == NULL)
-       {
-         ret = 1;
-         break;
-       }
+      /* Look for branches to outside of this section.  */
+      local_syms = NULL;
+      htab = ppc_hash_table (info);
+      if (htab == NULL)
+       return -1;
 
-      if (h == NULL)
-       sym_value = sym->st_value;
-      else
+      for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
        {
-         if (h->root.type != bfd_link_hash_defined
-             && h->root.type != bfd_link_hash_defweak)
-           abort ();
-         sym_value = h->root.u.def.value;
-       }
-      sym_value += rel->r_addend;
+         enum elf_ppc64_reloc_type r_type;
+         unsigned long r_symndx;
+         struct elf_link_hash_entry *h;
+         struct ppc_link_hash_entry *eh;
+         Elf_Internal_Sym *sym;
+         asection *sym_sec;
+         struct _opd_sec_data *opd;
+         bfd_vma sym_value;
+         bfd_vma dest;
+
+         r_type = ELF64_R_TYPE (rel->r_info);
+         if (r_type != R_PPC64_REL24
+             && r_type != R_PPC64_REL14
+             && r_type != R_PPC64_REL14_BRTAKEN
+             && r_type != R_PPC64_REL14_BRNTAKEN)
+           continue;
 
-      /* If this branch reloc uses an opd sym, find the code section.  */
-      opd = get_opd_info (sym_sec);
-      if (opd != NULL)
-       {
-         if (h == NULL && opd->adjust != NULL)
+         r_symndx = ELF64_R_SYM (rel->r_info);
+         if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx,
+                         isec->owner))
            {
-             long adjust;
+             ret = -1;
+             break;
+           }
 
-             adjust = opd->adjust[sym->st_value / 8];
-             if (adjust == -1)
-               /* Assume deleted functions won't ever be called.  */
-               continue;
-             sym_value += adjust;
+         /* Calls to dynamic lib functions go through a plt call stub
+            that uses r2.  */
+         eh = (struct ppc_link_hash_entry *) h;
+         if (eh != NULL
+             && (eh->elf.plt.plist != NULL
+                 || (eh->oh != NULL
+                     && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
+           {
+             ret = 1;
+             break;
            }
 
-         dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
-         if (dest == (bfd_vma) -1)
+         if (sym_sec == NULL)
+           /* Ignore other undefined symbols.  */
            continue;
-       }
-      else
-       dest = (sym_value
-               + sym_sec->output_offset
-               + sym_sec->output_section->vma);
 
-      /* Ignore branch to self.  */
-      if (sym_sec == isec)
-       continue;
+         /* Assume branches to other sections not included in the
+            link need stubs too, to cover -R and absolute syms.  */
+         if (sym_sec->output_section == NULL)
+           {
+             ret = 1;
+             break;
+           }
 
-      /* If the called function uses the toc, we need a stub.  */
-      if (sym_sec->has_toc_reloc
-         || sym_sec->makes_toc_func_call)
-       {
-         ret = 1;
-         break;
-       }
+         if (h == NULL)
+           sym_value = sym->st_value;
+         else
+           {
+             if (h->root.type != bfd_link_hash_defined
+                 && h->root.type != bfd_link_hash_defweak)
+               abort ();
+             sym_value = h->root.u.def.value;
+           }
+         sym_value += rel->r_addend;
 
-      /* Assume any branch that needs a long branch stub might in fact
-        need a plt_branch stub.  A plt_branch stub uses r2.  */
-      else if (dest - (isec->output_offset
-                      + isec->output_section->vma
-                      + rel->r_offset) + (1 << 25) >= (2 << 25))
-       {
-         ret = 1;
-         break;
-       }
+         /* If this branch reloc uses an opd sym, find the code section.  */
+         opd = get_opd_info (sym_sec);
+         if (opd != NULL)
+           {
+             if (h == NULL && opd->adjust != NULL)
+               {
+                 long adjust;
 
-      /* If calling back to a section in the process of being tested, we
-        can't say for sure that no toc adjusting stubs are needed, so
-        don't return zero.  */
-      else if (sym_sec->call_check_in_progress)
-       ret = 2;
+                 adjust = opd->adjust[sym->st_value / 8];
+                 if (adjust == -1)
+                   /* Assume deleted functions won't ever be called.  */
+                   continue;
+                 sym_value += adjust;
+               }
 
-      /* Branches to another section that itself doesn't have any TOC
-        references are OK.  Recursively call ourselves to check.  */
-      else if (sym_sec->id <= htab->top_id
-              && htab->stub_group[sym_sec->id].toc_off == 0)
-       {
-         int recur;
+             dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
+             if (dest == (bfd_vma) -1)
+               continue;
+           }
+         else
+           dest = (sym_value
+                   + sym_sec->output_offset
+                   + sym_sec->output_section->vma);
 
-         /* Mark current section as indeterminate, so that other
-            sections that call back to current won't be marked as
-            known.  */
-         isec->call_check_in_progress = 1;
-         recur = toc_adjusting_stub_needed (info, sym_sec);
-         isec->call_check_in_progress = 0;
+         /* Ignore branch to self.  */
+         if (sym_sec == isec)
+           continue;
 
-         if (recur < 0)
+         /* If the called function uses the toc, we need a stub.  */
+         if (sym_sec->has_toc_reloc
+             || sym_sec->makes_toc_func_call)
            {
-             /* An error.  Exit.  */
-             ret = -1;
+             ret = 1;
              break;
            }
-         else if (recur <= 1)
+
+         /* Assume any branch that needs a long branch stub might in fact
+            need a plt_branch stub.  A plt_branch stub uses r2.  */
+         else if (dest - (isec->output_offset
+                          + isec->output_section->vma
+                          + rel->r_offset) + (1 << 25) >= (2 << 25))
            {
-             /* Known result.  Mark as checked and set section flag.  */
-             htab->stub_group[sym_sec->id].toc_off = 1;
+             ret = 1;
+             break;
+           }
+
+         /* If calling back to a section in the process of being
+            tested, we can't say for sure that no toc adjusting stubs
+            are needed, so don't return zero.  */
+         else if (sym_sec->call_check_in_progress)
+           ret = 2;
+
+         /* Branches to another section that itself doesn't have any TOC
+            references are OK.  Recursively call ourselves to check.  */
+         else if (!sym_sec->call_check_done)
+           {
+             int recur;
+
+             /* Mark current section as indeterminate, so that other
+                sections that call back to current won't be marked as
+                known.  */
+             isec->call_check_in_progress = 1;
+             recur = toc_adjusting_stub_needed (info, sym_sec);
+             isec->call_check_in_progress = 0;
+
              if (recur != 0)
                {
-                 sym_sec->makes_toc_func_call = 1;
-                 ret = 1;
-                 break;
+                 ret = recur;
+                 if (recur != 2)
+                   break;
                }
            }
-         else
-           {
-             /* Unknown result.  Continue checking.  */
-             ret = 2;
-           }
+       }
+
+      if (local_syms != NULL
+         && (elf_symtab_hdr (isec->owner).contents
+             != (unsigned char *) local_syms))
+       free (local_syms);
+      if (elf_section_data (isec)->relocs != relstart)
+       free (relstart);
+    }
+
+  if ((ret & 1) == 0
+      && isec->map_head.s != NULL
+      && (strcmp (isec->output_section->name, ".init") == 0
+         || strcmp (isec->output_section->name, ".fini") == 0))
+    {
+      if (isec->map_head.s->has_toc_reloc
+         || isec->map_head.s->makes_toc_func_call)
+       ret = 1;
+      else if (!isec->map_head.s->call_check_done)
+       {
+         int recur;
+         isec->call_check_in_progress = 1;
+         recur = toc_adjusting_stub_needed (info, isec->map_head.s);
+         isec->call_check_in_progress = 0;
+         if (recur != 0)
+           ret = recur;
        }
     }
 
-  if (local_syms != NULL
-      && (elf_symtab_hdr (isec->owner).contents != (unsigned char *) local_syms))
-    free (local_syms);
-  if (elf_section_data (isec)->relocs != relstart)
-    free (relstart);
+  if (ret == 1)
+    isec->makes_toc_func_call = 1;
 
   return ret;
 }
@@ -10377,23 +10385,55 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
          if (elf_gp (isec->owner) != 0)
            htab->toc_curr = elf_gp (isec->owner);
        }
-      else if (htab->stub_group[isec->id].toc_off == 0)
-       {
-         int ret = toc_adjusting_stub_needed (info, isec);
-         if (ret < 0)
-           return FALSE;
-         else
-           isec->makes_toc_func_call = ret & 1;
-       }
+      else if (!isec->call_check_done
+              && toc_adjusting_stub_needed (info, isec) < 0)
+       return FALSE;
     }
 
   /* Functions that don't use the TOC can belong in any TOC group.
      Use the last TOC base.  This happens to make _init and _fini
-     pasting work.  */
+     pasting work, because the fragments generally don't use the TOC.  */
   htab->stub_group[isec->id].toc_off = htab->toc_curr;
   return TRUE;
 }
 
+/* Check that all .init and .fini sections use the same toc, if they
+   have toc relocs.  */
+
+static bfd_boolean
+check_pasted_section (struct bfd_link_info *info, const char *name)
+{
+  asection *o = bfd_get_section_by_name (info->output_bfd, name);
+
+  if (o != NULL)
+    {
+      struct ppc_link_hash_table *htab = ppc_hash_table (info);
+      bfd_vma toc_off = 0;
+      asection *i;
+
+      for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+       if (i->has_toc_reloc)
+         {
+           if (toc_off == 0)
+             toc_off = htab->stub_group[i->id].toc_off;
+           else if (toc_off != htab->stub_group[i->id].toc_off)
+             return FALSE;
+         }
+      /* Make sure the whole pasted function uses the same toc offset.  */
+      if (toc_off != 0)
+       for (i = o->map_head.s; i != NULL; i = i->map_head.s)
+         htab->stub_group[i->id].toc_off = toc_off;
+    }
+  return TRUE;
+}
+
+bfd_boolean
+ppc64_elf_check_init_fini (struct bfd_link_info *info)
+{
+  return (check_pasted_section (info, ".init")
+         & check_pasted_section (info, ".fini"));
+}
+
 /* See whether we can group stub sections together.  Grouping stub
    sections may result in fewer stubs.  More importantly, we need to
    put all .init* and .fini* stubs at the beginning of the .init or
index 9f69e06f60c53932637ffc550207e9fb725ae680..b6bc5fb21c66a0eab195ca755f858da40bdcdb1b 100644 (file)
@@ -42,6 +42,8 @@ bfd_boolean ppc64_elf_layout_multitoc
   (struct bfd_link_info *);
 void ppc64_elf_finish_multitoc_partition
   (struct bfd_link_info *);
+bfd_boolean ppc64_elf_check_init_fini
+  (struct bfd_link_info *);
 bfd_boolean ppc64_elf_next_input_section
   (struct bfd_link_info *, asection *);
 bfd_boolean ppc64_elf_size_stubs
index 9905b0a620cdd510c1a7de7e2c5a4e34ebe6c192..61f50814afaeb20e630ea03962ec85220b43df5d 100644 (file)
@@ -1,3 +1,9 @@
+2010-03-14  Alan Modra  <amodra@gmail.com>
+
+       PR ld/11378
+       * emultempl/ppc64elf.em (gld${EMULATION_NAME}_after_allocation): Call
+       ppc64_elf_check_init_fini and warn if .init/.fini use different TOCs.
+
 2010-03-11  George Gensure  <werkt0@gmail.com>
 
        PR ld/11367
index 2e6c8052f4f9b705fe3549c1ba2ef36488d78ef3..0d9dba9e8ed5390776d402985d2b972d9f52b089 100644 (file)
@@ -346,6 +346,9 @@ gld${EMULATION_NAME}_after_allocation (void)
 
          lang_for_each_statement (build_section_lists);
 
+         if (!ppc64_elf_check_init_fini (&link_info))
+           einfo ("%P: .init/.fini fragments use differing TOC pointers\n");
+
          /* Call into the BFD backend to do the real work.  */
          if (!ppc64_elf_size_stubs (&link_info, group_size))
            einfo ("%X%P: can not size stub section: %E\n");