about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2002-07-20 01:14:41 +0000
committerUlrich Drepper <drepper@redhat.com>2002-07-20 01:14:41 +0000
commit739d440d2a748be4b0139d4e5e0a566098abfcec (patch)
tree395d06a998290892d7d92568471adee8e1e4824f /elf
parent9df63767d4078fdaf90307f5aa153422f7ec0722 (diff)
downloadglibc-739d440d2a748be4b0139d4e5e0a566098abfcec.tar.gz
glibc-739d440d2a748be4b0139d4e5e0a566098abfcec.tar.xz
glibc-739d440d2a748be4b0139d4e5e0a566098abfcec.zip
Update.
2002-07-19  Ulrich Drepper  <drepper@redhat.com>

	* configure.in: Add test for __thread support in compiler.
	* config.h.in: Add HAVE___THREAD.
	* Makefile (headers): Remove errno.h, sys/errno.h, and bits/errno.h.
	* include/sys/errno.h: Moved to...
	* stdlib/sys/errno.h: ...here.  New file.
	* stdlib/errno.h: New file.  Moved from...
	* include/errno.h: ...here.  Changed into an internal header defining
	libc-local things like __set_errno.
	* stdlib/Makefile (headers): Add errno.h, sys/errno.h, and
	bits/errno.h.
	* elf/dl-minimal.c: Include <tls.h>.  Define errno as thread-local
	variable if USE_TLS && HAVE___THREAD.  Don't define __errno_location
	either.
	* elf/rtld.c (_dl_start): Add code to initialize TLS for ld.so
	from...
	(_dl_start_final): ...here.  Add code to initialize tls elements from
	bootstrap_map.
	* sysdeps/generic/errno-loc.c: Define errno as thread-local variable
	if USE_TLS && HAVE___THREAD.
	* sysdeps/generic/bits/errno.h: Remove __set_errno definition.
	* sysdeps/mach/hurd/bits/errno.h: Likewise.
	* sysdeps/standalone/arm/bits/errno.h: Likewise.
	* sysdeps/standalone/bits/errno.h: Likewise.
	* sysdeps/unix/bsd/bsd4.4/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/aix/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/hpux/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/linux/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/linux/hppa/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/linux/mips/bits/errno.h: Likewise.
	* sysdeps/unix/sysv/sysv4/solaris2/bits/errno.h: Likewise.
	* sysdeps/i386/dl-machine.c (elf_machine_rel) [RTLD_BOOTSTRAP]: Don't
	use GL(dl_rtld_map), use map parameter.
	* sysdeps/sh/dl-machine.h (elf_machine_rela): Likewise.
	* sysdeps/unix/sysv/linux/i386/sysdep.S: Define errno in .tbss if
	USE_TLS && HAVE___THREAD.
	* sysdeps/unix/sysv/linux/i386/sysdep.h: Unify SETUP_PIC_REG
	definitions.  If USE_TLS && HAVE___THREAD store errooor value using
	TLS code sequence.
	* sysdeps/unix/sysv/linux/i386/i686/sysdep.h: Likewise.

	* sysdeps/unix/sysv/linux/getcwd.c: No real need to restore errno.
	* sysdeps/unix/sysv/linux/grantpt.c: Likewise.
	* sysdeps/unix/sysv/linux/internal_statvfs.c: Likewise.
	* sysdeps/unix/sysv/linux/msgctl.c: Likewise.
	* sysdeps/unix/sysv/linux/readv.c: Likewise.
	* sysdeps/unix/sysv/linux/writev.c: Likewise.
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-minimal.c6
-rw-r--r--elf/rtld.c207
2 files changed, 120 insertions, 93 deletions
diff --git a/elf/dl-minimal.c b/elf/dl-minimal.c
index 0f284d0a80..a6c1803b34 100644
--- a/elf/dl-minimal.c
+++ b/elf/dl-minimal.c
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <string.h>
+#include <tls.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/param.h>
@@ -354,8 +355,12 @@ const char INTUSE(_itoa_lower_digits)[16] attribute_hidden
   = "0123456789abcdef";
 
 
+
 #undef errno
 /* The 'errno' in ld.so is not exported.  */
+#if USE_TLS && HAVE___THREAD
+extern __thread int errno attribute_hidden;
+#else
 extern int errno attribute_hidden;
 
 int *
@@ -363,3 +368,4 @@ __errno_location (void)
 {
   return &errno;
 }
