This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 1/5] Lay out MIPS GOTs later in the link process


Richard Sandiford <rdsandiford@googlemail.com> writes:
> This patch is the first of a series aimed at improving the GOT allocation.
> It addresses what I see as the most fundamental flaw of the current code:
> that it allocates the GOT too early, before we even know how many dynamic
> symbols there will be.
>
> Specifically, the current code allocates the GOT in
> elf_backend_always_size_sections rather than
> elf_backend_size_dynamic_sections.  This has two main drawbacks:
>
>   - We have an 80+ line function, _bfd_mips_elf_hide_symbol,
>     whose sole purpose is to try to update the GOT allocation
>     in response to symbol hiding between always_size_sections
>     and size_dynamic_sections.  As the comment says, it isn't
>     always possible to reclaim space:
>
>       /* If this was a global symbol forced into the primary GOT, we
> 	 no longer need an entry for it.  We can't release the entry
> 	 at this point, but we must at least stop counting it as one
> 	 of the symbols that required a forced got entry.  */
>
>     This then leads to further fixups in size_dynamic_sections itself:
>
>       /* _bfd_mips_elf_always_size_sections() has already done
> 	 most of the work, but some symbols may have been mapped
> 	 to versions that we must now resolve in the got_entries
> 	 hash tables.  */
>
>   - We don't know in always_size_sections how many stubs we need --
>     that's determined by _bfd_mips_elf_adjust_dynamic_symbol --
>     so we have to use a very conservative estimate when computing
>     loadable_size:
>
>       /* In the worst case, we'll get one stub per dynamic symbol, plus
> 	 one to account for the dummy entry at the end required by IRIX
> 	 rld.  */
>       loadable_size += htab->function_stub_size * (i + 1);
>
>     This means that we can have more page entries than we really need.
>
> Before the patch, the code has the following steps:
>
>   always_size_sections
>   --------------------
>
>   [A] Compute the amount of memory that can be addressed by GOT page entries.
>   [B] Sort the symbol table, dividing it into non-GOT-mapped and
>       GOT-mapped areas.
>   [C] Pick a stub size.
>   [D] Count the number of page and TLS GOT entries.
>   [E] Replace GOT entries for indirect and warning symbols
>       with GOT entries for the target symbol.
>
>   Either call mips_elf_multi_got or:
>     [F1] Assign indices for TLS GOT entries.
>
>   mips_elf_multi_got (called from always_size_sections)
>   ------------------
>
>   [G] Create a separate GOT for each input BFD.
>   [H] Merge per-BFD GOTs together where possible, choosing one as
>       the primary GOT.
>   [I] Mark symbols that need primary GOT entries and reorder the
>       symbol table so that those symbols come before all others
>       in the "master" (i.e. ABI-defined) GOT.
>   [J] Prevent symbols referenced by secondary GOTs from having
>       lazy-binding stubs.
>   [F2] Assign indices for TLS GOT entries.
>
>   adjust_dynamic_symbol
>   ---------------------
>   [K] Allocate .MIPS.stub entries to each function that needs a stub.
>
>   mips_elf_record_global_got_symbol
>   ---------------------------------
>   [L1] Count the number of forced-local symbols with global GOT entries.
>
>   hide_symbol
>   -----------
>   [L2] Adjust local/global-GOT counts for symbols that have already
>        been allocated a GOT entry.
>
>   size_dymamic_sections
>   ---------------------
>   [M] If we have multiple GOTs, reapply [E].
>   [N] If we have multiple GOTs, assign each primary and secondary GOT
>       a position in the master GOT.
>   [O] Allocate dynamic relocations needed by the GOT.
>
> The corresponding steps after the patch are:
>
>   adjust_dynamic_symbol
>   ---------------------
>   [k1] Count the number of stubs needed.
>
>   mips_elf_estimate_stub_size (called from size_dynamic_sections)
>   ---------------------------
>   [c] Pick a stub size and estimate the size of .MIPS.stubs.
>
>   mips_lay_out_got (called from size_dynamic_sections)
>   ----------------
>   [e] Replace GOT entries for indirect and warning symbols
>       with GOT entries for the target symbol.
>   [l] Count the number forced-local symbols.
>   [b] Sort the symbol table, dividing it into non-GOT-mapped and
>       GOT-mapped areas.
>   [a] Compute the amount of memory that can be addressed by GOT page entries.
>   [d] Count the number of page and TLS GOT entries.
>
>   Either call mips_elf_multi_got or:
>     [f1] Assign indices for TLS GOT entries.
>     [o1] Allocate dynamic relocations needed by the GOT.
>
>   mips_elf_multi_got (called from mips_lay_out_got)
>   ------------------
>   [g] Create a separate GOT for each input BFD.
>   [h] Merge per-BFD GOTs together where possible, choosing one as
>       the primary GOT.
>   [i] Mark symbols that need primary GOT entries and reorder the
>       symbol table so that those symbols come before all others
>       in the "master" (i.e. ABI-defined) GOT.
>   [j] Prevent symbols referenced by secondary GOTs from having
>       lazy-binding stubs.
>   [f2] Assign indices for TLS GOT entries.
>   [n] Assign each primary and secondary GOT a position in the master GOT.
>   [o2] Allocate dynamic relocations needed by the GOT.
>
>   mips_elf_lay_out_lazy_stubs (called from size_dynamic_sections)
>   ---------------------------
>   [k2] Allocate offsets to each .MIPS.stub entry.
>
>   size_dynamic_sections
>   ---------------------
>   Call mips_elf_estimate_stub_size, mips_elf_lay_out_got and
>   mips_elf_lay_out_lazy_stubs.
>
> In other words, everything is now handled by adjust_dynamic_symbol and
> size_dynamic_sections, although some of the work is done by subroutines.
> There is no need for special handling in always_size_sections,
> mips_elf_record_global_got_symbol or hide_symbol.
>
> Notes:
>
>   - [J] happened before [K], so setting no_fn_stub to TRUE was
>     enough to prevent a stub being used.  [k1] now happens before [j],
>     so [k1] conservatively assumes that we need a stub, then [j]
>     removes it if necessary.  The patch uses a new "needs_lazy_stub"
>     field to track whether we're creating a stub.
>
>     This arrangement means that, if we need multiple GOTs, we still
>     overestimate the size of .MIPS.stubs when deciding how many page
>     entries are needed.  The new estimate is tighter than the old one
>     though.  Note that the final size of .MIPS.stubs is computed by
>     [k2] and is accurate.
>
>     mips_elf_output_extsym used no_fn_stub to detect whether a stub
>     had been created.  The patch uses needs_lazy_stub instead.
>
>   - There was a comment querying whether [M] is really needed:
>
>       /* NOTE 2005-02-03: How can this call, or the next, ever
> 	 find any indirect entries to resolve?  They were all
> 	 resolved in mips_elf_multi_got.  */
>
>     It certainly isn't after the patch.  The comment refers to step [E]
>     (actually in always_size_sections) and [e], like [M], now happens
>     in size_dynamic_sections.
>
>   - [E] was needlessly quadratic.  mips_elf_resolve_final_got_entries
>     applied mips_elf_resolve_final_got_entry to each GOT entry,
>     but stopped as soon as it found an entry that needed adjusting.
>     (It isn't safe to continue a traversal after modifying the
>     hashtable.)  mips_elf_resolve_final_got_entries would then
>     start again from the beginning, restarting again if it found
>     another entry that needed adjusting.
>
>     [e] instead does one walk to see whether any change needs to
>     be made.  If so, it uses a second traversal to creates a new GOT
>     with the new information.
>
>   - Symbols had a MIPS-specific "forced_local" field as well as the
>     generic ELF "root.forced_local" field.  Only GOT code used the
>     MIPS-specific version.
>
>     I'm not sure if the old code really needed a separate field,
>     but the new code doesn't.  I think it's confusing to have both.
>
>   - The main size_dynamic_sections loop allocated GOT dynamic
>     relocations ([O]), so the loop had to treat .rel.dyn specially,
>     postponing the size calculation until after the loop.  Now that
>     mips_lay_out_got does [o] as part of the main GOT lay-out code,
>     this special treatment is no longer necessary.
>
> Tested on mips64-linux-gnu and mips64el-linux-gnu.  OK to install?

