aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2003-07-31 07:42:20 +0000
committerUlrich Drepper <drepper@redhat.com>2003-07-31 07:42:20 +0000
commitadc12574e555ec7d6ba3969eed4f829705c235ab (patch)
treecaff1741b560ff8258ace64120781354e62b56c2
parent9722e6f3e26822835542c1c49048d855a5881510 (diff)
downloadglibc-adc12574e555ec7d6ba3969eed4f829705c235ab.zip
glibc-adc12574e555ec7d6ba3969eed4f829705c235ab.tar.gz
glibc-adc12574e555ec7d6ba3969eed4f829705c235ab.tar.bz2
Update.
2003-07-30 Jakub Jelinek <jakub@redhat.com> * elf/dl-reloc.c (_dl_allocate_static_tls): Don't return any value, call dl_signal_error directly. If already relocated, call GL(dl_init_static_tls) directly, otherwise queue it for later. (CHECK_STATIC_TLS): Undo 2003-07-24 change. * elf/rtld.c (dl_main): Initialize GL(dl_init_static_tls). * elf/dl-open.c (dl_open_worker): Call GL_dl_init_static_tls for all static TLS initializations delayed in _dl_allocate_static_tls. * elf/dl-support.c (_dl_init_static_tls): New variable. * include/link.h (struct link_map): Add l_need_tls_init. * sysdeps/generic/ldsodefs.h (_rtld_global): Add _dl_init_static_tls. (_dl_nothread_init_static_tls): New prototype. (_dl_allocate_static_tls): Adjust prototype. * elf/tls-macros.h (VAR_INT_DEF): Add alignment directive. elf_machine_rela_relative): Adjust. (CHECK_STATIC_TLS): _dl_allocate_static_tls can fail now.
-rw-r--r--ChangeLog21
-rw-r--r--elf/dl-open.c10
-rw-r--r--elf/dl-support.c4
-rw-r--r--elf/rtld.c4
-rw-r--r--elf/tls-macros.h1
-rw-r--r--include/link.h4
-rw-r--r--linuxthreads/ChangeLog6
-rw-r--r--linuxthreads/pthread.c42
-rw-r--r--nptl/ChangeLog16
-rw-r--r--nptl/Makefile8
-rw-r--r--nptl/allocatestack.c38
-rw-r--r--nptl/init.c2
-rw-r--r--nptl/pthreadP.h2
-rw-r--r--nptl/tst-tls4.c191
-rw-r--r--nptl/tst-tls4moda.c56
-rw-r--r--nptl/tst-tls4modb.c65
-rw-r--r--sysdeps/generic/ldsodefs.h8
17 files changed, 472 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index ae719fa..d095165 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2003-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/dl-reloc.c (_dl_allocate_static_tls): Don't return any value,
+ call dl_signal_error directly. If already relocated, call
+ GL(dl_init_static_tls) directly, otherwise queue it for later.
+ (CHECK_STATIC_TLS): Undo 2003-07-24 change.
+ * elf/rtld.c (dl_main): Initialize GL(dl_init_static_tls).
+ * elf/dl-open.c (dl_open_worker): Call GL_dl_init_static_tls
+ for all static TLS initializations delayed in _dl_allocate_static_tls.
+ * elf/dl-support.c (_dl_init_static_tls): New variable.
+ * include/link.h (struct link_map): Add l_need_tls_init.
+ * sysdeps/generic/ldsodefs.h (_rtld_global): Add _dl_init_static_tls.
+ (_dl_nothread_init_static_tls): New prototype.
+ (_dl_allocate_static_tls): Adjust prototype.
+
+ * elf/tls-macros.h (VAR_INT_DEF): Add alignment directive.
+
2003-07-31 Alexandre Oliva <aoliva@redhat.com>
* elf/dynamic-link.h (elf_machine_rel, elf_machine_rela,
@@ -26,7 +43,7 @@
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_rela,
elf_machine_rela_relative): Adjust.
* sysdeps/s390/s390-64/dl-machine.h (elf_machine_rela,
- elf_machine_rela_relative):
+ elf_machine_rela_relative): Adjust.
* sysdeps/sh/dl-machine.h (elf_machine_rela,
elf_machine_rela_relative): Adjust.
* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela,
@@ -123,7 +140,7 @@
* elf/rtld.c (_dl_start_final, _dl_start, dl_main): Likewise.
* elf/dl-reloc.c (_dl_allocate_static_tls): Change return type to int.
Take l_tls_firstbyte_offset information into account.
- (CHECK_STATIS_TLS): _dl_allocate_static_tls can fail now.
+ (CHECK_STATIC_TLS): _dl_allocate_static_tls can fail now.
* sysdeps/generic/ldsodefs.h: Adjust _dl_allocate_static_tls prototype.
* elf/Makefile: Add rules to build and run tst-tls14.
* elf/tst-tls14.c: New file.
diff --git a/elf/dl-open.c b/elf/dl-open.c
index aadd8f5..fcda376 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -303,6 +303,16 @@ dl_open_worker (void *a)
}
#ifdef USE_TLS
+ /* Do static TLS initialization now if it has been delayed because
+ the TLS template might not be fully relocated at _dl_allocate_static_tls
+ time. */
+ for (l = new; l; l = l->l_next)
+ if (l->l_need_tls_init)
+ {
+ l->l_need_tls_init = 0;
+ GL(dl_init_static_tls) (l);
+ }
+
/* We normally don't bump the TLS generation counter. There must be
actually a need to do this. */
any_tls = false;
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 52447f4..8c58b2b 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -98,6 +98,10 @@ int _dl_starting_up = 1;
hp_timing_t _dl_cpuclock_offset;
#endif
+#ifdef USE_TLS
+void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
+#endif
+
/* This is zero at program start to signal that the global scope map is
allocated by rtld. Later it keeps the size of the map. It might be
reset if in _dl_close if the last global object is removed. */
diff --git a/elf/rtld.c b/elf/rtld.c
index c63405a..54e5688 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -622,6 +622,10 @@ dl_main (const ElfW(Phdr) *phdr,
GL(dl_error_catch_tsd) = &_dl_initial_error_catch_tsd;
#endif
+#ifdef USE_TLS
+ GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
+#endif
+
/* Process the environment variable which control the behaviour. */
process_envvars (&mode);
diff --git a/elf/tls-macros.h b/elf/tls-macros.h
index bb243d8..7c25424 100644
--- a/elf/tls-macros.h
+++ b/elf/tls-macros.h
@@ -9,6 +9,7 @@
#define VAR_INT_DEF(x) \
asm (".section .tdata\n\t" \
".globl " #x "\n" \
+ ".balign 4\n" \
#x ":\t.long 0\n\t" \
".size " #x ",4\n\t" \
".previous")
diff --git a/include/link.h b/include/link.h
index cd66222..5d10bd6 100644
--- a/include/link.h
+++ b/include/link.h
@@ -186,7 +186,9 @@ struct link_map
the l_libname list. */
unsigned int l_faked:1; /* Nonzero if this is a faked descriptor
without associated file. */
-
+ unsigned int l_need_tls_init:1; /* Nonzero if GL(dl_init_static_tls)
+ should be called on this link map
+ when relocation finishes. */
/* Array with version names. */
unsigned int l_nversions;
struct r_found_version *l_versions;
diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog
index b151dc3..288d352 100644
--- a/linuxthreads/ChangeLog
+++ b/linuxthreads/ChangeLog
@@ -1,3 +1,9 @@
+2003-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ * pthread.c (init_one_static_tls, __pthread_init_static_tls): New
+ functions.
+ (pthread_initialize): Initialize GL(dl_init_static_tls).
+
2003-06-19 Daniel Jacobowitz <drow@mvista.com>
* sysdeps/pthread/timer_create.c (timer_create): Call timer_delref
diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c
index 6211124..f708113 100644
--- a/linuxthreads/pthread.c
+++ b/linuxthreads/pthread.c
@@ -462,6 +462,44 @@ __libc_dl_error_tsd (void)
# endif
#endif
+#ifdef USE_TLS
+static inline void __attribute__((always_inline))
+init_one_static_tls (pthread_descr descr, struct link_map *map)
+{
+# if TLS_TCB_AT_TP
+ dtv_t *dtv = GET_DTV (descr);
+ void *dest = (char *) descr - map->l_tls_offset;
+# elif TLS_DTV_AT_TP
+ dtv_t *dtv = GET_DTV ((pthread_descr) ((char *) descr + TLS_PRE_TCB_SIZE));
+ void *dest = (char *) descr + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+# else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+ dtv[map->l_tls_modid].pointer = dest;
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+ '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+static void
+__pthread_init_static_tls (struct link_map *map)
+{
+ size_t i;
+
+ for (i = 0; i < PTHREAD_THREADS_MAX; ++i)
+ if (__pthread_handles[i].h_descr != NULL && i != 1)
+ {
+ __pthread_lock (&__pthread_handles[i].h_lock, NULL);
+ if (__pthread_handles[i].h_descr != NULL)
+ init_one_static_tls (__pthread_handles[i].h_descr, map);
+ __pthread_unlock (&__pthread_handles[i].h_lock);
+ }
+}
+#endif
+
static void pthread_initialize(void)
{
struct sigaction sa;
@@ -551,6 +589,10 @@ static void pthread_initialize(void)
*__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
#endif
+
+#ifdef USE_TLS
+ GL(dl_init_static_tls) = &__pthread_init_static_tls;
+#endif
}
void __pthread_initialize(void)
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index 45037eb..d79e798 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,19 @@
+2003-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ * init.c (__pthread_initialize_minimal_internal): Initialize
+ GL(dl_init_static_tls).
+ * pthreadP.h (__pthread_init_static_tls): New prototype.
+ * allocatestack.c (init_one_static_tls, __pthread_init_static_tls):
+ New functions.
+ * Makefile (tests): Add tst-tls4.
+ (modules-names): Add tst-tls4moda and tst-tls4modb.
+ ($(objpfx)tst-tls4): Link against libdl and libpthread.
+ ($(objpfx)tst-tls4.out): Depend on tst-tls4moda.so and
+ tst-tls4modb.so.
+ * tst-tls4.c: New file.
+ * tst-tls4moda.c: New file.
+ * tst-tls4modb.c: New file.
+
2003-06-19 Daniel Jacobowitz <drow@mvista.com>
* sysdeps/pthread/timer_create.c (timer_create): Call timer_delref
diff --git a/nptl/Makefile b/nptl/Makefile
index 6beacdc..cfb82e9 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -251,10 +251,11 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \
tst-oncex3 tst-oncex4
endif
ifeq ($(build-shared),yes)
-tests += tst-atfork2 tst-tls3 tst-_res1
+tests += tst-atfork2 tst-tls3 tst-tls4 tst-_res1
endif
-modules-names = tst-atfork2mod tst-tls3mod tst-_res1mod1 tst-_res1mod2
+modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
+ tst-_res1mod1 tst-_res1mod2
extra-objs += $(addsuffix .os,$(strip $(modules-names)))
test-extras += $(modules-names)
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
@@ -395,6 +396,9 @@ LDFLAGS-tst-tls3 = -rdynamic
$(objpfx)tst-tls3.out: $(objpfx)tst-tls3mod.so
$(objpfx)tst-tls3mod.so: $(shared-thread-library)
+$(objpfx)tst-tls4: $(libdl) $(shared-thread-library)
+$(objpfx)tst-tls4.out: $(objpfx)tst-tls4moda.so $(objpfx)tst-tls4modb.so
+
$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library)
ifeq (yes,$(build-shared))
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index e042cf4..729f3b8 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -710,3 +710,41 @@ __find_thread_by_id (pid_t tid)
return result;
}
#endif
+
+static inline void __attribute__((always_inline))
+init_one_static_tls (struct pthread *curp, struct link_map *map)
+{
+ dtv_t *dtv = GET_DTV (TLS_TPADJ (curp));
+# if TLS_TCB_AT_TP
+ void *dest = (char *) curp - map->l_tls_offset;
+# elif TLS_DTV_AT_TP
+ void *dest = (char *) curp + map->l_tls_offset + TLS_PRE_TCB_SIZE;
+# else
+# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+# endif
+
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+ dtv[map->l_tls_modid].pointer = dest;
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+ '\0', map->l_tls_blocksize - map->l_tls_initimage_size);
+}
+
+void
+attribute_hidden
+__pthread_init_static_tls (struct link_map *map)
+{
+ lll_lock (stack_cache_lock);
+
+ /* Iterate over the list with system-allocated threads first. */
+ list_t *runp;
+ list_for_each (runp, &stack_used)
+ init_one_static_tls (list_entry (runp, struct pthread, list), map);
+
+ /* Now the list with threads using user-allocated stacks. */
+ list_for_each (runp, &__stack_user)
+ init_one_static_tls (list_entry (runp, struct pthread, list), map);
+
+ lll_unlock (stack_cache_lock);
+}
diff --git a/nptl/init.c b/nptl/init.c
index 9c76773..dae24f1 100644
--- a/nptl/init.c
+++ b/nptl/init.c
@@ -272,6 +272,8 @@ __pthread_initialize_minimal_internal (void)
GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;
#endif
+ GL(dl_init_static_tls) = &__pthread_init_static_tls;
+
/* Register the fork generation counter with the libc. */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
__libc_multiple_threads_ptr =
diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
index a8cefab..b07c6da 100644
--- a/nptl/pthreadP.h
+++ b/nptl/pthreadP.h
@@ -257,6 +257,8 @@ extern int *__libc_multiple_threads_ptr attribute_hidden;
/* Find a thread given its TID. */
extern struct pthread *__find_thread_by_id (pid_t tid) attribute_hidden;
+extern void __pthread_init_static_tls (struct link_map *) attribute_hidden;
+
/* Namespace save aliases. */
extern int __pthread_getschedparam (pthread_t thread_id, int *policy,
diff --git a/nptl/tst-tls4.c b/nptl/tst-tls4.c
new file mode 100644
index 0000000..52775de
--- /dev/null
+++ b/nptl/tst-tls4.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+#define N 3
+
+void (*test1) (void), (*test2) (void);
+
+pthread_barrier_t b2, b3;
+
+static void *
+tf (void *arg)
+{
+ int i;
+
+ for (i = 0; i <= (uintptr_t) arg; ++i)
+ {
+ int r = pthread_barrier_wait (&b3);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("tf: barrier_wait failed");
+ exit (1);
+ }
+ }
+
+ test1 ();
+
+ for (i = 0; i < 3; ++i)
+ {
+ int r = pthread_barrier_wait (&b3);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("tf: barrier_wait failed");
+ exit (1);
+ }
+ }
+
+ test2 ();
+
+ for (i = 0; i < 3 - (uintptr_t) arg; ++i)
+ {
+ int r = pthread_barrier_wait (&b3);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("tf: barrier_wait failed");
+ exit (1);
+ }
+ }
+
+ return NULL;
+}
+
+static void *
+tf2 (void *arg)
+{
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("tf2: barrier_wait failed");
+ exit (1);
+ }
+
+ int i;
+ for (i = 0; i < N; ++i)
+ tf (arg);
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ pthread_t th[2];
+ const char *modules[N]
+ = { "tst-tls4moda.so", "tst-tls4moda.so", "tst-tls4modb.so" };
+
+ if (pthread_barrier_init (&b2, NULL, 2) != 0)
+ {
+ puts ("barrier_init failed");
+ return 1;
+ }
+
+ if (pthread_barrier_init (&b3, NULL, 3) != 0)
+ {
+ puts ("barrier_init failed");
+ return 1;
+ }
+
+ if (pthread_create (&th[0], NULL, tf2, (void *) (uintptr_t) 1))
+ {
+ puts ("pthread_create failed");
+ return 1;
+ }
+
+ int r = pthread_barrier_wait (&b2);
+ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ {
+ puts ("barrier_wait failed");
+ return 1;
+ }
+
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ void *h = dlopen (modules[i], RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("dlopen failed %s\n", dlerror ());
+ return 1;
+ }
+
+ test1 = dlsym (h, "test1");
+ if (test1 == NULL)
+ {
+ printf ("dlsym for test1 failed %s\n", dlerror ());
+ return 1;
+ }
+
+ test2 = dlsym (h, "test2");
+ if (test2 == NULL)
+ {
+ printf ("dlsym for test2 failed %s\n", dlerror ());
+ return 1;
+ }
+
+ if (pthread_create (&th[1], NULL, tf, (void *) (uintptr_t) 2))
+ {
+ puts ("pthread_create failed");
+ return 1;
+ }
+
+ tf ((void *) (uintptr_t) 0);
+
+ if (pthread_join (th[1], NULL) != 0)
+ {
+ puts ("join failed");
+ return 1;
+ }
+
+ if (dlclose (h))
+ {
+ puts ("dlclose failed");
+ return 1;
+ }
+
+ printf ("test %d with %s succeeded\n", i, modules[i]);
+ }
+
+ if (pthread_join (th[0], NULL) != 0)
+ {
+ puts ("join failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TIMEOUT 5
+#define TEST_FUNCTION do_test ()
+
+#else
+
+#define TEST_FUNCTION 0
+
+#endif
+
+#include "../test-skeleton.c"
diff --git a/nptl/tst-tls4moda.c b/nptl/tst-tls4moda.c
new file mode 100644
index 0000000..ff7ee56
--- /dev/null
+++ b/nptl/tst-tls4moda.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+static __thread unsigned char foo [32]
+ __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))));
+
+void
+test1 (void)
+{
+ size_t s;
+
+ for (s = 0; s < sizeof (foo); ++s)
+ {
+ if (foo [s])
+ abort ();
+ foo [s] = s;
+ }
+}
+
+void
+test2 (void)
+{
+ size_t s;
+
+ for (s = 0; s < sizeof (foo); ++s)
+ {
+ if (foo [s] != s)
+ abort ();
+ foo [s] = sizeof (foo) - s;
+ }
+}
+
+#endif
diff --git a/nptl/tst-tls4modb.c b/nptl/tst-tls4modb.c
new file mode 100644
index 0000000..99f3b54
--- /dev/null
+++ b/nptl/tst-tls4modb.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <tls.h>
+
+#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE
+
+static int i;
+int bar;
+
+static __thread void *foo [32 / sizeof (void *)]
+ __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *))))
+ = { &i, &bar };
+
+void
+test1 (void)
+{
+ size_t s;
+
+ if (foo [0] != &i || foo [1] != &bar)
+ abort ();
+
+ foo [0] = NULL;
+ foo [1] = NULL;
+ for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
+ {
+ if (foo [s])
+ abort ();
+ foo [s] = &foo[s];
+ }
+}
+
+void
+test2 (void)
+{
+ size_t s;
+
+ for (s = 0; s < sizeof (foo) / sizeof (void *); ++s)
+ {
+ if (foo [s] != &foo [s])
+ abort ();
+ foo [s] = &foo [s ^ 1];
+ }
+}
+
+#endif
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 565edb3..b647ea4 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -390,6 +390,8 @@ struct rtld_global
EXTERN void *_dl_initial_dtv;
/* Generation counter for the dtv. */
EXTERN size_t _dl_tls_generation;
+
+ EXTERN void (*_dl_init_static_tls) (struct link_map *);
#endif
#ifdef NEED_DL_SYSINFO
@@ -797,7 +799,7 @@ rtld_hidden_proto (_dl_allocate_tls)
extern void _dl_get_tls_static_info (size_t *sizep, size_t *alignp)
internal_function;
-extern int _dl_allocate_static_tls (struct link_map *map)
+extern void _dl_allocate_static_tls (struct link_map *map)
internal_function attribute_hidden;
/* These are internal entry points to the two halves of _dl_allocate_tls,
@@ -816,6 +818,10 @@ rtld_hidden_proto (_dl_deallocate_tls)
extern void *_dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
internal_function;
+#if defined USE_TLS
+extern void _dl_nothread_init_static_tls (struct link_map *) attribute_hidden;
+#endif
+
__END_DECLS
#endif /* ldsodefs.h */