about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--sysdeps/mips/dl-machine.h60
1 files changed, 35 insertions, 25 deletions
diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h
index 2a19126208..c0ece38719 100644
--- a/sysdeps/mips/dl-machine.h
+++ b/sysdeps/mips/dl-machine.h
@@ -136,7 +136,11 @@ elf_machine_load_address (void)
 }
 
 /* The MSB of got[1] of a gnu object is set to identify gnu objects.  */
-#define ELF_MIPS_GNU_GOT1_MASK 0x80000000
+#define ELF_MIPS_GNU_GOT1_MASK	0x80000000
+
+/* GNU Binutils upto 2.10 produce a wrong relocations.  Bit 30 of
+   got[1] marks good objects.  */
+#define ELF_MIPS_GNU_GOT1_OK	0x00000001
 
 /* We can't rely on elf_machine_got_rel because _dl_object_relocation_scope
    fiddles with global data.  */
@@ -149,6 +153,9 @@ do {									\
 									\
   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);			\
 									\
+  if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)				\
+    got[1] = (ElfW(Addr)) ELF_MIPS_GNU_GOT1_MASK			\
+              | (got[1] & ELF_MIPS_GNU_GOT1_OK);			\
 									\
   if (__builtin_expect (map->l_addr == 0, 1))				\
     goto done;								\
@@ -212,8 +219,8 @@ elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
 
       if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
 	{
-	  struct link_map *l =
-	    (struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
+	  struct link_map *l = (struct link_map *)
+		(g1 & ~(ELF_MIPS_GNU_GOT1_MASK|ELF_MIPS_GNU_GOT1_OK));
 	  ElfW(Addr) base, limit;
 	  const ElfW(Phdr) *p = l->l_phdr;
 	  ElfW(Half) this, nent = l->l_phnum;
@@ -352,11 +359,12 @@ asm ("\n								      \
 	.type	_dl_runtime_resolve,@function\n				      \
 	.ent	_dl_runtime_resolve\n					      \
 _dl_runtime_resolve:\n							      \
+	.frame	$29, 40, $31\n						      \
 	.set noreorder\n						      \
-	# Save GP.\n						      \
+	# Save GP.\n							      \
 	move	$3, $28\n						      \
 	# Modify t9 ($25) so as to point .cpload instruction.\n		      \
-	addu	$25,8\n							      \
+	addu	$25, 8\n						      \
 	# Compute GP.\n							      \
 	.cpload $25\n							      \
 	.set reorder\n							      \
@@ -366,24 +374,20 @@ _dl_runtime_resolve:\n							      \
 	subu	$29, 40\n						      \
 	.cprestore 32\n							      \
 	sw	$15, 36($29)\n						      \
-	sw	$4, 12($29)\n						      \
-	sw	$5, 16($29)\n						      \
-	sw	$6, 20($29)\n						      \
-	sw	$7, 24($29)\n						      \
-	sw	$16, 28($29)\n						      \
-	move	$16, $29\n						      \
+	sw	$4, 16($29)\n						      \
+	sw	$5, 20($29)\n						      \
+	sw	$6, 24($29)\n						      \
+	sw	$7, 28($29)\n						      \
 	move	$4, $24\n						      \
 	move	$5, $15\n						      \
 	move	$6, $3\n						      \
 	move	$7, $2\n						      \
 	jal	__dl_runtime_resolve\n					      \
-	move	$29, $16\n						      \
 	lw	$31, 36($29)\n						      \
-	lw	$4, 12($29)\n						      \
-	lw	$5, 16($29)\n						      \
-	lw	$6, 20($29)\n						      \
-	lw	$7, 24($29)\n						      \
-	lw	$16, 28($29)\n						      \
+	lw	$4, 16($29)\n						      \
+	lw	$5, 20($29)\n						      \
+	lw	$6, 24($29)\n						      \
+	lw	$7, 28($29)\n						      \
 	addu	$29, 40\n						      \
 	move	$25, $2\n						      \
 	jr	$25\n							      \
@@ -580,15 +584,20 @@ elf_machine_got_rel (struct link_map *map, int lazy)
 
   got = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
 
-  /* got[0] is reserved. got[1] is also reserved for the dynamic object
-     generated by gnu ld. Skip these reserved entries from relocation.  */
-  i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
   n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
-  /* Add the run-time display to all local got entries if needed. */
-  if (__builtin_expect (map->l_addr != 0, 0))
+  /* The dynamic linker's local got entries have already been relocated.  */
+  if (map != &_dl_rtld_map)
     {
-      while (i < n)
-	got[i++] += map->l_addr;
+      /* got[0] is reserved. got[1] is also reserved for the dynamic object
+	 generated by gnu ld. Skip these reserved entries from relocation.  */
+      i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2 : 1;
+
+      /* Add the run-time display to all local got entries if needed. */
+      if (__builtin_expect (map->l_addr != 0, 0))
+	{
+	  while (i < n)
+	    got[i++] += map->l_addr;
+	}
     }
 
   /* Handle global got entries. */
@@ -661,7 +670,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	 of got[1] of a gnu object is set to identify gnu objects.
 	 Where we can store l for non gnu objects? XXX  */
       if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
-	got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
+	got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK
+	                       | (got[1] & ELF_MIPS_GNU_GOT1_OK));
       else
 	_dl_mips_gnu_objects = 0;
     }