bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Mon, 11 Feb 2013 18:15:47 +0000 (18:15 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Mon, 11 Feb 2013 18:15:47 +0000 (18:15 +0000)
* elfxx-mips.c (mips_got_entry): Remove tls_ldm_offset.
(mips_elf_link_hash_entry): Remove tls_ie_type, tls_gd_type,
tls_ie_got_offset and tls_gd_got_offset.
(mips_elf_link_hash_newfunc): Remove initialization.
(mips_elf_create_got_info): Likewise.
(mips_elf_count_local_got_entries, mips_elf_count_global_tls_entries)
(mips_tls_single_got_index): Delete.
(mips_elf_local_got_index): Always use the GOT entry to track
GOT indices.
(mips_elf_global_got_index): Likewise.
(mips_elf_create_local_got_entry): Assert that TLS entries have
already been allocated.
(mips_elf_record_global_got_symbol): Don't initialize
tls_ie_type or tls_gd_type.
(mips_elf_count_got_symbols): Only count reloc-only GOT entries here.
(mips_elf_initialize_tls_index): Allocate a GOT index for every TLS
entry.
(mips_elf_lay_out_got): Use mips_elf_count_got_entries to count
the GOT entries.
(_bfd_mips_elf_finish_dynamic_symbol): Assert that TLS GOT offsets
have been allocated.
(_bfd_mips_elf_copy_indirect_symbol): Remove handling of
tls_ie_type and tls_gd_type.

bfd/ChangeLog
bfd/elfxx-mips.c

index 9d7564a68cf9899875eb0b8f900e63d0d0854cf3..510301938a1cbf11cf90e054536123fe709e0512 100644 (file)
@@ -1,3 +1,29 @@
+2013-02-11  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * elfxx-mips.c (mips_got_entry): Remove tls_ldm_offset.
+       (mips_elf_link_hash_entry): Remove tls_ie_type, tls_gd_type,
+       tls_ie_got_offset and tls_gd_got_offset.
+       (mips_elf_link_hash_newfunc): Remove initialization.
+       (mips_elf_create_got_info): Likewise.
+       (mips_elf_count_local_got_entries, mips_elf_count_global_tls_entries)
+       (mips_tls_single_got_index): Delete.
+       (mips_elf_local_got_index): Always use the GOT entry to track
+       GOT indices.
+       (mips_elf_global_got_index): Likewise.
+       (mips_elf_create_local_got_entry): Assert that TLS entries have
+       already been allocated.
+       (mips_elf_record_global_got_symbol): Don't initialize
+       tls_ie_type or tls_gd_type.
+       (mips_elf_count_got_symbols): Only count reloc-only GOT entries here.
+       (mips_elf_initialize_tls_index): Allocate a GOT index for every TLS
+       entry.
+       (mips_elf_lay_out_got): Use mips_elf_count_got_entries to count
+       the GOT entries.
+       (_bfd_mips_elf_finish_dynamic_symbol): Assert that TLS GOT offsets
+       have been allocated.
+       (_bfd_mips_elf_copy_indirect_symbol): Remove handling of
+       tls_ie_type and tls_gd_type.
+
 2013-02-11  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * elfxx-mips.c (mips_elf_create_local_got_entry): Tidy.  Avoid
index 6e0d822f5865fac79832dd63ae9ba61071e1381c..102e57fa427f33088b41ada346845a5424c2ace1 100644 (file)
@@ -89,6 +89,12 @@ struct mips_got_entry
   /* The TLS type of this GOT entry: GOT_NORMAL, GOT_TLS_IE, GOT_TLS_GD
      or GOT_TLS_LDM.  An LDM GOT entry will be a local symbol entry with
      r_symndx == 0.  */
+#define GOT_NORMAL     0
+#define GOT_TLS_GD     1
+#define GOT_TLS_LDM    2
+#define GOT_TLS_IE     4
+#define GOT_TLS_TYPE   7
+#define GOT_TLS_DONE    0x80
   unsigned char tls_type;
 
   /* The offset from the beginning of the .got section to the entry
@@ -149,11 +155,6 @@ struct mips_got_info
   /* In multi-got links, a pointer to the next got (err, rather, most
      of the time, it points to the previous got).  */
   struct mips_got_info *next;
-  /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
-     for none, or MINUS_TWO for not yet assigned.  This is needed
-     because a single-GOT link may have multiple hash table entries
-     for the LDM.  It does not get initialized in multi-GOT mode.  */
-  bfd_vma tls_ldm_offset;
 };
 
 /* Structure passed when merging bfds' gots.  */
