This is the mail archive of the binutils@sources.redhat.com 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]

Another MIPS multigot patch


Currently I can't build an n64 GCC (with my other patches applied to the
linker).  The error is an R_MIPS_GOT_PAGE overflow for a common variable
(flag_dump_unnumbered?).  Here's the problem:

  if (1)
    {
      gg->assigned_gotno = gg->global_gotno - g->global_gotno;
      g->global_gotno = gg->global_gotno;
      set_got_offset_arg.value = 2;
    }

With this, global_gotno increases by a substantial amount.  If the primary
GOT was full, then the odds are good that there is now a 16-bit relocation
in the primary GOT that can no longer be resolved.  Essentially, we're
accessing two GOTs (the "master" GOT and the "primary" GOT) using the same
$gp value.

The patch below implements the obvious fix if my understanding is correct:
consider the number of global symbols in the primary GOT to be the total
number of global symbols.  If it goes over the limit of GOT size, we'll
create a dummy primary GOT with no local symbols and no input BFD using it,
to satisfy the dynamic linker.  So everything should work out OK.

Tested on mips64el-linux-gnu, lightly.  I'll do more thorough testing after
I have a chance to revise my previous patch to Richard's comment.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2003-11-21  Daniel Jacobowitz  <drow@mvista.com>

	* elfxx-mips.c (struct mips_elf_got_per_bfd_arg): Add global_count.
	(mips_elf_merge_gots): Use arg->global_count instead of the primary
	GOT's global_gotno.
	(mips_elf_multi_got): Set got_per_bfd_arg.global_count.

--- src/bfd/elfxx-mips.c.orig	2003-11-21 15:13:04.000000000 -0500
+++ src/bfd/elfxx-mips.c	2003-11-21 15:50:25.000000000 -0500
@@ -121,7 +121,11 @@ struct mips_elf_got_per_bfd_arg
   /* The maximum number of got entries that can be addressed with a
      16-bit offset.  */
   unsigned int max_count;
-  /* The number of local and global entries in the primary got.  */
+  /* The number of global entries in the master GOT (i.e. including
+     entries otherwise unreferenced in the primary GOT).  */
+  unsigned int global_count;
+  /* The number of local and global entries in the primary and master
+     GOTs.  */
   unsigned int primary_count;
   /* The number of local and global entries in the current got.  */
   unsigned int current_count;
@@ -2271,16 +2275,15 @@ mips_elf_merge_gots (bfd2got_, p)
   
   /* If we don't have a primary GOT and this is not too big, use it as
      a starting point for the primary GOT.  */
-  if (! arg->primary && lcount + gcount <= maxcnt)
+  if (! arg->primary && lcount + arg->global_count <= maxcnt)
     {
       arg->primary = bfd2got->g;
       arg->primary_count = lcount + gcount;
     }
   /* If it looks like we can merge this bfd's entries with those of
-     the primary, merge them.  The heuristics is conservative, but we
+     the primary, merge them.  The heuristic is conservative, but we
      don't have to squeeze it too hard.  */
-  else if (arg->primary
-	   && (arg->primary_count + lcount + gcount) <= maxcnt)
+  else if (arg->primary && (arg->primary_count + lcount) <= maxcnt)
     {
       struct mips_got_info *g = bfd2got->g;
       int old_lcount = arg->primary->local_gotno;
@@ -2302,8 +2305,7 @@ mips_elf_merge_gots (bfd2got_, p)
       BFD_ASSERT (old_lcount + lcount >= arg->primary->local_gotno);
       BFD_ASSERT (old_gcount + gcount >= arg->primary->global_gotno);
 
-      arg->primary_count = arg->primary->local_gotno
-	+ arg->primary->global_gotno;
+      arg->primary_count = arg->primary->local_gotno + arg->global_count;
     }
   /* If we can merge with the last-created got, do it.  */
   else if (arg->current
@@ -2544,6 +2546,12 @@ mips_elf_multi_got (abfd, info, g, got, 
 				/ MIPS_ELF_GOT_SIZE (abfd))
 			       - MIPS_RESERVED_GOTNO - pages);
 
+  /* The primary GOT will be expanded to include all global symbols, so
+     pass the total number so that we don't merge too many other GOT's
+     local symbols in.  See below for why IRIX needs this and GNU/Linux
+     has adoped the requirement.  */
+  got_per_bfd_arg.global_count = g->global_gotno;
+
   /* Try to merge the GOTs of input bfds together, as long as they
      don't seem to exceed the maximum GOT size, choosing one of them
      to be the primary GOT.  */


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