I've updated this for current mainline, taking account of:

    http://sources.redhat.com/ml/binutils/2008-07/msg00350.html

Patches 2-4 are unaffected.  I'll post an updated patch 5 in a sec.

Richard


bfd/
	* elf32-mips.c (elf_backend_hide_symbol): Delete.
	* elfn32-mips.c (elf_backend_hide_symbol): Likewise.
	* elf64-mips.c (elf_backend_hide_symbol): Likewise.
	* elfxx-mips.h (elf_backend_hide_symbol): Likewise.
	* elfxx-mips.c (mips_elf_link_hash_entry): Remove "forced_local"
	and add "needs_lazy_stub".
	(mips_elf_link_hash_newfunc): Update accordingly.
	(mips_elf_link_hash_table): Remove "computed_got_sizes" and
	add "lazy_stub_count".
	(_bfd_mips_elf_link_hash_table_create): Update accordingly.
	(mips_elf_output_extsym): Use hd->needs_lazy_stub to detect
	cases where a lazy stub is being used.
	(mips_elf_sort_hash_table_f): Use h->root.forced_local instead
	of h->forced_local.
	(mips_elf_record_global_got_symbol): Use _bfd_elf_link_hash_hide_symbol
	instead of _bfd_mips_elf_hide_symbol.  Do not increment local_gotno
	here.
	(mips_elf_allocate_dynamic_relocations): Move before new first use.
	(mips_elf_check_recreate_got, mips_elf_recreate_got): New functions.
	(mips_elf_resolve_final_got_entries): Move earlier in file.  Make at
	most two passes over the hash table.  Use mips_elf_check_recreate_got
	to see if there are any indirect or warning entries and
	mips_elf_recreate_got to create a new GOT without them.
	Return a boolean success value.
	(mips_elf_count_forced_local_got_entries): New function.
	(mips_elf_make_got_per_bfd): Check h->root.forced_local instead of
	h->forced_local.
	(mips_elf_set_global_got_offset): Likewise.
	(mips_elf_set_no_stub): Replace with...
	(mips_elf_forbid_lazy_stubs): ...this new function.
	(mips_elf_resolve_final_got_entry): Delete.
	(mips_elf_multi_got): Fix formatting.  Use mips_elf_forbid_lazy_stubs
	instead of mips_elf_set_no_stub.  Move the code that sets
	global offsets and allocates dynamic relocations from the main
	_bfd_mips_elf_size_dynamic_sections loop to here.
	(_bfd_mips_elf_adjust_dynamic_symbol): Do not allocate room in
	.MIPS.stubs here; just set hmips->needs_lazy_stub and increment
	htab->lazy_stub_count.
	(_bfd_mips_elf_always_size_sections): Move the stub-estimation
	code to mips_elf_estimate_stub_size and the GOT-sizing code to
	mips_elf_lay_out_got.  Do not call these functions here.
	(mips_elf_estimate_stub_size): New function, split
	out from _bfd_mips_elf_always_size_sections.  Call
	mips_elf_resolve_final_got_entries earlier.  Count the number
	of forced-local entries.  Do not add stub sizes to loadable_size;
	after this patch, the stub sizes are already included in the main
	estimate.  Allocate dynamic relocations here rather than in the
	main _bfd_mips_elf_size_dynamic_sections loop.
	(mips_elf_estimate_stub_size): New function, split out from
	_bfd_mips_elf_always_size_sections.
	(mips_elf_allocate_lazy_stub): New function.
	(mips_elf_lay_out_lazy_stubs): Likewise.
	(_bfd_mips_elf_size_dynamic_sections): Call mips_elf_estimate_stub_size,
	mips_elf_lay_out_got and mips_elf_lay_out_lazy_stubs.  Do not handle
	the allocation of sreldyn specially.
	(_bfd_mips_elf_hide_symbol): Delete.

ld/testsuite/
	* ld-mips-elf/tlsdyn-o32-2.got, ld-mips-elf/tlsdyn-o32-3.got,
	ld-mips-elf/tlsdyn-o32-2.d, ld-mips-elf/tlsdyn-o32-3.d: Change the
	GOT layout as follows:

	         BEFORE                  AFTER
	   +0x08 %call16(__tls_get_addr) %call16(__tls_get_addr)
	   +0x0c %tlsldm(tlsbin_ld)      %gottprel(tlsvar_ie)
	   +0x10   "  "                  %tlsgd(tlsvar_gd)
	   +0x14 %tlsgd(tlsvar_gd)          "  "
	   +0x18   "  "                  %tlsgd(tlsbin_gd)
	   +0x1c %gottprel(tlsvar_ie)       "  "
	   +0x20 %tlsgd(tlsbin_gd)       %tlsldm(tlsbin_ld)
	   +0x24   "  "                     "  "       
	   +0x28 %gottprel(tlsbin_ie)    %gottprel(tlsbin_ie)

Index: bfd/elf32-mips.c
===================================================================
--- bfd/elf32-mips.c	2008-08-06 20:43:36.000000000 +0100
+++ bfd/elf32-mips.c	2008-08-06 21:00:51.000000000 +0100
@@ -1606,7 +1606,6 @@ #define elf_backend_gc_mark_hook	_bfd_mi
 #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
 #define elf_backend_copy_indirect_symbol \
 					_bfd_mips_elf_copy_indirect_symbol
-#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
 #define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
 #define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
 #define elf_backend_ecoff_debug_swap	&mips_elf32_ecoff_debug_swap
Index: bfd/elfn32-mips.c
===================================================================
--- bfd/elfn32-mips.c	2008-08-06 20:43:36.000000000 +0100
+++ bfd/elfn32-mips.c	2008-08-06 21:00:51.000000000 +0100
@@ -2433,7 +2433,6 @@ #define elf_backend_gc_mark_hook	_bfd_mi
 #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
 #define elf_backend_copy_indirect_symbol \
 					_bfd_mips_elf_copy_indirect_symbol
-#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
 #define elf_backend_grok_prstatus	elf32_mips_grok_prstatus
 #define elf_backend_grok_psinfo		elf32_mips_grok_psinfo
 #define elf_backend_ecoff_debug_swap	&mips_elf32_ecoff_debug_swap