@@ -321,23 +322,6 @@ struct mips_elf_link_hash_entry
      being called returns a floating point value.  */
   asection *call_fp_stub;
 
-#define GOT_NORMAL     0
-#define GOT_TLS_GD     1
-#define GOT_TLS_LDM    2
-#define GOT_TLS_IE     4
-#define GOT_TLS_TYPE   7
-#define GOT_TLS_OFFSET_DONE    0x40
-#define GOT_TLS_DONE    0x80
-  unsigned char tls_ie_type;
-  unsigned char tls_gd_type;
-
-  /* These fields are only used in single-GOT mode; in multi-GOT mode there
-     is one mips_got_entry per GOT entry, so the offset is stored
-     there.  In single-GOT mode there may be many mips_got_entry
-     structures all referring to the same GOT slot.  */
-  bfd_vma tls_ie_got_offset;
-  bfd_vma tls_gd_got_offset;
-
   /* The highest GGA_* value that satisfies all references to this symbol.  */
   unsigned int global_got_area : 2;
 
@@ -1075,8 +1059,6 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       ret->fn_stub = NULL;
       ret->call_stub = NULL;
       ret->call_fp_stub = NULL;
-      ret->tls_ie_type = GOT_NORMAL;
-      ret->tls_gd_type = GOT_NORMAL;
       ret->global_got_area = GGA_NONE;
       ret->got_only_for_calls = TRUE;
       ret->readonly_reloc = FALSE;
@@ -2813,7 +2795,6 @@ mips_elf_create_got_info (bfd *abfd)
   if (g == NULL)
     return NULL;
 
-  g->tls_ldm_offset = MINUS_ONE;
   g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
                                    mips_elf_got_entry_eq, NULL);
   if (g->got_entries == NULL)
@@ -3013,63 +2994,6 @@ mips_elf_count_got_entries (void **entryp, void *data)
   return 1;
 }
 
-/* A htab_traverse callback.  If *SLOT describes a GOT entry for a local
-   symbol, count the number of GOT entries and TLS relocations that it
-   requires.  DATA points to a mips_elf_traverse_got_arg structure.  */
-
-static int
-mips_elf_count_local_got_entries (void **entryp, void *data)
-{
-  struct mips_got_entry *entry;
-  struct mips_elf_traverse_got_arg *arg;
-
-  entry = (struct mips_got_entry *) *entryp;
-  arg = (struct mips_elf_traverse_got_arg *) data;
-  if (entry->abfd != NULL && entry->symndx != -1)
-    {
-      if ((entry->tls_type & GOT_TLS_TYPE) == GOT_TLS_LDM)
-       {
-         if (arg->g->tls_ldm_offset == MINUS_TWO)
-           return 1;
-         arg->g->tls_ldm_offset = MINUS_TWO;
-       }
-      mips_elf_count_got_entry (arg->info, arg->g, entry);
-    }
-
-  return 1;
-}
-
-/* Count the number of TLS GOT entries and relocationss required for the
-   global (or forced-local) symbol in ARG1.  */
-
-static int
-mips_elf_count_global_tls_entries (void *entry, void *data)
-{
-  struct mips_elf_link_hash_entry *hm;
-  struct mips_elf_traverse_got_arg *arg;
-
-  hm = (struct mips_elf_link_hash_entry *) entry;
-  if (hm->root.root.type == bfd_link_hash_indirect
-      || hm->root.root.type == bfd_link_hash_warning)
-    return 1;
-
-  arg = (struct mips_elf_traverse_got_arg *) data;
-  if (hm->tls_gd_type)
-    {
-      arg->g->tls_gotno += 2;
-      arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_gd_type,
-                                            &hm->root);
-    }
-  if (hm->tls_ie_type)
-    {
-      arg->g->tls_gotno += 1;
-      arg->g->relocs += mips_tls_got_relocs (arg->info, hm->tls_ie_type,
-                                            &hm->root);
-    }
-
-  return 1;
-}
-
 /* Output a simple dynamic relocation into SRELOC.  */
 
 static void
