about summary refs log tree commit diff
path: root/sysdeps/i386/dl-machine.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/i386/dl-machine.h')
-rw-r--r--sysdeps/i386/dl-machine.h45
1 files changed, 40 insertions, 5 deletions
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index fa6ce04d99..8f17441dd8 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -410,8 +410,6 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	  *reloc_addr = value;
 	  break;
 
-	  /* XXX Remove TLS relocations which are not needed.  */
-
 #ifdef USE_TLS
 	case R_386_TLS_DTPMOD32:
 # ifdef RTLD_BOOTSTRAP
@@ -432,7 +430,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	  /* During relocation all TLS symbols are defined and used.
 	     Therefore the offset is already correct.  */
 	  if (sym != NULL)
-	    *reloc_addr += sym->st_value;
+	    *reloc_addr = sym->st_value;
 # endif
 	  break;
 	case R_386_TLS_TPOFF32:
@@ -444,7 +442,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	     It is a positive value which will be subtracted from the
 	     thread pointer.  To get the variable position in the TLS
 	     block we subtract the offset from that of the TLS block.  */
-	  if (sym_map != NULL && sym != NULL)
+	  if (sym != NULL)
 	    *reloc_addr += sym_map->l_tls_offset - sym->st_value;
 # endif
 	  break;
@@ -516,7 +514,44 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 	case R_386_PC32:
 	  *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
 	  break;
-	  /* XXX Do we have to handle the TLS relocation here?  */
+
+#ifdef USE_TLS
+	case R_386_TLS_DTPMOD32:
+# ifdef RTLD_BOOTSTRAP
+	  /* During startup the dynamic linker is always the module
+	     with index 1.
+	     XXX If this relocation is necessary move before RESOLVE
+	     call.  */
+	  *reloc_addr = 1;
+# else
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+# endif
+	  break;
+	case R_386_TLS_DTPOFF32:
+# ifndef RTLD_BOOTSTRAP
+	  /* During relocation all TLS symbols are defined and used.
+	     Therefore the offset is already correct.  */
+	  *reloc_addr = (sym == NULL ? 0 : sym->st_value) + reloc->r_addend;
+# endif
+	  break;
+	case R_386_TLS_TPOFF32:
+	  /* The offset is positive, backward from the thread pointer.  */
+# ifdef RTLD_BOOTSTRAP
+	  *reloc_addr = map->l_tls_offset - sym->st_value + reloc->r_addend;
+# else
+	  /* We know the offset of object the symbol is contained in.
+	     It is a positive value which will be subtracted from the
+	     thread pointer.  To get the variable position in the TLS
+	     block we subtract the offset from that of the TLS block.  */
+	  *reloc_addr
+	    = (sym == NULL ? 0 : sym_map->l_tls_offset - sym->st_value)
+	      + reloc->r_addend;
+# endif
+	  break;
+#endif	/* use TLS */
 	default:
 	  /* We add these checks in the version to relocate ld.so only
 	     if we are still debugging.  */