* elf64-ppc.c (merge_got_entries): Move earlier in file.
authorAlan Modra <amodra@gmail.com>
Tue, 9 Feb 2010 12:31:01 +0000 (12:31 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 9 Feb 2010 12:31:01 +0000 (12:31 +0000)
(allocate_dynrelocs): Merge got entries here if not doing multi-toc.
(ppc64_elf_size_dynamic_sections): Similarly merge tlsld_got.
(ppc64_elf_layout_multitoc): Don't resize if we have already
merged got entries.

bfd/ChangeLog
bfd/elf64-ppc.c

index 597e4ca62723a03af9e8f571b9b4fd2deb6eaddb..b9e08bfc91495c6b542254267d89d282300447e6 100644 (file)
@@ -1,3 +1,11 @@
+2010-02-09  Alan Modra  <amodra@gmail.com>
+
+       * elf64-ppc.c (merge_got_entries): Move earlier in file.
+       (allocate_dynrelocs): Merge got entries here if not doing multi-toc.
+       (ppc64_elf_size_dynamic_sections): Similarly merge tlsld_got.
+       (ppc64_elf_layout_multitoc): Don't resize if we have already
+       merged got entries.
+
 2010-02-09  Michael Holzheu  <holzheu@de.ibm.com>
 
        * elf-bfd.h (elfcore_write_s390_timer, elfcore_write_s390_todcmp,
index 15ccf32ab3ecbd60ce5f2e9219f60e386f728f96..90d1b9f810cf01e1bc89eae3cb5d0f0bbecfeced 100644 (file)
@@ -8306,6 +8306,26 @@ allocate_got (struct elf_link_hash_entry *h,
     }
 }
 
+/* This function merges got entries in the same toc group.  */
+
+static void
+merge_got_entries (struct got_entry **pent)
+{
+  struct got_entry *ent, *ent2;
+
+  for (ent = *pent; ent != NULL; ent = ent->next)
+    if (!ent->is_indirect)
+      for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
+       if (!ent2->is_indirect
+           && ent2->addend == ent->addend
+           && ent2->tls_type == ent->tls_type
+           && elf_gp (ent2->owner) == elf_gp (ent->owner))
+         {
+           ent2->is_indirect = TRUE;
+           ent2->got.ent = ent;
+         }
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
@@ -8416,9 +8436,30 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
            gent->tls_type = TLS_TLS | TLS_TPREL;
        }
 
+  /* Remove any list entry that won't generate a word in the GOT before
+     we call merge_got_entries.  Otherwise we risk merging to empty
+     entries.  */
   pgent = &h->got.glist;
   while ((gent = *pgent) != NULL)
     if (gent->got.refcount > 0)
+      {
+       if ((gent->tls_type & TLS_LD) != 0
+           && !h->def_dynamic)
+         {
+           ppc64_tlsld_got (gent->owner)->got.refcount += 1;
+           *pgent = gent->next;
+         }
+       else
+         pgent = &gent->next;
+      }
+    else
+      *pgent = gent->next;
+
+  if (!htab->do_multi_toc)
+    merge_got_entries (&h->got.glist);
+
+  for (gent = h->got.glist; gent != NULL; gent = gent->next)
+    if (!gent->is_indirect)
       {
        /* Make sure this symbol is output as a dynamic symbol.
           Undefined weak syms won't yet be marked as dynamic,
@@ -8432,22 +8473,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              return FALSE;
          }
 
-       if ((gent->tls_type & TLS_LD) != 0
-           && !h->def_dynamic)
-         {
-           ppc64_tlsld_got (gent->owner)->got.refcount += 1;
-           *pgent = gent->next;
-           continue;
-         }
-
        if (!is_ppc64_elf (gent->owner))
          abort ();
 
        allocate_got (h, info, gent);
-       pgent = &gent->next;
       }
-    else
-      *pgent = gent->next;
 
   if (eh->dyn_relocs == NULL
       || (!htab->elf.dynamic_sections_created
@@ -8587,6 +8617,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   asection *s;
   bfd_boolean relocs;
   bfd *ibfd;
+  struct got_entry *first_tlsld;
 
   htab = ppc_hash_table (info);
   if (htab == NULL)
@@ -8722,25 +8753,39 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
 
+  first_tlsld = NULL;
   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
     {
+      struct got_entry *ent;
+
       if (!is_ppc64_elf (ibfd))
        continue;
 
-      if (ppc64_tlsld_got (ibfd)->got.refcount > 0)
+      ent = ppc64_tlsld_got (ibfd);
+      if (ent->got.refcount > 0)
        {
-         s = ppc64_elf_tdata (ibfd)->got;
-         ppc64_tlsld_got (ibfd)->got.offset = s->size;
-         ppc64_tlsld_got (ibfd)->owner = ibfd;
-         s->size += 16;
-         if (info->shared)
+         if (!htab->do_multi_toc && first_tlsld != NULL)
            {
-             asection *srel = ppc64_elf_tdata (ibfd)->relgot;
-             srel->size += sizeof (Elf64_External_Rela);
+             ent->is_indirect = TRUE;
+             ent->got.ent = first_tlsld;
+           }
+         else
+           {
+             if (first_tlsld == NULL)
+               first_tlsld = ent;
+             s = ppc64_elf_tdata (ibfd)->got;
+             ent->got.offset = s->size;
+             ent->owner = ibfd;
+             s->size += 16;
+             if (info->shared)
+               {
+                 asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+                 srel->size += sizeof (Elf64_External_Rela);
+               }
            }
        }
       else
-       ppc64_tlsld_got (ibfd)->got.offset = (bfd_vma) -1;
+       ent->got.offset = (bfd_vma) -1;
     }
 
   /* We now have determined the sizes of the various dynamic sections.
@@ -9855,26 +9900,6 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec)
   return TRUE;
 }
 
-/* This function merges got entries in the same toc group.  */
-
-static void
-merge_got_entries (struct got_entry **pent)
-{
-  struct got_entry *ent, *ent2;
-
-  for (ent = *pent; ent != NULL; ent = ent->next)
-    if (!ent->is_indirect)
-      for (ent2 = ent->next; ent2 != NULL; ent2 = ent2->next)
-       if (!ent2->is_indirect
-           && ent2->addend == ent->addend
-           && ent2->tls_type == ent->tls_type
-           && elf_gp (ent2->owner) == elf_gp (ent->owner))
-         {
-           ent2->is_indirect = TRUE;
-           ent2->got.ent = ent;
-         }
-}
-
 /* Called via elf_link_hash_traverse to merge GOT entries for global
    symbol H.  */
 
@@ -9925,6 +9950,9 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
 
   htab->multi_toc_needed = htab->toc_curr != elf_gp (info->output_bfd);
 
+  if (!htab->do_multi_toc)
+    return FALSE;
+
   /* Merge global sym got entries within a toc group.  */
   elf_link_hash_traverse (&htab->elf, merge_global_got, info);