diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/Makefile | 8 | ||||
-rw-r--r-- | elf/dl-close.c | 3 | ||||
-rw-r--r-- | elf/dl-reloc.c | 16 | ||||
-rw-r--r-- | elf/dl-tls.c | 26 | ||||
-rw-r--r-- | elf/elf.h | 4 | ||||
-rw-r--r-- | elf/rtld-Rules | 22 | ||||
-rw-r--r-- | elf/tst-tls16.c | 52 | ||||
-rw-r--r-- | elf/tst-tlsmod16a.c | 7 | ||||
-rw-r--r-- | elf/tst-tlsmod16b.c | 13 |
9 files changed, 126 insertions, 25 deletions
diff --git a/elf/Makefile b/elf/Makefile index e5812e3668..4230b55df6 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -165,7 +165,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ 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-tls-dlinfo \ + tst-tls16 tst-tls-dlinfo \ tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \ tst-dlmodcount tst-dlopenrpath tst-deep1 \ 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-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \ tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \ - tst-tlsmod15a tst-tlsmod15b \ + tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \ circlemod1 circlemod1a circlemod2 circlemod2a \ circlemod3 circlemod3a \ reldep8mod1 reldep8mod2 reldep8mod3 \ @@ -492,6 +492,7 @@ tst-tlsmod12.so-no-z-defs = yes tst-tlsmod14a.so-no-z-defs = yes tst-tlsmod14b.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 circlemod3.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-align2.c = $(stack-align-test-flags) CFLAGS-tst-alignmod.c = $(stack-align-test-flags) diff --git a/elf/dl-close.c b/elf/dl-close.c index 264e13a8ee..46f1a40adc 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -531,7 +531,8 @@ _dl_close_worker (struct link_map *map) /* All dynamically loaded modules with TLS are unloaded. */ 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 this search list, going in either direction. When the diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index c315b5d972..e9784c2094 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -47,8 +47,10 @@ void internal_function __attribute_noinline__ _dl_allocate_static_tls (struct link_map *map) { - /* If the alignment requirements are too high fail. */ - if (map->l_tls_align > GL(dl_tls_static_align)) + /* If we've already used the variable with dynamic access, or if the + 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: _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 can't be done, we fall back to the error that DF_STATIC_TLS is intended to produce. */ -#define CHECK_STATIC_TLS(map, sym_map) \ - do { \ - if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET, 0)) \ - _dl_allocate_static_tls (sym_map); \ +#define CHECK_STATIC_TLS(map, sym_map) \ + do { \ + if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET \ + || ((sym_map)->l_tls_offset \ + == FORCED_DYNAMIC_TLS_OFFSET), 0)) \ + _dl_allocate_static_tls (sym_map); \ } while (0) #include "dynamic-link.h" diff --git a/elf/dl-tls.c b/elf/dl-tls.c index d5865ab409..3059481043 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -413,7 +413,8 @@ _dl_allocate_tls_init (void *result) not be the generation counter. */ 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 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)) the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + retry: p = dtv[GET_ADDR_MODULE].pointer.val; if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0)) @@ -722,6 +724,28 @@ __tls_get_addr (GET_ADDR_ARGS) 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); dtv[GET_ADDR_MODULE].pointer.is_static = false; } diff --git a/elf/elf.h b/elf/elf.h index 2defde0da7..3fc6244c0c 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1,5 +1,6 @@ /* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2003,2004,2005,2006,2007 Free Software Foundation, Inc. + Copyright (C) 1995-2003,2004,2005,2006,2007,2008 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -605,6 +606,7 @@ typedef struct #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ #define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ /* Legal values for the note segment descriptor types for object files. */ diff --git a/elf/rtld-Rules b/elf/rtld-Rules index 01fbbdf0c5..9f31a560e5 100644 --- a/elf/rtld-Rules +++ b/elf/rtld-Rules @@ -1,6 +1,6 @@ # Subroutine makefile for compiling libc modules linked into dynamic linker. -# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2005, 2006, 2008 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -93,9 +93,12 @@ else # These are the basic compilation rules corresponding to the Makerules ones. # The sysd-rules generated makefile already defines pattern rules for rtld-% # targets built from sysdeps source files. -$(objpfx)rtld-%.os: %.S $(before-compile); $(compile-command.S) -$(objpfx)rtld-%.os: %.s $(before-compile); $(compile-command.s) -$(objpfx)rtld-%.os: %.c $(before-compile); $(compile-command.c) +$(objpfx)rtld-%.os: %.S $(before-compile) + $(compile-command.S) $(rtld-CPPFLAGS) +$(objpfx)rtld-%.os: %.s $(before-compile) + $(compile-command.s) $(rtld-CPPFLAGS) +$(objpfx)rtld-%.os: %.c $(before-compile) + $(compile-command.c) $(rtld-CPPFLAGS) # The rules for generated source files. $(objpfx)rtld-%.os: $(objpfx)%.S $(before-compile); $(compile-command.S) @@ -118,16 +121,7 @@ ifdef rtld-depfiles -include $(rtld-depfiles) endif -# Just in case we wind up e.g. regenerating dependencies for non-rtld objects, -# we don't unconditionally modify the flags. For rtld-% targets, use the -# special flags set below. -CFLAGS += $(if $(filter rtld-%,$(@F)),$(CFLAGS-rtld)) -CPPFLAGS += $(if $(filter rtld-%,$(@F)),$(CPPFLAGS-rtld)) - - # This here is the whole point of all the shenanigans. -CPPFLAGS-rtld := -DNOT_IN_libc=1 -DIS_IN_rtld=1 -CFLAGS-rtld := # blah - +rtld-CPPFLAGS := -DNOT_IN_libc=1 -DIS_IN_rtld=1 endif diff --git a/elf/tst-tls16.c b/elf/tst-tls16.c new file mode 100644 index 0000000000..b3519858a0 --- /dev/null +++ b/elf/tst-tls16.c @@ -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" diff --git a/elf/tst-tlsmod16a.c b/elf/tst-tlsmod16a.c new file mode 100644 index 0000000000..847c8090f5 --- /dev/null +++ b/elf/tst-tlsmod16a.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE +int __thread tlsvar; +#else +int tlsvar; +#endif diff --git a/elf/tst-tlsmod16b.c b/elf/tst-tlsmod16b.c new file mode 100644 index 0000000000..308e6bae92 --- /dev/null +++ b/elf/tst-tlsmod16b.c @@ -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; +} |