* sysdeps/generic/ldsodefs.h (struct rtld_global): Move all [USE_TLS]

members to the end, so a libpthread compiled with !USE_TLS will still
	find other members properly.

	* sysdeps/i386/i486/bits/string.h (__strcpy_g): Add dummy output
	operand for DEST memory.  Fix dummy input operand to use SRC.
	Reported by Davin McCall <davmac@ozonline.com.au>.

	* sysdeps/generic/libc-tls.c (__libc_setup_tls): Account for TCB
	alignment when initializing the DTV entry.

	* elf/dl-load.c (_dl_map_object_from_fd): If we hit a TLS segment
	when TLS has not been set up, try to set it up if we can.
	* elf/tst-tls4.c: Revert last change.
	* elf/tst-tls5.c: Likewise.
	* elf/tst-tls6.c: Likewise.
	* elf/tst-tls7.c: Likewise.
	* elf/tst-tls8.c: Likewise.
	* elf/tst-tls9.c: Likewise.

	* sysdeps/generic/dl-tls.c [SHARED] (_dl_tls_setup): New function.
	* sysdeps/generic/ldsodefs.h: Declare it.
	* elf/Versions (ld: GLIBC_PRIVATE): Add it.
	* sysdeps/generic/libc-tls.c (init_slotinfo): New static inline
	function, broken out of __libc_setup_tls.
	(init_static_tls): Likewise.
	(__libc_setup_tls): Call them.
	(_dl_tls_setup): New function, uses new subroutines.

	* elf/dl-close.c (free_slotinfo): Make argument pointer to pointer.
	Clear the pointer when returning true.
	(libc_freeres_fn) [SHARED]: If GL(dl_initial_dtv) is null, free the
	first element of the slotinfo list too.

	* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Define only if
	[SHARED].

	* sysdeps/generic/ldsodefs.h (_dl_next_tls_modid): Declare as hidden.
	(_dl_determine_tlsoffset): Likewise.

	* elf/rtld.c (_dl_initial_error_catch_tsd): Renamed from
	startup_error_tsd, made global.
	(dl_main): Update initialization.
	* elf/dl-tsd.c: Likewise.
	* sysdeps/generic/ldsodefs.h: Declare it.
This commit is contained in:
Roland McGrath 2002-12-04 12:30:40 +00:00
parent 68dc80ca28
commit 216455bc28
15 changed files with 215 additions and 120 deletions

View File

@ -1,3 +1,51 @@
2002-12-04 Roland McGrath <roland@redhat.com>
* sysdeps/generic/ldsodefs.h (struct rtld_global): Move all [USE_TLS]
members to the end, so a libpthread compiled with !USE_TLS will still
find other members properly.
* sysdeps/i386/i486/bits/string.h (__strcpy_g): Add dummy output
operand for DEST memory. Fix dummy input operand to use SRC.
Reported by Davin McCall <davmac@ozonline.com.au>.
* sysdeps/generic/libc-tls.c (__libc_setup_tls): Account for TCB
alignment when initializing the DTV entry.
* elf/dl-load.c (_dl_map_object_from_fd): If we hit a TLS segment
when TLS has not been set up, try to set it up if we can.
* elf/tst-tls4.c: Revert last change.
* elf/tst-tls5.c: Likewise.
* elf/tst-tls6.c: Likewise.
* elf/tst-tls7.c: Likewise.
* elf/tst-tls8.c: Likewise.
* elf/tst-tls9.c: Likewise.
* sysdeps/generic/dl-tls.c [SHARED] (_dl_tls_setup): New function.
* sysdeps/generic/ldsodefs.h: Declare it.
* elf/Versions (ld: GLIBC_PRIVATE): Add it.
* sysdeps/generic/libc-tls.c (init_slotinfo): New static inline
function, broken out of __libc_setup_tls.
(init_static_tls): Likewise.
(__libc_setup_tls): Call them.
(_dl_tls_setup): New function, uses new subroutines.
* elf/dl-close.c (free_slotinfo): Make argument pointer to pointer.
Clear the pointer when returning true.
(libc_freeres_fn) [SHARED]: If GL(dl_initial_dtv) is null, free the
first element of the slotinfo list too.
* sysdeps/generic/dl-tls.c (_dl_determine_tlsoffset): Define only if
[SHARED].
* sysdeps/generic/ldsodefs.h (_dl_next_tls_modid): Declare as hidden.
(_dl_determine_tlsoffset): Likewise.
* elf/rtld.c (_dl_initial_error_catch_tsd): Renamed from
startup_error_tsd, made global.
(dl_main): Update initialization.
* elf/dl-tsd.c: Likewise.
* sysdeps/generic/ldsodefs.h: Declare it.
2002-12-03 Ulrich Drepper <drepper@redhat.com>
* manual/texinfo.tex: Update from latest upstream version.

