about summary refs log tree commit diff
path: root/sysdeps/s390/s390-32
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/s390/s390-32')
-rw-r--r--sysdeps/s390/s390-32/bits/link.h5
-rw-r--r--sysdeps/s390/s390-32/dl-machine.h17
2 files changed, 21 insertions, 1 deletions
diff --git a/sysdeps/s390/s390-32/bits/link.h b/sysdeps/s390/s390-32/bits/link.h
new file mode 100644
index 0000000000..962cf56851
--- /dev/null
+++ b/sysdeps/s390/s390-32/bits/link.h
@@ -0,0 +1,5 @@
+struct link_map_machine
+  {
+    Elf32_Addr plt; /* Address of .plt + 0x2c */
+    Elf32_Addr gotplt; /* Address of .got + 0x0c */
+  };
diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h
index f72651fba0..fc80877428 100644
--- a/sysdeps/s390/s390-32/dl-machine.h
+++ b/sysdeps/s390/s390-32/dl-machine.h
@@ -92,6 +92,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	 and then jump to _GLOBAL_OFFSET_TABLE[2].  */
       Elf32_Addr *got;
       got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
+      /* If a library is prelinked but we have to relocate anyway,
+	 we have to be able to undo the prelinking of .got.plt.
+	 The prelinker saved us here address of .plt + 0x2c.  */
+      if (got[1])
+	{
+	  l->l_mach.plt = got[1] + l->l_addr;
+	  l->l_mach.gotplt = (Elf32_Addr) &got[3];
+	}
       got[1] = (Elf32_Addr) l;	/* Identify this shared object.  */
 
       /* The got[2] entry contains the address of a function which gets
@@ -454,7 +462,14 @@ elf_machine_lazy_rel (struct link_map *map,
   const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == R_390_JMP_SLOT, 1))
-    *reloc_addr += l_addr;
+    {
+      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+	*reloc_addr += l_addr;
+      else
+	*reloc_addr =
+	  map->l_mach.plt
+	  + (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 8;
+    }
   else
     _dl_reloc_bad_type (map, r_type, 1);
 }