+#endif
diff --git a/elf/rtld.c b/elf/rtld.c
index 9ec250214b..85d8108813 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -130,9 +130,14 @@ _dl_start (void *arg)
 {
   struct link_map bootstrap_map;
   hp_timing_t start_time;
-#ifndef HAVE_BUILTIN_MEMSET
+#if !defined HAVE_BUILTIN_MEMSET || defined USE_TLS
   size_t cnt;
 #endif
+#ifdef USE_TLS
+  ElfW(Ehdr) *ehdr;
+  ElfW(Phdr) *phdr;
+  dtv_t initdtv[3];
+#endif
 
   /* This #define produces dynamic linking inline functions for
      bootstrap relocation instead of general-purpose relocation.  */
@@ -166,6 +171,97 @@ _dl_start (void *arg)
   bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
   elf_get_dynamic_info (&bootstrap_map);
 
+#if USE_TLS
+# ifndef HAVE___THREAD
+  /* Signal that we have not found TLS data so far.  */
+  bootstrap_map.l_tls_modid = 0;
+# endif
+
+  /* Get the dynamic linkers program header.  */
+  ehdr = (ElfW(Ehdr) *) bootstrap_map.l_addr;
+  phdr = (ElfW(Phdr) *) (bootstrap_map.l_addr + ehdr->e_phoff);
+  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
+    if (phdr[cnt].p_type == PT_TLS)
+      {
+	void *tlsblock;
+	size_t max_align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
+
+	bootstrap_map.l_tls_blocksize = phdr[cnt].p_memsz;
+	bootstrap_map.l_tls_align = phdr[cnt].p_align;
+	assert (bootstrap_map.l_tls_blocksize != 0);
+	bootstrap_map.l_tls_initimage_size = phdr[cnt].p_filesz;
+	bootstrap_map.l_tls_initimage = (void *) (bootstrap_map.l_addr
+						  + phdr[cnt].p_offset);
+
+	/* We can now allocate the initial TLS block.  This can happen
+	   on the stack.  We'll get the final memory later when we
+	   know all about the various objects loaded at startup
+	   time.  */
+# if TLS_TCB_AT_TP
+	tlsblock = alloca (roundup (bootstrap_map.l_tls_blocksize,
+				    TLS_INIT_TCB_ALIGN)
+			   + TLS_INIT_TCB_SIZE
+			   + max_align);
+# elif TLS_DTV_AT_TP
+	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE,
+				    bootstrap_map.l_tls_align)
+			   + bootstrap_map.l_tls_blocksize
+			   + max_align);
+# else
+	/* In case a model with a different layout for the TCB and DTV
+	   is defined add another #elif here and in the following #ifs.  */
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	/* Align the TLS block.  */
+	tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
+			     & ~(max_align - 1));
+
+	/* Initialize the dtv.  [0] is the length, [1] the generation
+	   counter.  */
+	initdtv[0].counter = 1;
+	initdtv[1].counter = 0;
+
+	/* Initialize the TLS block.  */
+# if TLS_TCB_AT_TP
+	initdtv[2].pointer = tlsblock;
+# elif TLS_DTV_AT_TP
+	bootstrap_map.l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
+					      bootstrap_map.l_tls_align);
+	initdtv[2].pointer = (char *) tlsblock + bootstrap_map.l_tls_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+	memset (__mempcpy (initdtv[2].pointer, bootstrap_map.l_tls_initimage,
+			   bootstrap_map.l_tls_initimage_size),
+		'\0', (bootstrap_map.l_tls_blocksize
+		       - bootstrap_map.l_tls_initimage_size));
+
+	/* Install the pointer to the dtv.  */
+
+	/* Initialize the thread pointer.  */
+# if TLS_TCB_AT_TP
+	bootstrap_map.l_tls_offset
+	  = roundup (bootstrap_map.l_tls_blocksize, TLS_INIT_TCB_ALIGN);
+
+	INSTALL_DTV ((char *) tlsblock + bootstrap_map.l_tls_offset,
+		     initdtv);
+
+	TLS_INIT_TP ((char *) tlsblock + bootstrap_map.l_tls_offset);
+# elif TLS_DTV_AT_TP
+	INSTALL_DTV (tlsblock, initdtv);
+	TLS_INIT_TP (tlsblock);
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+	/* So far this is module number one.  */
+	bootstrap_map.l_tls_modid = 1;
+
+	/* There can only be one PT_TLS entry.  */
+	break;
+      }
+#endif	/* use TLS */
+
 #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
   ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
 #endif
@@ -220,12 +316,6 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr)));
   extern char _begin[] attribute_hidden;
   extern char _end[] attribute_hidden;