View File

@ -51,6 +51,6 @@ ld {
_dl_unload_cache;
_rtld_global; _dl_tls_symaddr; _dl_allocate_tls; _dl_deallocate_tls;
_dl_get_tls_static_info; _dl_allocate_tls_init;
_dl_get_origin;
_dl_get_origin; _dl_tls_setup;
}
}

View File

@ -429,28 +429,28 @@ libc_hidden_def (_dl_close)
#ifdef USE_TLS
static bool
free_slotinfo (struct dtv_slotinfo_list *elemp)
free_slotinfo (struct dtv_slotinfo_list **elemp)
{
size_t cnt;
if (elemp == NULL)
if (*elemp == NULL)
/* Nothing here, all is removed (or there never was anything). */
return true;
if (!free_slotinfo (elemp->next))
if (!free_slotinfo (&(*elemp)->next))
/* We cannot free the entry. */
return false;
/* The least we could do is remove next element (if there was any). */
elemp->next = NULL;
/* That cleared our next pointer for us. */
for (cnt = 0; cnt < elemp->len; ++cnt)
if (elemp->slotinfo[cnt].map != NULL)
for (cnt = 0; cnt < (*elemp)->len; ++cnt)
if ((*elemp)->slotinfo[cnt].map != NULL)
/* Still used. */
return false;
/* We can remove the list element. */
free (elemp);
free (*elemp);
*elemp = NULL;
return true;
}
@ -479,12 +479,17 @@ libc_freeres_fn (free_mem)
if (USE___THREAD || GL(dl_tls_dtv_slotinfo_list) != NULL)
{
/* Free the memory allocated for the dtv slotinfo array. We can do
this only if all modules which used this memory are unloaded.
Also, the first element of the list does not have to be
deallocated. It was allocated in the dynamic linker (i.e., with
a different malloc). */
if (free_slotinfo (GL(dl_tls_dtv_slotinfo_list)->next))
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
this only if all modules which used this memory are unloaded. */
# ifdef SHARED
if (GL(dl_initial_dtv) == NULL)
/* There was no initial TLS setup, it was set up later when
it used the normal malloc. */
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list));
# endif
/* The first element of the list does not have to be deallocated.
It was allocated in the dynamic linker (i.e., with a different
malloc), and in the static library it's in .bss space. */
free_slotinfo (&GL(dl_tls_dtv_slotinfo_list)->next);
}
#endif
}

View File

