mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 20:40:05 +00:00
* include/link.h (FORCED_DYNAMIC_TLS_OFFSET): Define.
* elf/dl-close.c (_dl_close): Check for it. * elf/dl-reloc.c (CHECK_STATIC_TLS): Likewise. (_dl_allocate_static_tls): Likewise. * elf/dl-tls.c (_dl_allocate_tls_init): Likewise. (__tls_get_addr): Protect from race conditions in setting l_tls_offset to it. * elf/tst-tls16.c: New file. * elf/tst-tlsmod16a.c: New file. * elf/tst-tlsmod16b.c: New file. * elf/Makefile: Add rules to build and run tst-tls16.
This commit is contained in:
parent
a0f6c236e0
commit
4c533566c2
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
|||||||
|
2007-10-23 Alexandre Oliva <aoliva@redhat.com>
|
||||||
|
|
||||||
|
* include/link.h (FORCED_DYNAMIC_TLS_OFFSET): Define.
|
||||||
|
* elf/dl-close.c (_dl_close): Check for it.
|
||||||
|
* elf/dl-reloc.c (CHECK_STATIC_TLS): Likewise.
|
||||||
|
(_dl_allocate_static_tls): Likewise.
|
||||||
|
* elf/dl-tls.c (_dl_allocate_tls_init): Likewise.
|
||||||
|
(__tls_get_addr): Protect from race conditions in setting l_tls_offset
|
||||||
|
to it.
|
||||||
|
* elf/tst-tls16.c: New file.
|
||||||
|
* elf/tst-tlsmod16a.c: New file.
|
||||||
|
* elf/tst-tlsmod16b.c: New file.
|
||||||
|
* elf/Makefile: Add rules to build and run tst-tls16.
|
||||||
|
|
||||||
2008-01-16 Ulrich Drepper <drepper@redhat.com>
|
2008-01-16 Ulrich Drepper <drepper@redhat.com>
|
||||||
|
|
||||||
[BZ #5628]
|
[BZ #5628]
|
||||||
|
@ -165,7 +165,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
|||||||
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
|
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
|
||||||
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
||||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
|
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
|
||||||
tst-tls-dlinfo \
|
tst-tls16 tst-tls-dlinfo \
|
||||||
tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
|
tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
|
||||||
tst-dlmodcount tst-dlopenrpath tst-deep1 \
|
tst-dlmodcount tst-dlopenrpath tst-deep1 \
|
||||||
tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
||||||
@ -199,7 +199,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
|||||||
tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
|
tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
|
||||||
tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
|
tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
|
||||||
tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
|
tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
|
||||||
tst-tlsmod15a tst-tlsmod15b \
|
tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \
|
||||||
circlemod1 circlemod1a circlemod2 circlemod2a \
|
circlemod1 circlemod1a circlemod2 circlemod2a \
|
||||||
circlemod3 circlemod3a \
|
circlemod3 circlemod3a \
|
||||||
reldep8mod1 reldep8mod2 reldep8mod3 \
|
reldep8mod1 reldep8mod2 reldep8mod3 \
|
||||||
@ -492,6 +492,7 @@ tst-tlsmod12.so-no-z-defs = yes
|
|||||||
tst-tlsmod14a.so-no-z-defs = yes
|
tst-tlsmod14a.so-no-z-defs = yes
|
||||||
tst-tlsmod14b.so-no-z-defs = yes
|
tst-tlsmod14b.so-no-z-defs = yes
|
||||||
tst-tlsmod15a.so-no-z-defs = yes
|
tst-tlsmod15a.so-no-z-defs = yes
|
||||||
|
tst-tlsmod16b.so-no-z-defs = yes
|
||||||
circlemod2.so-no-z-defs = yes
|
circlemod2.so-no-z-defs = yes
|
||||||
circlemod3.so-no-z-defs = yes
|
circlemod3.so-no-z-defs = yes
|
||||||
circlemod3a.so-no-z-defs = yes
|
circlemod3a.so-no-z-defs = yes
|
||||||
@ -711,6 +712,9 @@ $(objpfx)tst-tls-dlinfo.out: $(objpfx)tst-tlsmod2.so
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$(objpfx)tst-tls16: $(libdl)
|
||||||
|
$(objpfx)tst-tls16.out: $(objpfx)tst-tlsmod16a.so $(objpfx)tst-tlsmod16b.so
|
||||||
|
|
||||||
CFLAGS-tst-align.c = $(stack-align-test-flags)
|
CFLAGS-tst-align.c = $(stack-align-test-flags)
|
||||||
CFLAGS-tst-align2.c = $(stack-align-test-flags)
|
CFLAGS-tst-align2.c = $(stack-align-test-flags)
|
||||||
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
|
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
|
||||||
|
@ -531,7 +531,8 @@ _dl_close_worker (struct link_map *map)
|
|||||||
/* All dynamically loaded modules with TLS are unloaded. */
|
/* All dynamically loaded modules with TLS are unloaded. */
|
||||||
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
|
GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
|
||||||
|
|
||||||
if (imap->l_tls_offset != NO_TLS_OFFSET)
|
if (imap->l_tls_offset != NO_TLS_OFFSET
|
||||||
|
&& imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
|
||||||
{
|
{
|
||||||
/* Collect a contiguous chunk built from the objects in
|
/* Collect a contiguous chunk built from the objects in
|
||||||
this search list, going in either direction. When the
|
this search list, going in either direction. When the
|
||||||
|
@ -47,8 +47,10 @@ void
|
|||||||
internal_function __attribute_noinline__
|
internal_function __attribute_noinline__
|
||||||
_dl_allocate_static_tls (struct link_map *map)
|
_dl_allocate_static_tls (struct link_map *map)
|
||||||
{
|
{
|
||||||
/* If the alignment requirements are too high fail. */
|
/* If we've already used the variable with dynamic access, or if the
|
||||||
if (map->l_tls_align > GL(dl_tls_static_align))
|
alignment requirements are too high, fail. */
|
||||||
|
if (map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET
|
||||||
|
|| map->l_tls_align > GL(dl_tls_static_align))
|
||||||
{
|
{
|
||||||
fail:
|
fail:
|
||||||
_dl_signal_error (0, map->l_name, NULL, N_("\
|
_dl_signal_error (0, map->l_name, NULL, N_("\
|
||||||
@ -255,10 +257,12 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
|||||||
an attempt to allocate it in surplus space on the fly. If that
|
an attempt to allocate it in surplus space on the fly. If that
|
||||||
can't be done, we fall back to the error that DF_STATIC_TLS is
|
can't be done, we fall back to the error that DF_STATIC_TLS is
|
||||||
intended to produce. */
|
intended to produce. */
|
||||||
#define CHECK_STATIC_TLS(map, sym_map) \
|
#define CHECK_STATIC_TLS(map, sym_map) \
|
||||||
do { \
|
do { \
|
||||||
if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \
|
if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET \
|
||||||
_dl_allocate_static_tls (sym_map); \
|
|| ((sym_map)->l_tls_offset \
|
||||||
|
== FORCED_DYNAMIC_TLS_OFFSET), 0)) \
|
||||||
|
_dl_allocate_static_tls (sym_map); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#include "dynamic-link.h"
|
#include "dynamic-link.h"
|
||||||
|
26
elf/dl-tls.c
26
elf/dl-tls.c
@ -413,7 +413,8 @@ _dl_allocate_tls_init (void *result)
|
|||||||
not be the generation counter. */
|
not be the generation counter. */
|
||||||
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
||||||
|
|
||||||
if (map->l_tls_offset == NO_TLS_OFFSET)
|
if (map->l_tls_offset == NO_TLS_OFFSET
|
||||||
|
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
|
||||||
{
|
{
|
||||||
/* For dynamically loaded modules we simply store
|
/* For dynamically loaded modules we simply store
|
||||||
the value indicating deferred allocation. */
|
the value indicating deferred allocation. */
|
||||||
@ -702,6 +703,7 @@ __tls_get_addr (GET_ADDR_ARGS)
|
|||||||
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
|
if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
|
||||||
the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
|
the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
|
||||||
|
|
||||||
|
retry:
|
||||||
p = dtv[GET_ADDR_MODULE].pointer.val;
|
p = dtv[GET_ADDR_MODULE].pointer.val;
|
||||||
|
|
||||||
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
|
||||||
@ -722,6 +724,28 @@ __tls_get_addr (GET_ADDR_ARGS)
|
|||||||
the_map = listp->slotinfo[idx].map;
|
the_map = listp->slotinfo[idx].map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure that, if a dlopen running in parallel forces the
|
||||||
|
variable into static storage, we'll wait until the address in
|
||||||
|
the static TLS block is set up, and use that. If we're
|
||||||
|
undecided yet, make sure we make the decision holding the
|
||||||
|
lock as well. */
|
||||||
|
if (__builtin_expect (the_map->l_tls_offset
|
||||||
|
!= FORCED_DYNAMIC_TLS_OFFSET, 0))
|
||||||
|
{
|
||||||
|
__rtld_lock_lock_recursive (GL(dl_load_lock));
|
||||||
|
if (__builtin_expect (the_map->l_tls_offset == NO_TLS_OFFSET, 1))
|
||||||
|
{
|
||||||
|
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
|
if (__builtin_expect (the_map->l_tls_offset
|
||||||
|
!= FORCED_DYNAMIC_TLS_OFFSET, 1))
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
||||||
dtv[GET_ADDR_MODULE].pointer.is_static = false;
|
dtv[GET_ADDR_MODULE].pointer.is_static = false;
|
||||||
}
|
}
|
||||||
|
52
elf/tst-tls16.c
Normal file
52
elf/tst-tls16.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
void *h = dlopen ("tst-tlsmod16a.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
if (h == NULL)
|
||||||
|
{
|
||||||
|
puts ("unexpectedly failed to open tst-tlsmod16a.so");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *p = dlsym (h, "tlsvar");
|
||||||
|
|
||||||
|
/* This dlopen should indeed fail, because tlsvar was assigned to
|
||||||
|
dynamic TLS, and the new module requests it to be in static TLS.
|
||||||
|
However, there's a possibility that dlopen succeeds if the
|
||||||
|
variable is, for whatever reason, assigned to static TLS, or if
|
||||||
|
the module fails to require static TLS, or even if TLS is not
|
||||||
|
supported. */
|
||||||
|
h = dlopen ("tst-tlsmod16b.so", RTLD_NOW | RTLD_GLOBAL);
|
||||||
|
if (h == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts ("unexpectedly succeeded to open tst-tlsmod16b.so");
|
||||||
|
|
||||||
|
|
||||||
|
void *(*fp) (void) = (void *(*) (void)) dlsym (h, "in_dso");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
puts ("cannot find in_dso");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the dlopen passes, at least make sure the address returned by
|
||||||
|
dlsym is the same as that returned by the initial-exec access.
|
||||||
|
If the variable was assigned to dynamic TLS during dlsym, this
|
||||||
|
portion will fail. */
|
||||||
|
if (fp () != p)
|
||||||
|
{
|
||||||
|
puts ("returned values do not match");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_FUNCTION do_test ()
|
||||||
|
#include "../test-skeleton.c"
|
7
elf/tst-tlsmod16a.c
Normal file
7
elf/tst-tlsmod16a.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <tls.h>
|
||||||
|
|
||||||
|
#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
|
||||||
|
int __thread tlsvar;
|
||||||
|
#else
|
||||||
|
int tlsvar;
|
||||||
|
#endif
|
13
elf/tst-tlsmod16b.c
Normal file
13
elf/tst-tlsmod16b.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include <tls.h>
|
||||||
|
|
||||||
|
#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
|
||||||
|
extern __thread int tlsvar __attribute__((tls_model("initial-exec")));
|
||||||
|
#else
|
||||||
|
extern int tlsvar;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *
|
||||||
|
in_dso (void)
|
||||||
|
{
|
||||||
|
return &tlsvar;
|
||||||
|
}
|
@ -278,6 +278,15 @@ struct link_map
|
|||||||
size_t l_tls_firstbyte_offset;
|
size_t l_tls_firstbyte_offset;
|
||||||
#ifndef NO_TLS_OFFSET
|
#ifndef NO_TLS_OFFSET
|
||||||
# define NO_TLS_OFFSET 0
|
# define NO_TLS_OFFSET 0
|
||||||
|
#endif
|
||||||
|
#ifndef FORCED_DYNAMIC_TLS_OFFSET
|
||||||
|
# if NO_TLS_OFFSET == 0
|
||||||
|
# define FORCED_DYNAMIC_TLS_OFFSET 1
|
||||||
|
# elif NO_TLS_OFFSET == -1
|
||||||
|
# define FORCED_DYNAMIC_TLS_OFFSET -2
|
||||||
|
# else
|
||||||
|
# error "FORCED_DYNAMIC_TLS_OFFSET is not defined"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
/* For objects present at startup time: offset in the static TLS block. */
|
/* For objects present at startup time: offset in the static TLS block. */
|
||||||
ptrdiff_t l_tls_offset;
|
ptrdiff_t l_tls_offset;
|
||||||
|
Loading…
Reference in New Issue
Block a user