diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | elf/rtld.c | 101 | ||||
-rw-r--r-- | linuxthreads/sysdeps/i386/tls.h | 20 | ||||
-rw-r--r-- | sysdeps/generic/dl-tls.c | 84 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 5 |
7 files changed, 175 insertions, 56 deletions
@@ -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 @@ -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 @@ -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 |