@ -946,32 +946,64 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
/* Nothing to do for an empty segment. */
break;
l->l_tls_blocksize = ph->p_memsz;
l->l_tls_align = ph->p_align;
l->l_tls_initimage_size = ph->p_filesz;
/* Since we don't know the load address yet only store the
offset. We will adjust it later. */
l->l_tls_initimage = (void *) ph->p_vaddr;
/* If not loading the initial set of shared libraries,
check whether we should permit loading a TLS segment. */
if (
# ifdef SHARED
__builtin_expect (l->l_type == lt_library, 1) ||
# endif
if (__builtin_expect (l->l_type == lt_library, 1)
/* If GL(dl_tls_max_dtv_idx) == 0, then rtld.c did not
set up TLS data structures, so don't use them now. */
__builtin_expect (GL(dl_tls_max_dtv_idx), 1) != 0)
|| __builtin_expect (GL(dl_tls_max_dtv_idx), 1) != 0)
{
l->l_tls_blocksize = ph->p_memsz;
l->l_tls_align = ph->p_align;
l->l_tls_initimage_size = ph->p_filesz;
/* Since we don't know the load address yet only store the
offset. We will adjust it later. */
l->l_tls_initimage = (void *) ph->p_vaddr;
/* Assign the next available module ID. */
l->l_tls_modid = _dl_next_tls_modid ();
break;
}
# ifdef SHARED
if (l->l_prev == NULL)
/* We are loading the executable itself when the dynamic linker
was executed directly. The setup will happen later. */
break;
/* In a static binary there is no way to tell if we dynamically
loaded libpthread. */
if (GL(dl_error_catch_tsd) == &_dl_initial_error_catch_tsd)
# endif
{
/* We have not yet loaded libpthread.
We can do the TLS setup right now! */
void *tcb;
/* The first call allocates TLS bookkeeping data structures.
Then we allocate the TCB for the initial thread. */
if (__builtin_expect (_dl_tls_setup (), 0)
|| __builtin_expect ((tcb = _dl_allocate_tls (NULL)) == NULL,
0))
{
errval = ENOMEM;
errstring = N_("\
cannot allocate TLS data structures for initial thread");
goto call_lose;
}
/* Now we install the TCB in the thread register. */
if (__builtin_expect (TLS_INIT_TP (tcb, 0), 0) != -1)
{
/* Now we are all good. */
l->l_tls_modid = ++GL(dl_tls_max_dtv_idx);
break;
}
/* The kernel is too old or somesuch. */
_dl_deallocate_tls (tcb, 1);
}
#endif
/* Uh-oh, the binary expects TLS support but we cannot

View File

@ -27,8 +27,8 @@
/* _dl_error_catch_tsd points to this for the single-threaded case.
It's reset by the thread library for multithreaded programs
if we're not using __thread. */
static void ** __attribute__ ((const))
startup_error_tsd (void)
void ** __attribute__ ((const))
_dl_initial_error_catch_tsd (void)
{
# if USE___THREAD
static __thread void *data;
@ -38,7 +38,7 @@ startup_error_tsd (void)
return &data;
}
void **(*_dl_error_catch_tsd) (void) __attribute__ ((const))
= &startup_error_tsd;
= &_dl_initial_error_catch_tsd;
# elif USE___THREAD

View File

