summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rwxr-xr-xconfigure2
-rw-r--r--configure.in2
-rw-r--r--elf/rtld.c101
-rw-r--r--linuxthreads/sysdeps/i386/tls.h20
-rw-r--r--sysdeps/generic/dl-tls.c84
-rw-r--r--sysdeps/generic/ldsodefs.h5
7 files changed, 175 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index c118ca341b..b8aaa19a25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2002-02-08  Ulrich Drepper  <drepper@redhat.com>
+
+	* elf/rtld.c (_dl_start_final): Install DTV explicitly.
+	(dl_main): Move dtv/static TLS handling before relocation.
+	Unconditionally call _dl_tlsoffset.  Call _dl_allocate_tls and
+	TLS_INIT_TP to allocate and install the dtv/static TLS block.
+	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): If no object
+	so far uses TLS initialize GL(dl_tls_static_size) and
+	GL(dl_tls_static_align) to account for the TCB.
+	(_dl_allocate_tls): New function.
+	* sysdeps/generic/ldsodefs.h (rtld_global): Add
+	_dl_initial_dtv_malloced.
+
+	* configure.in: Test for __builtin_memset more realistically.
+
+	* csu/version.c (banner): If TLS support available say so.
+
 2002-02-04  H.J. Lu  <hjl@gnu.org>
 
 	* sysdeps/mips/dl-machine.h (elf_machine_matches_host): Use