Index: bfd/elf64-mips.c
===================================================================
--- bfd/elf64-mips.c	2008-08-06 20:43:36.000000000 +0100
+++ bfd/elf64-mips.c	2008-08-06 21:00:51.000000000 +0100
@@ -3179,7 +3179,6 @@ #define elf_backend_gc_mark_hook	_bfd_mi
 #define elf_backend_gc_sweep_hook	_bfd_mips_elf_gc_sweep_hook
 #define elf_backend_copy_indirect_symbol \
 					_bfd_mips_elf_copy_indirect_symbol
-#define elf_backend_hide_symbol		_bfd_mips_elf_hide_symbol
 #define elf_backend_ignore_discarded_relocs \
 					_bfd_mips_elf_ignore_discarded_relocs
 #define elf_backend_mips_irix_compat	elf64_mips_irix_compat
Index: bfd/elfxx-mips.h
===================================================================
--- bfd/elfxx-mips.h	2008-08-06 20:18:41.000000000 +0100
+++ bfd/elfxx-mips.h	2008-08-06 21:00:51.000000000 +0100
@@ -81,8 +81,6 @@
 extern void _bfd_mips_elf_copy_indirect_symbol
   (struct bfd_link_info *, struct elf_link_hash_entry *,
    struct elf_link_hash_entry *);
-extern void _bfd_mips_elf_hide_symbol
-  (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean);
 extern bfd_boolean _bfd_mips_elf_ignore_discarded_relocs
   (asection *);
 extern bfd_boolean _bfd_mips_elf_find_nearest_line
Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c	2008-08-06 20:57:18.000000000 +0100
+++ bfd/elfxx-mips.c	2008-08-06 21:00:51.000000000 +0100
@@ -317,15 +317,15 @@ #define GOT_TLS_DONE    0x80
      in any relocs other than a 16 bit call.  */
   unsigned int need_fn_stub : 1;
 
-  /* Are we forced local?  This will only be set if we have converted
-     the initial global GOT entry to a local GOT entry.  */
-  unsigned int forced_local : 1;
-
   /* Are we referenced by some kind of relocation?  */
   unsigned int is_relocation_target : 1;
 
   /* Are we referenced by branch relocations?  */
   unsigned int is_branch_target : 1;
+
+  /* Does this symbol need a traditional MIPS lazy-binding stub
+     (as opposed to a PLT entry)?  */
+  unsigned int needs_lazy_stub : 1;
 };
 
 /* MIPS ELF linker hash table.  */
@@ -349,8 +349,6 @@ struct mips_elf_link_hash_table
   bfd_vma rld_value;
   /* This is set if we see any mips16 stub sections.  */
   bfd_boolean mips16_stubs_seen;
-  /* True if we've computed the size of the GOT.  */
-  bfd_boolean computed_got_sizes;
   /* True if we're generating code for VxWorks.  */
   bfd_boolean is_vxworks;
   /* True if we already reported the small-data section overflow.  */
@@ -371,6 +369,8 @@ struct mips_elf_link_hash_table
   bfd_vma plt_header_size;
   /* The size of a PLT entry in bytes (VxWorks only).  */
   bfd_vma plt_entry_size;
+  /* The number of functions that need a lazy-binding stub.  */
+  bfd_vma lazy_stub_count;
   /* The size of a function stub entry in bytes.  */
   bfd_vma function_stub_size;
 };