@@ -3240,22 +3164,6 @@ mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
   return got_index;
 }
 
-/* Return the GOT index to use for a relocation of type R_TYPE against H
-   in ABFD.  */
-
-static bfd_vma
-mips_tls_single_got_index (bfd *abfd, int r_type, struct bfd_link_info *info,
-                          struct mips_elf_link_hash_entry *h, bfd_vma symbol)
-{
-  if (tls_gottprel_reloc_p (r_type))
-    return mips_tls_got_index (abfd, h->tls_ie_got_offset, &h->tls_ie_type,
-                              info, h, symbol);
-  if (tls_gd_reloc_p (r_type))
-    return mips_tls_got_index (abfd, h->tls_gd_got_offset, &h->tls_gd_type,
-                              info, h, symbol);
-  abort ();
-}
-
 /* Return the offset from _GLOBAL_OFFSET_TABLE_ of the .got.plt entry
    for global symbol H.  .got.plt comes before the GOT, so the offset
    will be negative.  */
@@ -3314,15 +3222,8 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
     return MINUS_ONE;
 
   if (entry->tls_type)
-    {
-      if (entry->symndx == -1 && htab->got_info->next == NULL)
-       /* A type (3) entry in the single-GOT case.  We use the symbol's
-          hash table entry to track the index.  */
-       return mips_tls_single_got_index (abfd, r_type, info, h, value);
-      else
-       return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
-                                  info, h, value);
-    }
+    return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type,
+                              info, h, value);
   else
     return entry->gotidx;
 }
