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.
This commit is contained in:
Ulrich Drepper 2002-02-09 01:41:44 +00:00
parent 013aafb7d0
commit a52d15621f
7 changed files with 175 additions and 56 deletions

View File

@ -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> 2002-02-04 H.J. Lu <hjl@gnu.org>
* sysdeps/mips/dl-machine.h (elf_machine_matches_host): Use * sysdeps/mips/dl-machine.h (elf_machine_matches_host): Use

2
configure vendored
View File

@ -3396,7 +3396,7 @@ else
cat > conftest.c <<\EOF cat > conftest.c <<\EOF
void zero (void *x) void zero (void *x)
{ {
__builtin_memset (x, 0, 4); __builtin_memset (x, 0, 1000);
} }
EOF 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; }; }; 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; }; };

View File

@ -1403,7 +1403,7 @@ AC_CACHE_CHECK(for __builtin_memset, libc_cv_gcc_builtin_memset, [dnl
cat > conftest.c <<\EOF cat > conftest.c <<\EOF
void zero (void *x) void zero (void *x)
{ {
__builtin_memset (x, 0, 4); __builtin_memset (x, 0, 1000);
} }
EOF EOF
dnl dnl

View File

@ -309,14 +309,20 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
'\0', (GL(dl_rtld_map).l_tls_blocksize '\0', (GL(dl_rtld_map).l_tls_blocksize
- GL(dl_rtld_map).l_tls_initimage_size)); - GL(dl_rtld_map).l_tls_initimage_size));
/* Install the pointer to the dtv. */
/* Initialize the thread pointer. */ /* Initialize the thread pointer. */
# if TLS_TCB_AT_TP # if TLS_TCB_AT_TP
GL(dl_rtld_map).l_tls_offset GL(dl_rtld_map).l_tls_offset
= roundup (GL(dl_rtld_map).l_tls_blocksize, TLS_INIT_TCB_ALIGN); = 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); initdtv);
TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset);
# elif TLS_DTV_AT_TP # elif TLS_DTV_AT_TP
TLS_INIT_TP (tlsblock, initdtv); INSTALL_DTV (tlsblock, initdtv);
TLS_INIT_TP (tlsblock);
# else # else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif # endif
@ -477,6 +483,9 @@ dl_main (const ElfW(Phdr) *phdr,
hp_timing_t stop; hp_timing_t stop;
hp_timing_t diff; hp_timing_t diff;
#endif #endif
#ifdef USE_TLS
void *tcbp;
#endif
/* Process the environment variable which control the behaviour. */ /* Process the environment variable which control the behaviour. */
process_envvars (&mode); process_envvars (&mode);
@ -1169,6 +1178,53 @@ of this helper program; chances are you did not intend to run this program.\n\
_exit (0); _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)] if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]
&& ! __builtin_expect (GL(dl_profile) != NULL, 0)) && ! __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. */ we need it in the memory handling later. */
GL(dl_initial_searchlist) = *GL(dl_main_searchlist); 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. */ /* Initialize _r_debug. */
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr); struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);

View File

@ -42,7 +42,7 @@ typedef struct
/* We can support TLS only if the floating-stack support is available. */ /* 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. */ /* Get system call information. */
# include <sysdep.h> # include <sysdep.h>
@ -66,10 +66,15 @@ typedef struct
thread pointer points to is unspecified. Allocate the TCB there. */ thread pointer points to is unspecified. Allocate the TCB there. */
# define TLS_TCB_AT_TP 1 # 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 /* Code to initially initialize the thread pointer. This might need
special attention since 'errno' is not yet available and if the special attention since 'errno' is not yet available and if the
operation can cause a failure 'errno' must not be touched. */ operation can cause a failure 'errno' must not be touched. */
# define TLS_INIT_TP(descr, dtvp) \ # define TLS_INIT_TP(descr) \
do { \ do { \
void *_descr = (descr); \ void *_descr = (descr); \
struct modify_ldt_ldt_s ldt_entry = \ struct modify_ldt_ldt_s ldt_entry = \
@ -78,7 +83,6 @@ typedef struct
tcbhead_t *head = _descr; \ tcbhead_t *head = _descr; \
\ \
head->tcb = _descr; \ head->tcb = _descr; \
head->dtv = dtvp; \
\ \
asm ("pushl %%ebx\n\t" \ asm ("pushl %%ebx\n\t" \
"movl $1, %%ebx\n\t" \ "movl $1, %%ebx\n\t" \
@ -94,16 +98,10 @@ typedef struct
/* Return the address of the dtv for the current thread. */ /* Return the address of the dtv for the current thread. */
# if FLOATING_STACKS # define THREAD_DTV() \
# define THREAD_DTV() \
({ struct _pthread_descr_struct *__descr; \ ({ struct _pthread_descr_struct *__descr; \
THREAD_GETMEM (__descr, p_header.data.dtvp); }) 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 */ #endif /* tls.h */

View File

@ -18,6 +18,7 @@
02111-1307 USA. */ 02111-1307 USA. */
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include <tls.h> #include <tls.h>
@ -84,6 +85,16 @@ _dl_determine_tlsoffset (struct link_map *firstp)
size_t max_align = 0; size_t max_align = 0;
size_t offset; 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 # if TLS_TCB_AT_TP
/* We simply start with zero. */ /* We simply start with zero. */
offset = 0; 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 /* 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 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 offset. The form used, among others, on IA-32 takes a reference to

View File

@ -303,6 +303,9 @@ struct rtld_global
EXTERN size_t _dl_tls_static_size; EXTERN size_t _dl_tls_static_size;
/* Alignment requirement of the static TLS block. */ /* Alignment requirement of the static TLS block. */
EXTERN size_t _dl_tls_static_align; 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 #endif
/* Name of the shared object to be profiled (if any). */ /* 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) extern void _dl_determine_tlsoffset (struct link_map *firstp)
internal_function; internal_function;
/* Allocate memory for static TLS block and dtv. */
extern void *_dl_allocate_tls (void) internal_function;
__END_DECLS __END_DECLS