@ -563,8 +563,8 @@ match_version (const char *string, struct link_map *map)
#ifdef _LIBC_REENTRANT
/* _dl_error_catch_tsd points to this for the single-threaded case.
It's reset by the thread library for multithreaded programs. */
static void ** __attribute__ ((const))
startup_error_tsd (void)
void ** __attribute__ ((const))
_dl_initial_error_catch_tsd (void)
{
static void *data;
return &data;
@ -602,7 +602,7 @@ dl_main (const ElfW(Phdr) *phdr,
#ifdef _LIBC_REENTRANT
/* Explicit initialization since the reloc would just be more work. */
GL(dl_error_catch_tsd) = &startup_error_tsd;
GL(dl_error_catch_tsd) = &_dl_initial_error_catch_tsd;
#endif
/* Process the environment variable which control the behaviour. */
@ -1180,9 +1180,7 @@ of this helper program; chances are you did not intend to run this program.\n\
slotinfo[++i].map = l;
assert (i == GL(dl_tls_max_dtv_idx));
/* Compute 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. */
/* Compute the TLS offsets for the various blocks. */
_dl_determine_tlsoffset ();
/* Construct the static TLS block and the dtv for the initial

View File

@ -4,14 +4,6 @@
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int

View File

@ -4,15 +4,6 @@
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int

View File

@ -5,15 +5,6 @@
#include <link.h>
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int

View File

@ -5,15 +5,6 @@
#include <link.h>
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int

View File

@ -5,15 +5,6 @@
#include <link.h>
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int

View File

@ -5,16 +5,6 @@
#include <link.h>
#include <tls.h>
#ifdef USE_TLS
# include "tls-macros.h"
/* This gives the executable a TLS segment so that even if the libc.so
it loads has none (i.e. --with-tls --without-__thread), ld.so will
permit loading of objects with TLS segments. */
COMMON_INT_DEF(loser);
#endif
#define TEST_FUNCTION do_test ()
static int
do_test (void)

View File

@ -110,6 +110,7 @@ _dl_next_tls_modid (void)
return result;
}
# ifdef SHARED
void
internal_function
@ -204,6 +205,41 @@ _dl_determine_tlsoffset (void)
}
/* This is called only when the data structure setup was skipped at startup,
when there was no need for it then. Now we have dynamically loaded
something needing TLS, or libpthread needs it. */
int
internal_function
_dl_tls_setup (void)
{
assert (GL(dl_tls_dtv_slotinfo_list) == NULL);
assert (GL(dl_tls_max_dtv_idx) == 0);
const size_t nelem = 2 + TLS_SLOTINFO_SURPLUS;
GL(dl_tls_dtv_slotinfo_list) =
malloc (sizeof (struct dtv_slotinfo_list)
+ nelem * sizeof (struct dtv_slotinfo));
if (GL(dl_tls_dtv_slotinfo_list) == NULL)
return -1;
memset (GL(dl_tls_dtv_slotinfo_list)->slotinfo, '\0',
nelem * sizeof (struct dtv_slotinfo));
GL(dl_tls_dtv_slotinfo_list)->len = nelem;
GL(dl_tls_dtv_slotinfo_list)->next = NULL;
/* Number of elements in the static TLS block. It can't be zero
because of various assumptions. The one element is null. */
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx) = 1;
/* This initializes more variables for us. */
_dl_determine_tlsoffset ();
return 0;
}
rtld_hidden_def (_dl_tls_setup)
# endif
static void *
internal_function
allocate_dtv (void *result)

View File