-#ifdef USE_TLS
-  ElfW(Ehdr) *ehdr;
-  ElfW(Phdr) *phdr;
-  size_t cnt;
-  dtv_t initdtv[3];
-#endif
 
   if (HP_TIMING_AVAIL)
     {
@@ -247,96 +337,27 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
   GL(dl_rtld_map).l_mach = bootstrap_map_p->l_mach;
   GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
-
-#if HP_TIMING_AVAIL
-  HP_TIMING_NOW (GL(dl_cpuclock_offset));
-#endif
-
+  /* Copy the TLS related data if necessary.  */
 #if USE_TLS
-  /* Get the dynamic linkers program header.  */
-  ehdr = (ElfW(Ehdr) *) GL(dl_rtld_map).l_map_start;
-  phdr = (ElfW(Phdr) *) (GL(dl_rtld_map).l_map_start + ehdr->e_phoff);
-  for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
-    if (phdr[cnt].p_type == PT_TLS)
-      {
-	void *tlsblock;
-	size_t max_align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
-
-	GL(dl_rtld_map).l_tls_blocksize = phdr[cnt].p_memsz;
-	GL(dl_rtld_map).l_tls_align = phdr[cnt].p_align;
-	assert (GL(dl_rtld_map).l_tls_blocksize != 0);
-	GL(dl_rtld_map).l_tls_initimage_size = phdr[cnt].p_filesz;
-	GL(dl_rtld_map).l_tls_initimage = (void *) (GL(dl_rtld_map).l_map_start
-						    + phdr[cnt].p_offset);
-
-	/* We can now allocate the initial TLS block.  This can happen
-	   on the stack.  We'll get the final memory later when we
-	   know all about the various objects loaded at startup
-	   time.  */
-# if TLS_TCB_AT_TP
-	tlsblock = alloca (roundup (GL(dl_rtld_map).l_tls_blocksize,
-				    TLS_INIT_TCB_ALIGN)
-			   + TLS_INIT_TCB_SIZE
-			   + max_align);
-# elif TLS_DTV_AT_TP
-	tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE,
-				    GL(dl_rtld_map).l_tls_align)
-			   + GL(dl_rtld_map).l_tls_blocksize
-			   + max_align);
-# else
-	/* In case a model with a different layout for the TCB and DTV
-	   is defined add another #elif here and in the following #ifs.  */
-#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
-# endif
-	/* Align the TLS block.  */
-	tlsblock = (void *) (((uintptr_t) tlsblock + max_align - 1)
-			     & ~(max_align - 1));
-
-	/* Initialize the dtv.  [0] is the length, [1] the generation
-	   counter.  */
-	initdtv[0].counter = 1;
-	initdtv[1].counter = 0;
-
-	/* Initialize the TLS block.  */
-# if TLS_TCB_AT_TP
-	initdtv[2].pointer = tlsblock;
-# elif TLS_DTV_AT_TP
-	GL(dl_rtld_map).l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
-						GL(dl_rtld_map).l_tls_align);
-	initdtv[2].pointer = (char *) tlsblock + GL(dl_rtld_map).l_tls_offset;
-# else
-#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
-# endif
-	memset (__mempcpy (initdtv[1].pointer, GL(dl_rtld_map).l_tls_initimage,
-			   GL(dl_rtld_map).l_tls_initimage_size),
-		'\0', (GL(dl_rtld_map).l_tls_blocksize
-		       - GL(dl_rtld_map).l_tls_initimage_size));
-
-	/* Install the pointer to the dtv.  */
-
-	/* Initialize the thread pointer.  */
-# if TLS_TCB_AT_TP
-	GL(dl_rtld_map).l_tls_offset
-	  = roundup (GL(dl_rtld_map).l_tls_blocksize, TLS_INIT_TCB_ALIGN);
-
-	INSTALL_DTV ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset,
-		     initdtv);
-
-	TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset);
-# elif TLS_DTV_AT_TP
-	INSTALL_DTV (tlsblock, initdtv);
-	TLS_INIT_TP (tlsblock);
+# ifdef HAVE___THREAD
+  assert (bootstrap_map_p->l_tls_modid != 0);
 # else
-#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+  if (bootstrap_map_p->l_tls_modid != 0)
 # endif
+    {
+      GL(dl_rtld_map).l_tls_blocksize = bootstrap_map_p->l_tls_blocksize;
+      GL(dl_rtld_map).l_tls_align = bootstrap_map_p->l_tls_align;
+      GL(dl_rtld_map).l_tls_initimage_size
+	= bootstrap_map_p->l_tls_initimage_size;
+      GL(dl_rtld_map).l_tls_initimage = bootstrap_map_p->l_tls_initimage;
+      GL(dl_rtld_map).l_tls_offset = bootstrap_map_p->l_tls_offset;
+      GL(dl_rtld_map).l_tls_modid = 1;
+    }
+#endif
 
-	/* So far this is module number one.  */
-	GL(dl_rtld_map).l_tls_modid = 1;
-
-	/* There can only be one PT_TLS entry.  */
-	break;
-      }
-#endif	/* use TLS */
+#if HP_TIMING_AVAIL
+  HP_TIMING_NOW (GL(dl_cpuclock_offset));
+#endif
 
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work