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]

MIPS multigot fixes for Linux


I humbly request an opinion from Richard S, who understands this stuff a
whole lot better than I do.  This is based on his earlier message:
  http://sources.redhat.com/ml/binutils/2003-06/msg00724.html

This patch fixes two bugs.  The first is that, as Richard described, glibc
needs a zero in the GOT entry for a global symbol or else it has a tendency
to treat that value as an addend and add the resolved value to it.  This is
an incompatibility.  I'm sticking with !SGI_COMPAT(output_bfd); there is
room in the glibc loader to vary the ABI if someone has a reason to fix all
this someday.  I'd recommend changing the special value used to identify GNU
objects in got[1].

The other issue is that we must not emit stubs for multiple-got symbols. 
There are two reasons:
  - Efficiency.  We need to resolve the symbol at start time anyway so why
    do it lazily also?  Plus this would require tweaking the dynamic linker;
    this appears to be why SGI has R_MIPS_RELGOT.
  - Stub simplicity.  Our stubs do not load $gp.  Therefore, if they are
    called from a function with a different GOT, they will fail to load
    _dl_runtime_resolve.  *boom*.
We already knew this.  Unfortunately, somehow, we ended up setting
no_fn_stub after reading it.

Look OK?  If you prefer I think the no_fn_stub setting below could be moved
into the else branch, since the second time is redundant.  I'm not thrilled
with how complicated the uses of mips_elf_set_global_got_offset are; it's
really three different functions with the same outer if test.

I believe this patch will fix Atsushi-san's testcase.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

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

	* elfxx-mips.c (mips_elf_set_global_got_offset): Set no_fn_stub
	in the first pass.
	(_bfd_mips_elf_finish_dynamic_symbol): Fill global GOT entries with
	zero for ! SGI_COMPAT.

Index: elfxx-mips.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/bfd/elfxx-mips.c,v
retrieving revision 1.78
diff -u -p -r1.78 elfxx-mips.c
--- elfxx-mips.c	13 Oct 2003 19:51:09 -0000	1.78
+++ elfxx-mips.c	11 Nov 2003 17:00:24 -0000
@@ -2333,15 +2333,19 @@ mips_elf_set_global_got_offset (entryp, 
   if (entry->abfd != NULL && entry->symndx == -1
       && entry->d.h->root.dynindx != -1)
     {
+      /* We can't do lazy update of GOT entries for non-primary GOTs since
+	 the PLT entries don't use the right offsets, so punt at it for now. 
+	 We set this here because we are called via mips_elf_multi_got
+	 before _bfd_mips_elf_adjust_dynamic_symbol reads the no_fn_stub
+	 flag; this only matters for the global case, but
+	 _bfd_mips_elf_size_dynamic_sections is too late.  */
+      entry->d.h->no_fn_stub = TRUE;
+
       if (g)
 	{
 	  BFD_ASSERT (g->global_gotsym == NULL);
 
 	  entry->gotidx = arg->value * (long) g->assigned_gotno++;
-	  /* We can't do lazy update of GOT entries for
-	     non-primary GOTs since the PLT entries don't use the
-	     right offsets, so punt at it for now.  */
-	  entry->d.h->no_fn_stub = TRUE;
 	  if (arg->info->shared
 	      || (elf_hash_table (arg->info)->dynamic_sections_created
 		  && ((entry->d.h->root.elf_link_hash_flags
@@ -6693,18 +6697,25 @@ _bfd_mips_elf_finish_dynamic_symbol (out
 
 	      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
 
-	      if ((info->shared
-		   || (elf_hash_table (info)->dynamic_sections_created
-		       && p->d.h != NULL
-		       && ((p->d.h->root.elf_link_hash_flags
-			    & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
-		       && ((p->d.h->root.elf_link_hash_flags
-			    & ELF_LINK_HASH_DEF_REGULAR) == 0)))
-		  && ! (mips_elf_create_dynamic_relocation
-			(output_bfd, info, rel,
-			 e.d.h, NULL, value, &addend, sgot)))
-		return FALSE;
-	      BFD_ASSERT (addend == 0);
+	      if (info->shared
+		  || (elf_hash_table (info)->dynamic_sections_created
+		      && p->d.h != NULL
+		      && ((p->d.h->root.elf_link_hash_flags
+			   & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+		      && ((p->d.h->root.elf_link_hash_flags
+			   & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+		{
+		  /* Unfortunately this is another one of the differences
+		     between glibc and the Irix rld.  */
+		  if (!SGI_COMPAT (output_bfd))
+		    MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents + offset);
+
+		  if (! (mips_elf_create_dynamic_relocation
+			 (output_bfd, info, rel,
+			  e.d.h, NULL, value, &addend, sgot)))
+		    return FALSE;
+		  BFD_ASSERT (addend == 0);
+		}
 	    }
 	}
     }


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