summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile8
-rw-r--r--elf/dl-close.c3
-rw-r--r--elf/dl-reloc.c16
-rw-r--r--elf/dl-tls.c26
-rw-r--r--elf/elf.h4
-rw-r--r--elf/rtld-Rules22
-rw-r--r--elf/tst-tls16.c52
-rw-r--r--elf/tst-tlsmod16a.c7
-rw-r--r--elf/tst-tlsmod16b.c13
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;
+}