@ -74,6 +74,35 @@ size_t _dl_tls_generation;
TLS_INIT_HELPER
#endif
static inline void
init_slotinfo (void)
{
/* Create the slotinfo list. */
static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
- (char *) &static_slotinfo.si.slotinfo[0])
/ sizeof static_slotinfo.si.slotinfo[0]);
// static_slotinfo.si.next = NULL; already zero
/* The slotinfo list. Will be extended by the code doing dynamic
linking. */
GL(dl_tls_max_dtv_idx) = 1;
GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
}
static inline void
init_static_tls (size_t memsz, size_t align)
{
/* That is the size of the TLS memory for this object. The initialized
value of _dl_tls_static_size is provided by dl-open.c to request some
surplus that permits dynamic loading of modules with IE-model TLS. */
GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
TLS_TCB_ALIGN);
GL(dl_tls_static_used) = memsz;
/* The alignment requirement for the static TLS block. */
GL(dl_tls_static_align) = align;
/* Number of elements in the static TLS block. */
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
}
void
__libc_setup_tls (size_t tcbsize, size_t tcbalign)
@ -117,8 +146,8 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
to request some surplus that permits dynamic loading of modules with
IE-model TLS. */
# if TLS_TCB_AT_TP
tlsblock = __sbrk (roundup (memsz, tcbalign) + tcbsize + max_align
+ GL(dl_tls_static_size));
tcb_offset = roundup (memsz + GL(dl_tls_static_size), tcbalign);
tlsblock = __sbrk (tcb_offset + tcbsize + max_align);
# elif TLS_DTV_AT_TP
tlsblock = __sbrk (roundup (tcbsize, align) + memsz + max_align
+ GL(dl_tls_static_size));
@ -138,10 +167,13 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
/* Initialize the TLS block. */
# if TLS_TCB_AT_TP
static_dtv[2].pointer = tlsblock;
static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
- roundup (memsz, align));
static_map.l_tls_offset = roundup (memsz, align);
# elif TLS_DTV_AT_TP
tcb_offset = roundup (tcbsize, align);
static_dtv[2].pointer = (char *) tlsblock + tcb_offset;
static_map.l_tls_offset = tcb_offset;
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
@ -152,8 +184,6 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
/* Initialize the thread pointer. */
# if TLS_TCB_AT_TP
tcb_offset = roundup (memsz, tcbalign);
INSTALL_DTV ((char *) tlsblock + tcb_offset, static_dtv);
TLS_INIT_TP ((char *) tlsblock + tcb_offset, 0);
@ -171,39 +201,38 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
static_map.l_tls_blocksize = memsz;
static_map.l_tls_initimage = initimage;
static_map.l_tls_initimage_size = filesz;
static_map.l_tls_offset = tcb_offset;
static_map.l_type = lt_executable;
static_map.l_tls_modid = 1;
/* Create the slotinfo list. */
static_slotinfo.si.len = (((char *) (&static_slotinfo + 1)
- (char *) &static_slotinfo.si.slotinfo[0])
/ sizeof static_slotinfo.si.slotinfo[0]);
// static_slotinfo.si.next = NULL; already zero
static_slotinfo.si.slotinfo[1].gen = 0;
init_slotinfo ();
// static_slotinfo.si.slotinfo[1].gen = 0; already zero
static_slotinfo.si.slotinfo[1].map = &static_map;
/* The slotinfo list. Will be extended by the code doing dynamic
linking. */
GL(dl_tls_max_dtv_idx) = 1;
GL(dl_tls_dtv_slotinfo_list) = &static_slotinfo.si;
memsz = roundup (memsz, align ?: 1);
# if TLS_TCB_AT_TP
memsz += tcbsize;
# endif
/* That is the size of the TLS memory for this object. The initialized
value of _dl_tls_static_size is provided by dl-open.c to request some
surplus that permits dynamic loading of modules with IE-model TLS. */
GL(dl_tls_static_size) = roundup (memsz + GL(dl_tls_static_size),
TLS_TCB_ALIGN);
GL(dl_tls_static_used) = memsz;
/* The alignment requirement for the static TLS block. */
GL(dl_tls_static_align) = MAX (TLS_TCB_ALIGN, max_align);
/* Number of elements in the static TLS block. */
GL(dl_tls_static_nelem) = GL(dl_tls_max_dtv_idx);
init_static_tls (memsz, MAX (TLS_TCB_ALIGN, max_align));
}
/* This is called only when the data structure setup was skipped at startup,
when there was no need for it then. Now we have dynamically loaded
something needing TLS, or libpthread needs it. */
int
internal_function
_dl_tls_setup (void)
{
init_slotinfo ();
init_static_tls (
# if TLS_TCB_AT_TP
TLS_TCB_SIZE,
# else
0,
# endif
TLS_TCB_ALIGN);
return 0;
}

View File

@ -636,9 +636,10 @@ __strcpy_g (char *__dest, __const char *__src)
"leal 1(%1),%1\n\t"
"testb %b2,%b2\n\t"
"jne 1b"
: "=&r" (__src), "=&r" (__tmp), "=&q" (__dummy)
: "=&r" (__src), "=&r" (__tmp), "=&q" (__dummy),
"=m" ( *(struct { char __x[0xfffffff]; } *)__dest)
: "0" (__src), "1" (__tmp),
"m" ( *(struct { char __x[0xfffffff]; } *)__dest)
"m" ( *(struct { char __x[0xfffffff]; } *)__src)
: "cc");
return __dest;
}