aboutsummaryrefslogtreecommitdiff
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 c118ca3..b8aaa19 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 4d567b5..013bcb1 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 9c627c5..5d9a52b 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 a19fad2..2ebde45 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 ed5e634..4d701cc 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 5b4fdd8..eb9a37b 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 f049878..e65865c 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