@@ -3366,54 +3267,31 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
                           struct elf_link_hash_entry *h, int r_type)
 {
   struct mips_elf_link_hash_table *htab;
-  bfd_vma got_index;
-  struct mips_got_info *g, *gg;
+  struct mips_got_info *g;
+  struct mips_got_entry lookup, *entry;
+  bfd_vma gotidx;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
 
-  gg = g = htab->got_info;
-  if (g->next && ibfd)
-    {
-      struct mips_got_entry e, *p;
-
-      BFD_ASSERT (h->dynindx >= 0);
-
-      g = mips_elf_bfd_got (ibfd, FALSE);
-      BFD_ASSERT (g);
-      if (g->next != gg || TLS_RELOC_P (r_type))
-       {
-         e.abfd = ibfd;
-         e.symndx = -1;
-         e.d.h = (struct mips_elf_link_hash_entry *)h;
-         e.tls_type = mips_elf_reloc_tls_type (r_type);
+  g = mips_elf_bfd_got (ibfd, FALSE);
+  BFD_ASSERT (g);
 
-         p = htab_find (g->got_entries, &e);
+  lookup.tls_type = mips_elf_reloc_tls_type (r_type);
+  if (!lookup.tls_type && g == mips_elf_bfd_got (obfd, FALSE))
+    return mips_elf_primary_global_got_index (obfd, info, h);
 
-         BFD_ASSERT (p && p->gotidx > 0);
+  lookup.abfd = ibfd;
+  lookup.symndx = -1;
+  lookup.d.h = (struct mips_elf_link_hash_entry *) h;
+  entry = htab_find (g->got_entries, &lookup);
+  BFD_ASSERT (entry);
 
-         if (p->tls_type)
-           {
-             bfd_vma value = MINUS_ONE;
-             if ((h->root.type == bfd_link_hash_defined
-                  || h->root.type == bfd_link_hash_defweak)
-                 && h->root.u.def.section->output_section)
-               value = (h->root.u.def.value
-                        + h->root.u.def.section->output_offset
-                        + h->root.u.def.section->output_section->vma);
-
-             return mips_tls_got_index (obfd, p->gotidx, &p->tls_type,
-                                        info, e.d.h, value);
-           }
-         else
-           return p->gotidx;
-       }
-    }
+  gotidx = entry->gotidx;
+  BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
 
-  if (TLS_RELOC_P (r_type))
+  if (lookup.tls_type)
     {
-      struct mips_elf_link_hash_entry *hm
-       = (struct mips_elf_link_hash_entry *) h;
       bfd_vma value = MINUS_ONE;
 
       if ((h->root.type == bfd_link_hash_defined
@@ -3423,13 +3301,10 @@ mips_elf_global_got_index (bfd *obfd, struct bfd_link_info *info, bfd *ibfd,
                 + h->root.u.def.section->output_offset
                 + h->root.u.def.section->output_section->vma);
 
-      got_index = mips_tls_single_got_index (obfd, r_type, info, hm, value);
+      return mips_tls_got_index (obfd, gotidx, &entry->tls_type,
+                                info, lookup.d.h, value);
     }
-  else
-    got_index = mips_elf_primary_global_got_index (obfd, info, h);
-  BFD_ASSERT (got_index < htab->sgot->size);
-
-  return got_index;
+  return gotidx;
 }
 
 /* Find a GOT page entry that points to within 32KB of VALUE.  These
@@ -3525,6 +3400,7 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
   void **loc;
   struct mips_got_info *g;
   struct mips_elf_link_hash_table *htab;
+  bfd_vma gotidx;
 
   htab = mips_elf_hash_table (info);
   BFD_ASSERT (htab != NULL);
@@ -3563,6 +3439,9 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
       entry = (struct mips_got_entry *) htab_find (g->got_entries, &lookup);
       BFD_ASSERT (entry);
 
+      gotidx = entry->gotidx;
+      BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+
       return entry;
     }
 
@@ -3811,10 +3690,6 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
   tls_type = mips_elf_reloc_tls_type (r_type);
   if (tls_type == GOT_NORMAL && hmips->global_got_area > GGA_NORMAL)
     hmips->global_got_area = GGA_NORMAL;
-  else if (tls_type == GOT_TLS_IE && hmips->tls_ie_type == 0)
-    hmips->tls_ie_type = tls_type;
-  else if (tls_type == GOT_TLS_GD && hmips->tls_gd_type == 0)
-    hmips->tls_gd_type = tls_type;
 
   entry.abfd = abfd;
   entry.symndx = -1;
@@ -4108,9 +3983,11 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g)
   return TRUE;
 }
 
-/* A mips_elf_link_hash_traverse callback for which DATA points
-   to the link_info structure.  Count the number of type (3) entries
-   in the master GOT.  */
+/* A mips_elf_link_hash_traverse callback for which DATA points to the
+   link_info structure.  Decide whether the hash entry needs an entry in
+   the global part of the primary GOT, setting global_got_area accordingly.
+   Count the number of global symbols that are in the primary GOT only
+   because they have relocations against them (reloc_only_gotno).  */
 
 static int
 mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
@@ -4137,14 +4014,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
          || (h->got_only_for_calls
              ? SYMBOL_CALLS_LOCAL (info, &h->root)
              : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
-       {
-         /* The symbol belongs in the local GOT.  We no longer need this
-            entry if it was only used for relocations; those relocations
-            will be against the null or section symbol instead of H.  */
-         if (h->global_got_area != GGA_RELOC_ONLY)
-           g->local_gotno++;
-         h->global_got_area = GGA_NONE;
-       }
+       /* The symbol belongs in the local GOT.  We no longer need this
+          entry if it was only used for relocations; those relocations
+          will be against the null or section symbol instead of H.  */
+       h->global_got_area = GGA_NONE;
       else if (htab->is_vxworks
               && h->got_only_for_calls
               && h->root.plt.offset != MINUS_ONE)
@@ -4152,11 +4025,10 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
           they don't need entries in the regular GOT.  .got.plt entries
           will be allocated by _bfd_mips_elf_adjust_dynamic_symbol.  */
        h->global_got_area = GGA_NONE;
-      else
+      else if (h->global_got_area == GGA_RELOC_ONLY)
        {
+         g->reloc_only_gotno++;
          g->global_gotno++;
-         if (h->global_got_area == GGA_RELOC_ONLY)
-           g->reloc_only_gotno++;
        }
     }
   return 1;
@@ -4367,8 +4239,6 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
 {
   struct mips_got_entry *entry;
   struct mips_elf_traverse_got_arg *arg;
-  struct mips_got_info *g;
-  bfd_vma next_index;
   unsigned char tls_type;
 
   /* We're only interested in TLS symbols.  */
@@ -4378,52 +4248,14 @@ mips_elf_initialize_tls_index (void **entryp, void *data)
     return 1;
 
   arg = (struct mips_elf_traverse_got_arg *) data;
-  g = arg->g;
-  next_index = arg->value * g->tls_assigned_gotno;
-
-  if (entry->symndx == -1 && g->next == NULL)
-    {
-      /* A type (3) got entry in the single-GOT case.  We use the symbol's
-        hash table entry to track its index.  */
-      if (tls_type == GOT_TLS_IE)
-       {
-         if (entry->d.h->tls_ie_type & GOT_TLS_OFFSET_DONE)
-           return 1;
-         entry->d.h->tls_ie_type |= GOT_TLS_OFFSET_DONE;
-         entry->d.h->tls_ie_got_offset = next_index;
-       }
-      else
-       {
-         BFD_ASSERT (tls_type == GOT_TLS_GD);
-         if (entry->d.h->tls_gd_type & GOT_TLS_OFFSET_DONE)
-           return 1;
-         entry->d.h->tls_gd_type |= GOT_TLS_OFFSET_DONE;
-         entry->d.h->tls_gd_got_offset = next_index;
-       }
-    }
-  else
+  if (!mips_elf_set_gotidx (entryp, arg->value * arg->g->tls_assigned_gotno))
     {
-      if (tls_type == GOT_TLS_LDM)
-       {
-         /* There are separate mips_got_entry objects for each input bfd
-            that requires an LDM entry.  Make sure that all LDM entries in
-            a GOT resolve to the same index.  */
-         if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
-           {
-             entry->gotidx = g->tls_ldm_offset;
-             return 1;
-           }
-         g->tls_ldm_offset = next_index;
-       }
-      if (!mips_elf_set_gotidx (entryp, next_index))
-       {
-         arg->g = NULL;
-         return 0;
-       }
+      arg->g = NULL;
+      return 0;
     }
 
   /* Account for the entries we've just allocated.  */
-  g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
+  arg->g->tls_assigned_gotno += mips_tls_got_entries (tls_type);
   return 1;
 }
 
@@ -8797,7 +8629,8 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
   if (!mips_elf_resolve_final_got_entries (g))
     return FALSE;
 
-  /* Count the number of GOT symbols.  */
+  /* Decide which symbols need to go in the global part of the GOT and
+     count the number of reloc-only GOT symbols.  */
   mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
 
   /* Calculate the total loadable size of the output.  That
@@ -8835,17 +8668,10 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
 
   g->local_gotno += page_gotno;
 
-  /* Count the number of local GOT entries and TLS relocs.  */
+  /* Count the number of GOT entries and TLS relocs.  */
   tga.info = info;
   tga.g = g;
-  htab_traverse (g->got_entries, mips_elf_count_local_got_entries, &tga);
-
-  /* We need to calculate tls_gotno for global symbols at this point
-     instead of building it up earlier, to avoid doublecounting
-     entries for one global symbol from multiple input files.  */
-  elf_link_hash_traverse (elf_hash_table (info),
-                         mips_elf_count_global_tls_entries,
-                         &tga);
+  htab_traverse (g->got_entries, mips_elf_count_got_entries, &tga);
 
   s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
   s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
@@ -10037,6 +9863,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
                                                           &e)))
            {
              offset = p->gotidx;
+             BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
              if (info->shared
                  || (elf_hash_table (info)->dynamic_sections_created
                      && p->d.h != NULL
@@ -11530,11 +11357,6 @@ _bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info,
     indmips->global_got_area = GGA_NONE;
   if (indmips->has_nonpic_branches)
     dirmips->has_nonpic_branches = TRUE;
-
-  if (dirmips->tls_ie_type == 0)
-    dirmips->tls_ie_type = indmips->tls_ie_type;
-  if (dirmips->tls_gd_type == 0)
-    dirmips->tls_gd_type = indmips->tls_gd_type;
 }
 \f
 #define PDR_SIZE 32