diff --git a/configure b/configure
index 4d567b5491..013bcb1d8b 100755
--- a/configure
+++ b/configure
@@ -3396,7 +3396,7 @@ else
   cat > conftest.c <<\EOF
 void zero (void *x)
 {
-  __builtin_memset (x, 0, 4);
+  __builtin_memset (x, 0, 1000);
 }
 EOF
 if { ac_try='${CC-cc} -O3 -S conftest.c -o - | fgrep "memset" > /dev/null'; { (eval echo configure:3403: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; };
diff --git a/configure.in b/configure.in
index 9c627c5611..5d9a52bda4 100644
--- a/configure.in
+++ b/configure.in
@@ -1403,7 +1403,7 @@ AC_CACHE_CHECK(for __builtin_memset, libc_cv_gcc_builtin_memset, [dnl
 cat > conftest.c <<\EOF
 void zero (void *x)
 {
-  __builtin_memset (x, 0, 4);
+  __builtin_memset (x, 0, 1000);
 }
 EOF
 dnl
diff --git a/elf/rtld.c b/elf/rtld.c
index a19fad24a4..2ebde4530a 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -309,14 +309,20 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
 		'\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);
-	TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset,
+
+	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
-	TLS_INIT_TP (tlsblock, initdtv);
+	INSTALL_DTV (tlsblock, initdtv);
+	TLS_INIT_TP (tlsblock);
 # else
 #  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
 # endif
@@ -477,6 +483,9 @@ dl_main (const ElfW(Phdr) *phdr,
   hp_timing_t stop;
   hp_timing_t diff;
 #endif
+#ifdef USE_TLS
+  void *tcbp;
+#endif
 
   /* Process the environment variable which control the behaviour.  */
   process_envvars (&mode);
@@ -1169,6 +1178,53 @@ of this helper program; chances are you did not intend to run this program.\n\
       _exit (0);
     }
 
+#ifdef USE_TLS
+  /* Now it is time to determine the layout of the static TLS block
+     and allocate it for the initial thread.  Note that we always
+     allocate the static block, we never defer it even if no
+     DF_STATIC_TLS bit is set.  The reason is that we know glibc will
+     use the static model.  First add the dynamic linker to the list
+     if it also uses TLS.  */
+  if (GL(dl_rtld_map).l_tls_blocksize != 0)
+    {
+      /* At to the list.  */
+      if (GL(dl_initimage_list) == NULL)
+	GL(dl_initimage_list) = GL(dl_rtld_map).l_tls_nextimage
+	  = GL(dl_rtld_map).l_tls_previmage = &GL(dl_rtld_map);
+	  else
+	    {
+	      GL(dl_rtld_map).l_tls_nextimage
+		= GL(dl_initimage_list)->l_tls_nextimage;
+	      GL(dl_rtld_map).l_tls_nextimage->l_tls_previmage
+		= &GL(dl_rtld_map);
+	      GL(dl_rtld_map).l_tls_previmage = GL(dl_initimage_list);
+	      GL(dl_rtld_map).l_tls_previmage->l_tls_nextimage
+		= &GL(dl_rtld_map);
+	      GL(dl_initimage_list) = &GL(dl_rtld_map);
+	    }
+
+      /* Assign a module ID.  */
+      GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
+    }
+
+  /* Computer the TLS offsets for the various blocks.  We call this
+     function even if none of the modules available at startup time
+     uses TLS to initialize some variables.  */
+    _dl_determine_tlsoffset (GL(dl_initimage_list));
+
+  /* Construct the static TLS block and the dtv for the initial
+     thread.  For some platforms this will include allocating memory
+     for the thread descriptor.  The memory for the TLS block will
+     never be freed.  It should be allocated accordingly.  The dtv
+     array can be changed if dynamic loading requires it.  */
+  tcbp = _dl_allocate_tls ();
+  if (tcbp == NULL)
+    _dl_fatal_printf ("cannot allocate TLS data structures for inital thread");
+
+  /* And finally install it for the main thread.  */
+  TLS_INIT_TP (tcbp);
+#endif
+
   if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]
       && ! __builtin_expect (GL(dl_profile) != NULL, 0))
     {
@@ -1333,47 +1389,6 @@ of this helper program; chances are you did not intend to run this program.\n\
      we need it in the memory handling later.  */
   GL(dl_initial_searchlist) = *GL(dl_main_searchlist);
 
-#ifdef USE_TLS
-  /* Now it is time to determine the layout of the static TLS block
-     and allocate it for the initial thread.  Note that we always
-     allocate the static block, we never defer it even if no
-     DF_STATIC_TLS bit is set.  The reason is that we know glibc will
-     use the static model.  First add the dynamic linker to the list
-     if it also uses TLS.  */
-  if (GL(dl_rtld_map).l_tls_blocksize != 0)
-    {
-      /* At to the list.  */
-      if (GL(dl_initimage_list) == NULL)
-	GL(dl_initimage_list) = GL(dl_rtld_map).l_tls_nextimage
-	  = GL(dl_rtld_map).l_tls_previmage = &GL(dl_rtld_map);
-	  else
-	    {
-	      GL(dl_rtld_map).l_tls_nextimage
-		= GL(dl_initimage_list)->l_tls_nextimage;
-	      GL(dl_rtld_map).l_tls_nextimage->l_tls_previmage
-		= &GL(dl_rtld_map);
-	      GL(dl_rtld_map).l_tls_previmage = GL(dl_initimage_list);
-	      GL(dl_rtld_map).l_tls_previmage->l_tls_nextimage
-		= &GL(dl_rtld_map);
-	      GL(dl_initimage_list) = &GL(dl_rtld_map);
-	    }
-
-      /* Assign a module ID.  */
-      GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
-    }
-
-  if (GL(dl_initimage_list) != NULL)
-    /* This means we actually have some modules which use TLS.
-       Computer the TLS offsets for the various blocks.  */
-    _dl_determine_tlsoffset (GL(dl_initimage_list)->l_tls_nextimage);
-
-  /* Construct the static TLS block and the dtv for the initial
-     thread.  For some platforms this will include allocating memory
-     for the thread descriptor.  The memory for the TLS block will
-     never be freed.  It should be allocated accordingly.  The dtv
-     array can be changed if dynamic loading requires it.  */
-#endif
-
   {
     /* Initialize _r_debug.  */
     struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h
index ed5e634a82..4d701cc6e8 100644
--- a/linuxthreads/sysdeps/i386/tls.h
+++ b/linuxthreads/sysdeps/i386/tls.h
@@ -42,7 +42,7 @@ typedef struct
 
 
 /* We can support TLS only if the floating-stack support is available.  */
-#ifdef HAVE_TLS_SUPPORT
+#if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT
 
 /* Get system call information.  */
 # include <sysdep.h>
@@ -66,10 +66,15 @@ typedef struct
    thread pointer points to is unspecified.  Allocate the TCB there.  */
 # define TLS_TCB_AT_TP	1
 
+
+/* Install the dtv pointer.  */
+# define INSTALL_DTV(descr, dtvp) \
+  ((tcbhead_t *) descr)->dtv = dtvp
+
 /* Code to initially initialize the thread pointer.  This might need
    special attention since 'errno' is not yet available and if the
    operation can cause a failure 'errno' must not be touched.  */
-# define TLS_INIT_TP(descr, dtvp) \
+# define TLS_INIT_TP(descr) \
   do {									      \
     void *_descr = (descr);						      \
     struct modify_ldt_ldt_s ldt_entry =					      \
@@ -78,7 +83,6 @@ typedef struct
     tcbhead_t *head = _descr;						      \
 									      \
     head->tcb = _descr;							      \
-    head->dtv = dtvp;							      \
 									      \
     asm ("pushl %%ebx\n\t"						      \
 	 "movl $1, %%ebx\n\t"						      \
@@ -94,16 +98,10 @@ typedef struct
 
 
 /* Return the address of the dtv for the current thread.  */
-# if FLOATING_STACKS
-#  define THREAD_DTV() \
+# define THREAD_DTV() \
   ({ struct _pthread_descr_struct *__descr;				      \
      THREAD_GETMEM (__descr, p_header.data.dtvp); })
-# else
-#  define THREAD_DTV() \
-  ({ struct _pthread_descr_struct *__descr = thread_self ();		      \
-     THREAD_GETMEM (__descr, p_header.data.dtvp); })
-# endif
 
-#endif	/* HAVE_TLS_SUPPORT */
+#endif	/* FLOATING_STACKS && HAVE_TLS_SUPPORT */
 
 #endif	/* tls.h */
diff --git a/sysdeps/generic/dl-tls.c b/sysdeps/generic/dl-tls.c
index 5b4fdd8cf1..eb9a37bf95 100644
--- a/sysdeps/generic/dl-tls.c
+++ b/sysdeps/generic/dl-tls.c
@@ -18,6 +18,7 @@
    02111-1307 USA.  */
 
 #include <assert.h>
+#include <stdlib.h>
 
 #include <tls.h>
 
@@ -84,6 +85,16 @@ _dl_determine_tlsoffset (struct link_map *firstp)
   size_t max_align = 0;
   size_t offset;
 
+  if (GL(dl_initimage_list) == NULL)
+    {
+      /* None of the objects used at startup time uses TLS.  We still
+	 have to allocate the TCB adn dtv.  */
+      GL(dl_tls_static_size) = TLS_TCB_SIZE;
+      GL(dl_tls_static_align) = TLS_TCB_ALIGN;
+
+      return;
+    }
+
 # if TLS_TCB_AT_TP
   /* We simply start with zero.  */
   offset = 0;
@@ -149,6 +160,79 @@ _dl_determine_tlsoffset (struct link_map *firstp)
 }
 
 
+void *
+internal_function
+_dl_allocate_tls (void)
+{
+  void *result;
+  dtv_t *dtv;
+
+  /* Allocate a correctly aligned chunk of memory.  */
+  /* XXX For now */
+  assert (GL(dl_tls_static_align) <= GL(dl_pagesize));
+#ifdef MAP_ANON
+# define _dl_zerofd (-1)
+#else
+# define _dl_zerofd GL(dl_zerofd)
+  if ((dl_zerofd) == -1)
+    GL(dl_zerofd) = _dl_sysdep_open_zero_fill ();
+# define MAP_ANON 0
+#endif
+  result = __mmap (0, GL(dl_tls_static_size), PROT_READ|PROT_WRITE,
+		   MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
+
+  dtv = (dtv_t *) malloc ((GL(dl_tls_max_dtv_idx) + 1) * sizeof (dtv_t));
+  if (result != MAP_FAILED && dtv != NULL)
+    {
+      struct link_map *runp;
+
+# if TLS_TCB_AT_TP
+      /* The TCB follows the TLS blocks.  */
+      result = (char *) result + GL(dl_tls_static_size) - TLS_TCB_SIZE;
+# endif
+
+      /* XXX Fill in an correct generation number.  */
+      dtv[0].counter = 0;
+
+      /* Initialize the memory from the initialization image list and clear
+	 the BSS parts.  */
+      if (GL(dl_initimage_list) != NULL)
+	{
+	  runp = GL(dl_initimage_list)->l_tls_nextimage;
+	  do
+	    {
+	      assert (runp->l_tls_modid > 0);
+	      assert (runp->l_tls_modid <= GL(dl_tls_max_dtv_idx));
+# if TLS_TCB_AT_TP
+	      dtv[runp->l_tls_modid].pointer = result - runp->l_tls_offset;
+# elif TLS_DTV_AT_TP
+	      dtv[runp->l_tls_modid].pointer = result + runp->l_tls_offset;
+# else
+#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+	      memset (__mempcpy (dtv[runp->l_tls_modid].pointer,
+				 runp->l_tls_initimage,
+				 runp->l_tls_initimage_size),
+		      '\0',
+		      runp->l_tls_blocksize - runp->l_tls_initimage_size);
+	    }
+	  while ((runp = runp->l_tls_nextimage) != NULL);
+	}
+
+      /* Add the dtv to the thread data structures.  */
+      INSTALL_DTV (result, dtv);
+    }
+  else if (result != NULL)
+    {
+      free (result);
+      result = NULL;
+    }
+
+  return result;
+}
+
+
 /* The __tls_get_addr function has two basic forms which differ in the
    arguments.  The IA-64 form takes two parameters, the module ID and
    offset.  The form used, among others, on IA-32 takes a reference to
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index f049878cbd..e65865c068 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -303,6 +303,9 @@ struct rtld_global
   EXTERN size_t _dl_tls_static_size;
   /* Alignment requirement of the static TLS block.  */
   EXTERN size_t _dl_tls_static_align;
+
+  /* True if the dtv for the initial thread was malloc()ed.  */
+  EXTERN bool _dl_initial_dtv_malloced;
 #endif
 
   /* Name of the shared object to be profiled (if any).  */
@@ -666,6 +669,8 @@ extern size_t _dl_next_tls_modid (void) internal_function;
 extern void _dl_determine_tlsoffset (struct link_map *firstp)
      internal_function;
 
+/* Allocate memory for static TLS block and dtv.  */
+extern void *_dl_allocate_tls (void) internal_function;
 
 __END_DECLS