@@ -871,9 +871,9 @@ mips_elf_link_hash_newfunc (struct bfd_h
       ret->readonly_reloc = FALSE;
       ret->no_fn_stub = FALSE;
       ret->need_fn_stub = FALSE;
-      ret->forced_local = FALSE;
       ret->is_relocation_target = FALSE;
       ret->is_branch_target = FALSE;
+      ret->needs_lazy_stub = FALSE;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -2066,18 +2066,14 @@ mips_elf_output_extsym (struct mips_elf_
       else
 	h->esym.asym.value = 0;
     }
-  else if (h->root.needs_plt)
+  else
     {
       struct mips_elf_link_hash_entry *hd = h;
-      bfd_boolean no_fn_stub = h->no_fn_stub;
 
       while (hd->root.root.type == bfd_link_hash_indirect)
-	{
-	  hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
-	  no_fn_stub = no_fn_stub || hd->no_fn_stub;
-	}
+	hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
 
-      if (!no_fn_stub)
+      if (hd->needs_lazy_stub)
 	{
 	  /* Set type and value for a symbol with a function stub.  */
 	  h->esym.asym.st = stProc;
@@ -2965,7 +2961,7 @@ mips_elf_sort_hash_table_f (struct mips_
 	hsd->low = (struct elf_link_hash_entry *) h;
       h->root.dynindx = hsd->max_unref_got_dynindx++;
     }
-  else if (h->root.got.offset != 1 || h->forced_local)
+  else if (h->root.got.offset != 1 || h->root.forced_local)
     h->root.dynindx = hsd->max_non_got_dynindx++;
   else
     {
@@ -3001,7 +2997,7 @@ mips_elf_record_global_got_symbol (struc
 	{
 	case STV_INTERNAL:
 	case STV_HIDDEN:
-	  _bfd_mips_elf_hide_symbol (info, h, TRUE);
+	  _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
 	  break;
 	}
       if (!bfd_elf_link_record_dynamic_symbol (info, h))
@@ -3042,14 +3038,10 @@ mips_elf_record_global_got_symbol (struc
     return TRUE;
 
   if (tls_flag == 0)
-    {
-      /* By setting this to a value other than -1, we are indicating that
-	 there needs to be a GOT entry for H.  Avoid using zero, as the
-	 generic ELF copy_indirect_symbol tests for <= 0.  */
-      h->got.offset = 1;
-      if (h->forced_local)
-	g->local_gotno++;
-    }
+    /* By setting this to a value other than -1, we are indicating that
+       there needs to be a GOT entry for H.  Avoid using zero, as the
+       generic ELF copy_indirect_symbol tests for <= 0.  */
+    h->got.offset = 1;
 
   return TRUE;
 }
@@ -3229,6 +3221,148 @@ mips_elf_record_got_page_entry (struct b
 
   return TRUE;
 }
+
+/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
+
+static void
+mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
+				       unsigned int n)
+{
+  asection *s;
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  s = mips_elf_rel_dyn_section (info, FALSE);
+  BFD_ASSERT (s != NULL);
+
+  if (htab->is_vxworks)
+    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
+  else
+    {
+      if (s->size == 0)
+	{
+	  /* Make room for a null element.  */
+	  s->size += MIPS_ELF_REL_SIZE (abfd);
+	  ++s->reloc_count;
+	}
+      s->size += n * MIPS_ELF_REL_SIZE (abfd);
+    }
+}
+
+/* A htab_traverse callback for GOT entries.  Set boolean *DATA to true
+   if the GOT entry is for an indirect or warning symbol.  */
+
+static int
+mips_elf_check_recreate_got (void **entryp, void *data)
+{
+  struct mips_got_entry *entry;
+  bfd_boolean *must_recreate;
+
+  entry = (struct mips_got_entry *) *entryp;
+  must_recreate = (bfd_boolean *) data;
+  if (entry->abfd != NULL && entry->symndx == -1)
+    {
+      struct mips_elf_link_hash_entry *h;
+
+      h = entry->d.h;
+      if (h->root.root.type == bfd_link_hash_indirect
+	  || h->root.root.type == bfd_link_hash_warning)
+	{
+	  *must_recreate = TRUE;
+	  return 0;
+	}
+    }
+  return 1;
+}
+
+/* A htab_traverse callback for GOT entries.  Add all entries to
+   hash table *DATA, converting entries for indirect and warning
+   symbols into entries for the target symbol.  Set *DATA to null
+   on error.  */
+
+static int
+mips_elf_recreate_got (void **entryp, void *data)
+{
+  htab_t *new_got;
+  struct mips_got_entry *entry;
+  void **slot;
+
+  new_got = (htab_t *) data;
+  entry = (struct mips_got_entry *) *entryp;
+  if (entry->abfd != NULL && entry->symndx == -1)
+    {
+      struct mips_elf_link_hash_entry *h;
+
+      h = entry->d.h;
+      while (h->root.root.type == bfd_link_hash_indirect
+	     || h->root.root.type == bfd_link_hash_warning)
+	h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
+      entry->d.h = h;
+    }
+  slot = htab_find_slot (*new_got, entry, INSERT);
+  if (slot == NULL)
+    {
+      *new_got = NULL;
+      return 0;
+    }
+  if (*slot == NULL)
+    *slot = entry;
+  else
+    free (entry);
+  return 1;
+}
+
+/* If any entries in G->got_entries are for indirect or warning symbols,
+   replace them with entries for the target symbol.  */
+
+static bfd_boolean
+mips_elf_resolve_final_got_entries (struct mips_got_info *g)
+{
+  bfd_boolean must_recreate;
+  htab_t new_got;
+
+  must_recreate = FALSE;
+  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate);
+  if (must_recreate)
+    {
+      new_got = htab_create (htab_size (g->got_entries),
+			     mips_elf_got_entry_hash,
+			     mips_elf_got_entry_eq, NULL);
+      htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got);
+      if (new_got == NULL)
+	return FALSE;
+
+      /* Each entry in g->got_entries has either been copied to new_got
+	 or freed.  Now delete the hash table itself.  */
+      htab_delete (g->got_entries);
+      g->got_entries = new_got;
+    }
+  return TRUE;
+}
+
+/* An elf_link_hash_traverse callback for which DATA points to a mips_got_info.
+   Add each forced-local GOT symbol to DATA's local_gotno field.  */
+
+static int
+mips_elf_count_forced_local_got_symbols (struct elf_link_hash_entry *h,
+					 void *data)
+{
+  struct mips_got_info *g;
+
+  g = (struct mips_got_info *) data;
+  if (h->got.offset != MINUS_ONE
+      && (h->forced_local || h->dynindx == -1))
+    {
+      /* 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->got.offset == 2)
+	h->got.offset = MINUS_ONE;
+      else
+	g->local_gotno++;
+    }
+  return 1;
+}
 
 /* Compute the hash value of the bfd in a bfd2got hash entry.  */
 
@@ -3360,7 +3494,7 @@ mips_elf_make_got_per_bfd (void **entryp
       if (entry->tls_type & GOT_TLS_IE)
 	g->tls_gotno += 1;
     }
-  else if (entry->symndx >= 0 || entry->d.h->forced_local)
+  else if (entry->symndx >= 0 || entry->d.h->root.forced_local)
     ++g->local_gotno;
   else
     ++g->global_gotno;
@@ -3593,7 +3727,7 @@ mips_elf_set_global_got_offset (void **e
 
   if (entry->abfd != NULL && entry->symndx == -1
       && entry->d.h->root.dynindx != -1
-      && !entry->d.h->forced_local
+      && !entry->d.h->root.forced_local
       && entry->d.h->tls_type == GOT_NORMAL)
     {
       if (g)
@@ -3614,85 +3748,31 @@ mips_elf_set_global_got_offset (void **e
   return 1;
 }
 
-/* Mark any global symbols referenced in the GOT we are iterating over
-   as inelligible for lazy resolution stubs.  */
+/* A htab_traverse callback for GOT entries for which DATA is the
+   bfd_link_info.  Forbid any global symbols from having traditional
+   lazy-binding stubs.  */
+
 static int
-mips_elf_set_no_stub (void **entryp, void *p ATTRIBUTE_UNUSED)
+mips_elf_forbid_lazy_stubs (void **entryp, void *data)
 {
-  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+  struct bfd_link_info *info;
+  struct mips_elf_link_hash_table *htab;
+  struct mips_got_entry *entry;
 
+  entry = (struct mips_got_entry *) *entryp;
+  info = (struct bfd_link_info *) data;
+  htab = mips_elf_hash_table (info);
   if (entry->abfd != NULL
       && entry->symndx == -1
-      && entry->d.h->root.dynindx != -1)
-    entry->d.h->no_fn_stub = TRUE;
-
-  return 1;
-}
-
-/* Follow indirect and warning hash entries so that each got entry
-   points to the final symbol definition.  P must point to a pointer
-   to the hash table we're traversing.  Since this traversal may
-   modify the hash table, we set this pointer to NULL to indicate
-   we've made a potentially-destructive change to the hash table, so
-   the traversal must be restarted.  */
-static int
-mips_elf_resolve_final_got_entry (void **entryp, void *p)
-{
-  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
-  htab_t got_entries = *(htab_t *)p;
-
-  if (entry->abfd != NULL && entry->symndx == -1)
+      && entry->d.h->needs_lazy_stub)
     {
-      struct mips_elf_link_hash_entry *h = entry->d.h;
-
-      while (h->root.root.type == bfd_link_hash_indirect
- 	     || h->root.root.type == bfd_link_hash_warning)
-	h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
-      if (entry->d.h == h)
-	return 1;
-
-      entry->d.h = h;
-
-      /* If we can't find this entry with the new bfd hash, re-insert
-	 it, and get the traversal restarted.  */
-      if (! htab_find (got_entries, entry))
-	{
-	  htab_clear_slot (got_entries, entryp);
-	  entryp = htab_find_slot (got_entries, entry, INSERT);
-	  if (! *entryp)
-	    *entryp = entry;
-	  /* Abort the traversal, since the whole table may have
-	     moved, and leave it up to the parent to restart the
-	     process.  */
-	  *(htab_t *)p = NULL;
-	  return 0;
-	}
-      /* We might want to decrement the global_gotno count, but it's
-	 either too early or too late for that at this point.  */
+      entry->d.h->needs_lazy_stub = FALSE;
+      htab->lazy_stub_count--;
     }
 
   return 1;
 }
 
-/* Turn indirect got entries in a got_entries table into their final
-   locations.  */
-static void
-mips_elf_resolve_final_got_entries (struct mips_got_info *g)
-{
-  htab_t got_entries;
-
-  do
-    {
-      got_entries = g->got_entries;
-
-      htab_traverse (got_entries,
-		     mips_elf_resolve_final_got_entry,
-		     &got_entries);
-    }
-  while (got_entries == NULL);
-}
-
 /* Return the offset of an input bfd IBFD's GOT from the beginning of
    the primary GOT.  */
 static bfd_vma
@@ -3724,8 +3804,10 @@ mips_elf_multi_got (bfd *abfd, struct bf
   struct mips_elf_got_per_bfd_arg got_per_bfd_arg;
   struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
   struct mips_got_info *g, *gg;
-  unsigned int assign;
+  unsigned int assign, needed_relocs;
+  bfd *dynobj;
 
+  dynobj = elf_hash_table (info)->dynobj;
   htab = mips_elf_hash_table (info);
   g = htab->got_info;
   g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
@@ -3916,16 +3998,49 @@ mips_elf_multi_got (bfd *abfd, struct bf
       /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
       g = gn;
 
-      /* Mark global symbols in every non-primary GOT as ineligible for
-	 stubs.  */
+      /* Forbid global symbols in every non-primary GOT from having
+	 lazy-binding stubs.  */
       if (g)
-	htab_traverse (g->got_entries, mips_elf_set_no_stub, NULL);
+	htab_traverse (g->got_entries, mips_elf_forbid_lazy_stubs, info);
     }
   while (g);
 
   got->size = (gg->next->local_gotno
-		    + gg->next->global_gotno
-		    + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+	       + gg->next->global_gotno
+	       + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+
+  needed_relocs = 0;
+  set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (abfd);
+  set_got_offset_arg.info = info;
+  for (g = gg->next; g && g->next != gg; g = g->next)
+    {
+      unsigned int save_assign;
+
+      /* Assign offsets to global GOT entries.  */
+      save_assign = g->assigned_gotno;
+      g->assigned_gotno = g->local_gotno;
+      set_got_offset_arg.g = g;
+      set_got_offset_arg.needed_relocs = 0;
+      htab_traverse (g->got_entries,
+		     mips_elf_set_global_got_offset,
+		     &set_got_offset_arg);
+      needed_relocs += set_got_offset_arg.needed_relocs;
+      BFD_ASSERT (g->assigned_gotno - g->local_gotno <= g->global_gotno);
+
+      g->assigned_gotno = save_assign;
+      if (info->shared)
+	{
+	  needed_relocs += g->local_gotno - g->assigned_gotno;
+	  BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
+		      + g->next->global_gotno
+		      + g->next->tls_gotno
+		      + MIPS_RESERVED_GOTNO (info));
+	}
+    }
+
+  if (needed_relocs)
+    mips_elf_allocate_dynamic_relocations (dynobj, info,
+					   needed_relocs);
 
   return TRUE;
 }
@@ -5059,33 +5174,6 @@ mips_elf_perform_relocation (struct bfd_
   return TRUE;
 }
 
-/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
-
-static void
-mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
-				       unsigned int n)
-{
-  asection *s;
-  struct mips_elf_link_hash_table *htab;
-
-  htab = mips_elf_hash_table (info);
-  s = mips_elf_rel_dyn_section (info, FALSE);
-  BFD_ASSERT (s != NULL);
-
-  if (htab->is_vxworks)
-    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
-  else
-    {
-      if (s->size == 0)
-	{
-	  /* Make room for a null element.  */
-	  s->size += MIPS_ELF_REL_SIZE (abfd);
-	  ++s->reloc_count;
-	}
-      s->size += n * MIPS_ELF_REL_SIZE (abfd);
-    }
-}
-
 /* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
    is the original relocation, which is now being transformed into a
    dynamic relocation.  The ADDENDP is adjusted if necessary; the
@@ -7547,18 +7635,8 @@ _bfd_mips_elf_adjust_dynamic_symbol (str
 	 executable and the shared library.  */
       if (!h->def_regular)
 	{
-	  /* We need .stub section.  */
-	  h->root.u.def.section = htab->sstubs;
-	  h->root.u.def.value = htab->sstubs->size;
-
-	  /* XXX Write this stub address somewhere.  */
-	  h->plt.offset = htab->sstubs->size;
-
-	  /* Make room for this stub code.  */
-	  htab->sstubs->size += htab->function_stub_size;
-
-	  /* The last half word of the stub will be filled with the index
-	     of this symbol in .dynsym section.  */
+	  hmips->needs_lazy_stub = TRUE;
+	  htab->lazy_stub_count++;
 	  return TRUE;
 	}
     }
@@ -7757,15 +7835,6 @@ _bfd_mips_elf_always_size_sections (bfd 
 				    struct bfd_link_info *info)
 {
   asection *ri;
-
-  asection *s;
-  struct mips_got_info *g;
-  int i;
-  bfd_size_type loadable_size = 0;
-  bfd_size_type page_gotno;
-  bfd_size_type dynsymcount;
-  bfd *sub;
-  struct mips_elf_count_tls_arg count_tls_arg;
   struct mips_elf_link_hash_table *htab;
 
   htab = mips_elf_hash_table (info);
@@ -7780,29 +7849,40 @@ _bfd_mips_elf_always_size_sections (bfd 
     mips_elf_link_hash_traverse (mips_elf_hash_table (info),
 				 mips_elf_check_mips16_stubs, info);
 
+  return TRUE;
+}
+
+/* If the link uses a GOT, lay it out and work out its size.  */
+
+static bfd_boolean
+mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
+{
+  bfd *dynobj;
+  asection *s;
+  struct mips_got_info *g;
+  int i;
+  bfd_size_type loadable_size = 0;
+  bfd_size_type page_gotno;
+  bfd *sub;
+  struct mips_elf_count_tls_arg count_tls_arg;
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
   s = htab->sgot;
   if (s == NULL)
     return TRUE;
 
+  dynobj = elf_hash_table (info)->dynobj;
   g = htab->got_info;
 
-  /* Calculate the total loadable size of the output.  That
-     will give us the maximum number of GOT_PAGE entries
-     required.  */
-  for (sub = info->input_bfds; sub; sub = sub->link_next)
-    {
-      asection *subsection;
+  /* Replace entries for indirect and warning symbols with entries for
+     the target symbol.  */
+  if (!mips_elf_resolve_final_got_entries (g))
+    return FALSE;
 
-      for (subsection = sub->sections;
-	   subsection;
-	   subsection = subsection->next)
-	{
-	  if ((subsection->flags & SEC_ALLOC) == 0)
-	    continue;
-	  loadable_size += ((subsection->size + 0xf)
-			    &~ (bfd_size_type) 0xf);
-	}
-    }
+  /* Count the number of forced-local entries.  */
+  elf_link_hash_traverse (elf_hash_table (info),
+			  mips_elf_count_forced_local_got_symbols, g);
 
   /* There has to be a global GOT entry for every symbol with
      a dynamic symbol table index of DT_MIPS_GOTSYM or
@@ -7819,22 +7899,23 @@ _bfd_mips_elf_always_size_sections (bfd 
        relocations, then GLOBAL_GOTSYM will be NULL.  */
     i = 0;
 
-  /* Get a worst-case estimate of the number of dynamic symbols needed.
-     At this point, dynsymcount does not account for section symbols
-     and count_section_dynsyms may overestimate the number that will
-     be needed.  */
-  dynsymcount = (elf_hash_table (info)->dynsymcount
-		 + count_section_dynsyms (output_bfd, info));
-
-  /* Determine the size of one stub entry.  */
-  htab->function_stub_size = (dynsymcount > 0x10000
-			      ? MIPS_FUNCTION_STUB_BIG_SIZE
-			      : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+  /* Calculate the total loadable size of the output.  That
+     will give us the maximum number of GOT_PAGE entries
+     required.  */
+  for (sub = info->input_bfds; sub; sub = sub->link_next)
+    {
+      asection *subsection;
 
-  /* In the worst case, we'll get one stub per dynamic symbol, plus
-     one to account for the dummy entry at the end required by IRIX
-     rld.  */
-  loadable_size += htab->function_stub_size * (i + 1);
+      for (subsection = sub->sections;
+	   subsection;
+	   subsection = subsection->next)
+	{
+	  if ((subsection->flags & SEC_ALLOC) == 0)
+	    continue;
+	  loadable_size += ((subsection->size + 0xf)
+			    &~ (bfd_size_type) 0xf);
+	}
+    }
 
   if (htab->is_vxworks)
     /* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
@@ -7868,27 +7949,120 @@ _bfd_mips_elf_always_size_sections (bfd 
   g->tls_gotno += count_tls_arg.needed;
   s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
 
-  mips_elf_resolve_final_got_entries (g);
-
   /* VxWorks does not support multiple GOTs.  It initializes $gp to
      __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
      dynamic loader.  */
-  if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
+  if (htab->is_vxworks)
+    {
+      /* VxWorks executables do not need a GOT.  */
+      if (info->shared)
+	{
+	  /* Each VxWorks GOT entry needs an explicit relocation.  */
+	  unsigned int count;
+
+	  count = g->global_gotno + g->local_gotno - MIPS_RESERVED_GOTNO (info);
+	  if (count)
+	    mips_elf_allocate_dynamic_relocations (dynobj, info, count);
+	}
+    }
+  else if (s->size > MIPS_ELF_GOT_MAX_SIZE (info))
     {
       if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
 	return FALSE;
     }
   else
     {
-      /* Set up TLS entries for the first GOT.  */
+      struct mips_elf_count_tls_arg arg;
+
+      /* Set up TLS entries.  */
       g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
       htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
+
+      /* Allocate room for the TLS relocations.  */
+      arg.info = info;
+      arg.needed = 0;
+      htab_traverse (g->got_entries, mips_elf_count_local_tls_relocs, &arg);
+      elf_link_hash_traverse (elf_hash_table (info),
+			      mips_elf_count_global_tls_relocs,
+			      &arg);
+      if (arg.needed)
+	mips_elf_allocate_dynamic_relocations (dynobj, info, arg.needed);
     }
-  htab->computed_got_sizes = TRUE;
 
   return TRUE;
 }
 
+/* Estimate the size of the .MIPS.stubs section.  */
+
+static void
+mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
+{
+  struct mips_elf_link_hash_table *htab;
+  bfd_size_type dynsymcount;
+
+  htab = mips_elf_hash_table (info);
+  if (htab->lazy_stub_count == 0)
+    return;
+
+  /* IRIX rld assumes that a function stub isn't at the end of the .text
+     section, so add a dummy entry to the end.  */
+  htab->lazy_stub_count++;
+
+  /* Get a worst-case estimate of the number of dynamic symbols needed.
+     At this point, dynsymcount does not account for section symbols
+     and count_section_dynsyms may overestimate the number that will
+     be needed.  */
+  dynsymcount = (elf_hash_table (info)->dynsymcount
+		 + count_section_dynsyms (output_bfd, info));
+
+  /* Determine the size of one stub entry.  */
+  htab->function_stub_size = (dynsymcount > 0x10000
+			      ? MIPS_FUNCTION_STUB_BIG_SIZE
+			      : MIPS_FUNCTION_STUB_NORMAL_SIZE);
+
+  htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
+}
+
+/* A mips_elf_link_hash_traverse callback for which DATA points to the
+   MIPS hash table.  If H needs a traditional MIPS lazy-binding stub,
+   allocate an entry in the stubs section.  */
+
+static bfd_boolean
+mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
+{
+  struct mips_elf_link_hash_table *htab;
+
+  htab = (struct mips_elf_link_hash_table *) data;
+  if (h->needs_lazy_stub)
+    {
+      h->root.root.u.def.section = htab->sstubs;
+      h->root.root.u.def.value = htab->sstubs->size;
+      h->root.plt.offset = htab->sstubs->size;
+      htab->sstubs->size += htab->function_stub_size;
+    }
+  return TRUE;
+}
+
+/* Allocate offsets in the stubs section to each symbol that needs one.
+   Set the final size of the .MIPS.stub section.  */
+
+static void
+mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
+{
+  struct mips_elf_link_hash_table *htab;
+
+  htab = mips_elf_hash_table (info);
+  if (htab->lazy_stub_count == 0)
+    return;
+
+  htab->sstubs->size = 0;
+  mips_elf_link_hash_traverse (mips_elf_hash_table (info),
+			       mips_elf_allocate_lazy_stub, htab);
+  htab->sstubs->size += htab->function_stub_size;
+  BFD_ASSERT (htab->sstubs->size
+	      == htab->lazy_stub_count * htab->function_stub_size);
+}
+
 /* Set the sizes of the dynamic sections.  */
 
 bfd_boolean
@@ -7896,7 +8070,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd
 				     struct bfd_link_info *info)
 {
   bfd *dynobj;
-  asection *s, *sreldyn;
+  asection *s;
   bfd_boolean reltext;
   struct mips_elf_link_hash_table *htab;
 
@@ -7918,19 +8092,20 @@ _bfd_mips_elf_size_dynamic_sections (bfd
 	}
       }
 
-  /* IRIX rld assumes that the function stub isn't at the end
-     of the .text section, so add a dummy entry to the end.  */
-  if (htab->sstubs && htab->sstubs->size > 0)
-    htab->sstubs->size += htab->function_stub_size;
-
   /* Allocate space for global sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
 
+  mips_elf_estimate_stub_size (output_bfd, info);
+
+  if (!mips_elf_lay_out_got (output_bfd, info))
+    return FALSE;
+
+  mips_elf_lay_out_lazy_stubs (info);
+
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
   reltext = FALSE;
-  sreldyn = NULL;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       const char *name;
@@ -7978,88 +8153,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd
 	      info->combreloc = 0;
 	    }
 	}
-      else if (htab->is_vxworks && strcmp (name, ".got") == 0)
-	{
-	  /* Executables do not need a GOT.  */
-	  if (info->shared)
-	    {
-	      /* Allocate relocations for all but the reserved entries.  */
-	      unsigned int count;
-
-	      count = (htab->got_info->global_gotno
-		       + htab->got_info->local_gotno
-		       - MIPS_RESERVED_GOTNO (info));
-	      mips_elf_allocate_dynamic_relocations (dynobj, info, count);
-	    }
-	}
-      else if (!htab->is_vxworks && CONST_STRNEQ (name, ".got"))
-	{
-	  /* _bfd_mips_elf_always_size_sections() has already done
-	     most of the work, but some symbols may have been mapped
-	     to versions that we must now resolve in the got_entries
-	     hash tables.  */
-	  struct mips_got_info *gg = htab->got_info;
-	  struct mips_got_info *g = gg;
-	  struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
-	  unsigned int needed_relocs = 0;
-
-	  if (gg->next)
-	    {
-	      set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd);
-	      set_got_offset_arg.info = info;
-
-	      /* NOTE 2005-02-03: How can this call, or the next, ever
-		 find any indirect entries to resolve?  They were all
-		 resolved in mips_elf_multi_got.  */
-	      mips_elf_resolve_final_got_entries (gg);
-	      for (g = gg->next; g && g->next != gg; g = g->next)
-		{
-		  unsigned int save_assign;
-
-		  mips_elf_resolve_final_got_entries (g);
-
-		  /* Assign offsets to global GOT entries.  */
-		  save_assign = g->assigned_gotno;
-		  g->assigned_gotno = g->local_gotno;
-		  set_got_offset_arg.g = g;
-		  set_got_offset_arg.needed_relocs = 0;
-		  htab_traverse (g->got_entries,
-				 mips_elf_set_global_got_offset,
-				 &set_got_offset_arg);
-		  needed_relocs += set_got_offset_arg.needed_relocs;
-		  BFD_ASSERT (g->assigned_gotno - g->local_gotno
-			      <= g->global_gotno);
-
-		  g->assigned_gotno = save_assign;
-		  if (info->shared)
-		    {
-		      needed_relocs += g->local_gotno - g->assigned_gotno;
-		      BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
-				  + g->next->global_gotno
-				  + g->next->tls_gotno
-				  + MIPS_RESERVED_GOTNO (info));
-		    }
-		}
-	    }
-	  else
-	    {
-	      struct mips_elf_count_tls_arg arg;
-	      arg.info = info;
-	      arg.needed = 0;
-
-	      htab_traverse (gg->got_entries, mips_elf_count_local_tls_relocs,
-			     &arg);
-	      elf_link_hash_traverse (elf_hash_table (info),
-				      mips_elf_count_global_tls_relocs,
-				      &arg);
-
-	      needed_relocs += arg.needed;
-	    }
-
-	  if (needed_relocs)
-	    mips_elf_allocate_dynamic_relocations (dynobj, info,
-						   needed_relocs);
-	}
       else if (! info->shared
 	       && ! mips_elf_hash_table (info)->use_rld_obj_head
 	       && CONST_STRNEQ (name, ".rld_map"))
@@ -8072,6 +8165,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd
 	       && CONST_STRNEQ (name, ".compact_rel"))
 	s->size += mips_elf_hash_table (info)->compact_rel_size;
       else if (! CONST_STRNEQ (name, ".init")
+	       && s != htab->sgot
 	       && s != htab->sgotplt
 	       && s != htab->splt
 	       && s != htab->sstubs)
