Hi Khem, All
while doing some test with firefox 3 (linked against uclibc-nptl on sh4), we discovered a bug in ld.so dynamic linker. In firefox there is a shared object libejmalloc.so having a constructor that accesses a TLS variable using the local-dynamic tls access model. During the ld.so startup the dtv entries are properly initialized just after calling the constructors for all NEEDED dso, so causing the segfault in __tls_get_address. The patch basically move the dtv initialization before calling the constructor (we checked glibc too, and it correclty does in this way).

My colleague implemented a simple test case (added in the test suite ) that exploits this bug.

Khem, may you run the test case, before and after applying the patch so on arm-nptl too.
Waiting for your feedback before pushing it out in SVN.

Cheers,
Carmelo
ldso: Initialize fully dtv before calling the constructors.

Signed-off-by: Filippo Arcidiacono <[EMAIL PROTECTED]>
Signed-off-by: Carmelo Amoroso <[EMAIL PROTECTED]>

Index: test/tls/Makefile
===================================================================
--- test/tls/Makefile   (revision 24035)
+++ test/tls/Makefile   (working copy)
@@ -3,7 +3,7 @@
 
 TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7        
\
        tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13       \
-       tst-tls14 tst-tls15 tst-tls1-static tst-tls2-static             \
+       tst-tls14 tst-tls15 tst-tls16 tst-tls1-static tst-tls2-static \
        tst-tls9-static
 TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static
 
@@ -42,6 +42,7 @@
 CFLAGS_tst-tlsmod14b.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod15a.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod15b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod16.so := -fPIC -DSHARED -shared
 
 LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod2.so := -shared -static-libgcc -L$(top_builddir)lib
@@ -66,6 +67,7 @@
 LDFLAGS_tst-tlsmod14b.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod15a.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod15b.so := -shared -static-libgcc -L$(top_builddir)lib
+LDFLAGS_tst-tlsmod16.so := -shared -static-libgcc -L$(top_builddir)lib
 
 LDFLAGS_tst-tls3 := tst-tlsmod1.so
 LDFLAGS_tst-tls4 := -ldl
@@ -80,6 +82,7 @@
 LDFLAGS_tst-tls13 := -ldl -Wl,-rpath-link=.
 LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so
 LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls16 := tst-tlsmod16.so
 
 tst-tls3: tst-tlsmod1.so
 tst-tls4: tst-tlsmod2.so
@@ -94,6 +97,7 @@
 tst-tls13: tst-tlsmod13.so tst-tlsmod13a.so
 tst-tls14: tst-tlsmod14a.so tst-tlsmod14b.so
 tst-tls15: tst-tlsmod15a.so tst-tlsmod15b.so
+tst-tls16: tst-tlsmod16.so
 
 RET_tst-tls13 := 1
 ifeq ($(TARGET_ARCH),mips)
Index: test/tls/tst-tls16.c
===================================================================
--- test/tls/tst-tls16.c        (revision 0)
+++ test/tls/tst-tls16.c        (revision 0)
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <tls.h>
+
+#define TLS_VAR_INIT_VALUE 99
+
+#ifdef USE_TLS
+extern __thread int tls_var;
+#endif
+
+int main(void)
+{
+       int ret = EXIT_SUCCESS;
+#ifdef USE_TLS
+       if (tls_var != TLS_VAR_INIT_VALUE) {
+               printf("tls_var = %d - Expected value = %d\n", tls_var, 
TLS_VAR_INIT_VALUE);
+               ret = EXIT_FAILURE;
+       }
+#endif
+       return ret;
+}
Index: test/tls/tst-tlsmod16.c
===================================================================
--- test/tls/tst-tlsmod16.c     (revision 0)
+++ test/tls/tst-tlsmod16.c     (revision 0)
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <tls.h>
+
+#define TLS_VAR_INIT_VALUE 99
+
+#ifdef USE_TLS
+__thread int tls_var  __attribute__((tls_model("global-dynamic")));
+static __thread int local_tls_var __attribute__((tls_model("local-dynamic")));
+#endif
+
+void __attribute__((constructor)) libtls_ctor(void);
+void libtls_ctor(void)
+{
+       printf("libtls: constructor!\n");
+#ifdef USE_TLS
+       local_tls_var = TLS_VAR_INIT_VALUE;
+       tls_var = local_tls_var;
+#endif
+}
+
+void __attribute__((destructor)) libtls_dtor(void);
+void libtls_dtor(void)
+{
+       printf("libtls: destructor!\n");
+}
Index: ldso/ldso/ldso.c
===================================================================
--- ldso/ldso/ldso.c    (revision 24035)
+++ ldso/ldso/ldso.c    (working copy)
@@ -842,6 +842,27 @@
                        _dl_protect_relro (tpnt);
        }
 
+       if (!was_tls_init_tp_called && _dl_tls_max_dtv_idx > 0)
+               ++_dl_tls_generation;
+
+       _dl_debug_early("Calling _dl_allocate_tls_init()!\n");
+
+       /* Now that we have completed relocation, the initializer data
+          for the TLS blocks has its final values and we can copy them
+          into the main thread's TLS area, which we allocated above.  */
+       _dl_allocate_tls_init (tcbp);
+
+       /* And finally install it for the main thread.  If ld.so itself uses
+          TLS we know the thread pointer was initialized earlier.  */
+       if (! tls_init_tp_called)
+       {
+               const char *lossage = (char *) TLS_INIT_TP (tcbp, USE___THREAD);
+               if (__builtin_expect (lossage != NULL, 0))
+               {
+                       _dl_debug_early("cannot set up thread-local storage: 
%s\n", lossage);
+                       _dl_exit(30);
+               }
+       }
        /* OK, at this point things are pretty much ready to run.  Now we need
         * to touch up a few items that are required, and then we can let the
         * user application have at it.  Note that the dynamic linker itself
@@ -921,27 +942,6 @@
        _dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
                _dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", 
_dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
                        
-       if (!was_tls_init_tp_called && _dl_tls_max_dtv_idx > 0)
-               ++_dl_tls_generation;
-
-       _dl_debug_early("Calling _dl_allocate_tls_init()!\n");
-
-       /* Now that we have completed relocation, the initializer data
-          for the TLS blocks has its final values and we can copy them
-          into the main thread's TLS area, which we allocated above.  */
-       _dl_allocate_tls_init (tcbp);
-
-       /* And finally install it for the main thread.  If ld.so itself uses
-          TLS we know the thread pointer was initialized earlier.  */
-       if (! tls_init_tp_called)
-       {
-               const char *lossage = (char *) TLS_INIT_TP (tcbp, USE___THREAD);
-               if (__builtin_expect (lossage != NULL, 0))
-               {
-                       _dl_debug_early("cannot set up thread-local storage: 
%s\n", lossage);
-                       _dl_exit(30);
-               }
-       }
 #endif
 
        /* Notify the debugger that all objects are now mapped in.  */
_______________________________________________
uClibc mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/uclibc

Reply via email to