@@ -8089,14 +8183,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd
       if ((s->flags & SEC_HAS_CONTENTS) == 0)
 	continue;
 
-      /* Allocate memory for this section last, since we may increase its
-	 size above.  */
-      if (strcmp (name, MIPS_ELF_REL_DYN_NAME (info)) == 0)
-	{
-	  sreldyn = s;
-	  continue;
-	}
-
       /* Allocate memory for the section contents.  */
       s->contents = bfd_zalloc (dynobj, s->size);
       if (s->contents == NULL)
@@ -8106,17 +8192,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd
 	}
     }
 
-  /* Allocate memory for the .rel(a).dyn section.  */
-  if (sreldyn != NULL)
-    {
-      sreldyn->contents = bfd_zalloc (dynobj, sreldyn->size);
-      if (sreldyn->contents == NULL)
-	{
-	  bfd_set_error (bfd_error_no_memory);
-	  return FALSE;
-	}
-    }
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       /* Add some entries to the .dynamic section.  We fill in the
@@ -10193,91 +10268,6 @@ _bfd_mips_elf_copy_indirect_symbol (stru
   if (dirmips->tls_type == 0)
     dirmips->tls_type = indmips->tls_type;
 }
-
-void
-_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
-			   struct elf_link_hash_entry *entry,
-			   bfd_boolean force_local)
-{
-  bfd *dynobj;
-  struct mips_got_info *g;
-  struct mips_elf_link_hash_entry *h;
-  struct mips_elf_link_hash_table *htab;
-
-  h = (struct mips_elf_link_hash_entry *) entry;
-  if (h->forced_local)
-    return;
-  h->forced_local = force_local;
-
-  dynobj = elf_hash_table (info)->dynobj;
-  htab = mips_elf_hash_table (info);
-  if (dynobj != NULL
-      && force_local
-      && h->root.type != STT_TLS
-      && htab->got_info != NULL)
-    {
-      g = htab->got_info;
-      if (g->next)
-	{
-	  struct mips_got_entry e;
-	  struct mips_got_info *gg = g;
-
-	  /* Since we're turning what used to be a global symbol into a
-	     local one, bump up the number of local entries of each GOT
-	     that had an entry for it.  This will automatically decrease
-	     the number of global entries, since global_gotno is actually
-	     the upper limit of global entries.  */
-	  e.abfd = dynobj;
-	  e.symndx = -1;
-	  e.d.h = h;
-	  e.tls_type = 0;
-
-	  for (g = g->next; g != gg; g = g->next)
-	    if (htab_find (g->got_entries, &e))
-	      {
-		BFD_ASSERT (g->global_gotno > 0);
-		g->local_gotno++;
-		g->global_gotno--;
-	      }
-
-	  /* If this was a global symbol forced into the primary GOT, we
-	     no longer need an entry for it.  We can't release the entry
-	     at this point, but we must at least stop counting it as one
-	     of the symbols that required a forced got entry.  */
-	  if (h->root.got.offset == 2)
-	    {
-	      BFD_ASSERT (gg->assigned_gotno > 0);
-	      gg->assigned_gotno--;
-	    }
-	}
-      else if (h->root.got.offset == 1)
-	{
-	  /* check_relocs didn't know that this symbol would be
-	     forced-local, so add an extra local got entry.  */
-	  g->local_gotno++;
-	  if (htab->computed_got_sizes)
-	    {
-	      /* We'll have treated this symbol as global rather
-		 than local.  */
-	      BFD_ASSERT (g->global_gotno > 0);
-	      g->global_gotno--;
-	    }
-	}
-      else if (htab->is_vxworks && h->root.needs_plt)
-	{
-	  /* check_relocs didn't know that this symbol would be
-	     forced-local, so add an extra local got entry.  */
-	  g->local_gotno++;
-	  if (htab->computed_got_sizes)
-	    /* The symbol is only used in call relocations, so we'll
-	       have assumed it only needs a .got.plt entry.  Increase
-	       the size of .got accordingly.  */
-	    htab->sgot->size += MIPS_ELF_GOT_SIZE (dynobj);
-        }
-    }
-
-  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
-}
 
 #define PDR_SIZE 32
 
@@ -10734,7 +10724,6 @@ _bfd_mips_elf_link_hash_table_create (bf
   ret->use_rld_obj_head = FALSE;
   ret->rld_value = 0;
   ret->mips16_stubs_seen = FALSE;
-  ret->computed_got_sizes = FALSE;
   ret->is_vxworks = FALSE;
   ret->small_data_overflow_reported = FALSE;
   ret->srelbss = NULL;
@@ -10748,6 +10737,7 @@ _bfd_mips_elf_link_hash_table_create (bf
   ret->got_info = NULL;
   ret->plt_header_size = 0;
   ret->plt_entry_size = 0;
+  ret->lazy_stub_count = 0;
   ret->function_stub_size = 0;
 
   return &ret->root.root;
Index: ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got
===================================================================
--- ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got	2008-08-06 20:18:41.000000000 +0100
+++ ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got	2008-08-06 21:00:51.000000000 +0100
@@ -4,16 +4,16 @@
 DYNAMIC RELOCATION RECORDS
 OFFSET   TYPE              VALUE 
 00000000 R_MIPS_NONE       \*ABS\*
-10000040 R_MIPS_TLS_DTPMOD32  tlsbin_gd
-10000044 R_MIPS_TLS_DTPREL32  tlsbin_gd
-10000034 R_MIPS_TLS_DTPMOD32  tlsvar_gd
-10000038 R_MIPS_TLS_DTPREL32  tlsvar_gd
-1000003c R_MIPS_TLS_TPREL32  tlsvar_ie
+10000038 R_MIPS_TLS_DTPMOD32  tlsbin_gd
+1000003c R_MIPS_TLS_DTPREL32  tlsbin_gd
+10000030 R_MIPS_TLS_DTPMOD32  tlsvar_gd
+10000034 R_MIPS_TLS_DTPREL32  tlsvar_gd
+1000002c R_MIPS_TLS_TPREL32  tlsvar_ie
 10000048 R_MIPS_TLS_TPREL32  tlsbin_ie
 
 
 Contents of section .got:
- 10000020 00000000 80000000 0040053c 00000001  .*
+ 10000020 00000000 80000000 0040053c 00000000  .*
  10000030 00000000 00000000 00000000 00000000  .*
- 10000040 00000000 00000000 00000000 00000000  .*
+ 10000040 00000001 00000000 00000000 00000000  .*
  10000050 00000000 00000000                    .*
Index: ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got
===================================================================
--- ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got	2008-08-06 20:18:41.000000000 +0100
+++ ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got	2008-08-06 21:00:51.000000000 +0100
@@ -4,16 +4,16 @@
 DYNAMIC RELOCATION RECORDS
 OFFSET   TYPE              VALUE 
 00000000 R_MIPS_NONE       \*ABS\*
-10000040 R_MIPS_TLS_DTPMOD32  tlsbin_gd
-10000044 R_MIPS_TLS_DTPREL32  tlsbin_gd
-10000034 R_MIPS_TLS_DTPMOD32  tlsvar_gd
-10000038 R_MIPS_TLS_DTPREL32  tlsvar_gd
-1000003c R_MIPS_TLS_TPREL32  tlsvar_ie
+10000038 R_MIPS_TLS_DTPMOD32  tlsbin_gd
+1000003c R_MIPS_TLS_DTPREL32  tlsbin_gd
+10000030 R_MIPS_TLS_DTPMOD32  tlsvar_gd
+10000034 R_MIPS_TLS_DTPREL32  tlsvar_gd
+1000002c R_MIPS_TLS_TPREL32  tlsvar_ie
 10000048 R_MIPS_TLS_TPREL32  tlsbin_ie
 
 
 Contents of section .got:
- 10000020 00000000 80000000 004005ec 00000001  .*
+ 10000020 00000000 80000000 004005ec 00000000  .*
  10000030 00000000 00000000 00000000 00000000  .*
- 10000040 00000000 00000000 00000000 00000000  .*
+ 10000040 00000001 00000000 00000000 00000000  .*
  10000050 00000000 00000000                    .*
Index: ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d
===================================================================
--- ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d	2008-08-06 20:48:34.000000000 +0100
+++ ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d	2008-08-06 21:00:51.000000000 +0100
@@ -12,19 +12,19 @@ Disassembly of section .text:
   .*:	03a0f021 	move	s8,sp
   .*:	afbc0000 	sw	gp,0\(sp\)
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848030 	addiu	a0,gp,-32720
+  .*:	27848028 	addiu	a0,gp,-32728
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848024 	addiu	a0,gp,-32732
+  .*:	27848020 	addiu	a0,gp,-32736
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	2784801c 	addiu	a0,gp,-32740
+  .*:	27848030 	addiu	a0,gp,-32720
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
@@ -36,7 +36,7 @@ Disassembly of section .text:
   .*:	8f838038 	lw	v1,-32712\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
-  .*:	8f83802c 	lw	v1,-32724\(gp\)
+  .*:	8f83801c 	lw	v1,-32740\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
   .*:	7c02283b 	rdhwr	v0,\$5
@@ -62,19 +62,19 @@ Disassembly of section .text:
   .*:	03a0f021 	move	s8,sp
   .*:	afbc0000 	sw	gp,0\(sp\)
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848030 	addiu	a0,gp,-32720
+  .*:	27848028 	addiu	a0,gp,-32728
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848024 	addiu	a0,gp,-32732
+  .*:	27848020 	addiu	a0,gp,-32736
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	2784801c 	addiu	a0,gp,-32740
+  .*:	27848030 	addiu	a0,gp,-32720
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
@@ -86,7 +86,7 @@ Disassembly of section .text:
   .*:	8f838038 	lw	v1,-32712\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
-  .*:	8f83802c 	lw	v1,-32724\(gp\)
+  .*:	8f83801c 	lw	v1,-32740\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
   .*:	7c02283b 	rdhwr	v0,\$5
Index: ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d
===================================================================
--- ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d	2008-08-06 20:48:34.000000000 +0100
+++ ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d	2008-08-06 21:00:51.000000000 +0100
@@ -12,19 +12,19 @@ Disassembly of section .text:
   .*:	03a0f021 	move	s8,sp
   .*:	afbc0000 	sw	gp,0\(sp\)
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848030 	addiu	a0,gp,-32720
+  .*:	27848028 	addiu	a0,gp,-32728
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848024 	addiu	a0,gp,-32732
+  .*:	27848020 	addiu	a0,gp,-32736
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	2784801c 	addiu	a0,gp,-32740
+  .*:	27848030 	addiu	a0,gp,-32720
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
@@ -36,7 +36,7 @@ Disassembly of section .text:
   .*:	8f838038 	lw	v1,-32712\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
-  .*:	8f83802c 	lw	v1,-32724\(gp\)
+  .*:	8f83801c 	lw	v1,-32740\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
   .*:	7c02283b 	rdhwr	v0,\$5
@@ -58,19 +58,19 @@ Disassembly of section .text:
   .*:	03a0f021 	move	s8,sp
   .*:	afbc0000 	sw	gp,0\(sp\)
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848030 	addiu	a0,gp,-32720
+  .*:	27848028 	addiu	a0,gp,-32728
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	27848024 	addiu	a0,gp,-32732
+  .*:	27848020 	addiu	a0,gp,-32736
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
   .*:	00000000 	nop
   .*:	8f998018 	lw	t9,-32744\(gp\)
-  .*:	2784801c 	addiu	a0,gp,-32740
+  .*:	27848030 	addiu	a0,gp,-32720
   .*:	0320f809 	jalr	t9
   .*:	00000000 	nop
   .*:	8fdc0000 	lw	gp,0\(s8\)
@@ -82,7 +82,7 @@ Disassembly of section .text:
   .*:	8f838038 	lw	v1,-32712\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
-  .*:	8f83802c 	lw	v1,-32724\(gp\)
+  .*:	8f83801c 	lw	v1,-32740\(gp\)
   .*:	00000000 	nop
   .*:	00621821 	addu	v1,v1,v0
   .*:	7c02283b 	rdhwr	v0,\$5


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]