separate __tls_get_addr implementation from dynamic linker/init_tls
authorRich Felker <dalias@aerifal.cx>
Thu, 19 Jun 2014 06:59:44 +0000 (02:59 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 19 Jun 2014 06:59:44 +0000 (02:59 -0400)
such separation serves multiple purposes:

- by having the common path for __tls_get_addr alone in its own
  function with a tail call to the slow case, code generation is
  greatly improved.

- by having __tls_get_addr in it own file, it can be replaced on a
  per-arch basis as needed, for optimization or ABI-specific purposes.

- by removing __tls_get_addr from __init_tls.c, a few bytes of code
  are shaved off of static binaries (which are unlikely to use this
  function unless the linker messed up).

src/env/__init_tls.c
src/ldso/dynlink.c
src/thread/__tls_get_addr.c [new file with mode: 0644]

index f7eab8d..13cf2ee 100644 (file)
@@ -53,11 +53,6 @@ void *__copy_tls(unsigned char *mem)
        return td;
 }
 
-void *__tls_get_addr(size_t *v)
-{
-       return (char *)__pthread_self()->dtv[1]+v[1];
-}
-
 #if ULONG_MAX == 0xffffffff
 typedef Elf32_Phdr Phdr;
 #else
index 2b6f0c9..bc4f2f6 100644 (file)
@@ -1031,17 +1031,15 @@ void *__copy_tls(unsigned char *mem)
        return td;
 }
 
-void *__tls_get_addr(size_t *v)
+void *__tls_get_new(size_t *v)
 {
        pthread_t self = __pthread_self();
-       if (v[0]<=(size_t)self->dtv[0])
-               return (char *)self->dtv[v[0]]+v[1];
 
        /* Block signals to make accessing new TLS async-signal-safe */
        sigset_t set;
-       pthread_sigmask(SIG_BLOCK, SIGALL_SET, &set);
+       __block_all_sigs(&set);
        if (v[0]<=(size_t)self->dtv[0]) {
-               pthread_sigmask(SIG_SETMASK, &set, 0);
+               __restore_sigs(&set);
                return (char *)self->dtv[v[0]]+v[1];
        }
 
@@ -1074,7 +1072,7 @@ void *__tls_get_addr(size_t *v)
                memcpy(mem, p->tls_image, p->tls_len);
                if (p->tls_id == v[0]) break;
        }
-       pthread_sigmask(SIG_SETMASK, &set, 0);
+       __restore_sigs(&set);
        return mem + v[1];
 }
 
@@ -1442,6 +1440,8 @@ static int invalid_dso_handle(void *h)
        return 1;
 }
 
+void *__tls_get_addr(size_t *);
+
 static void *do_dlsym(struct dso *p, const char *s, void *ra)
 {
        size_t i;
diff --git a/src/thread/__tls_get_addr.c b/src/thread/__tls_get_addr.c
new file mode 100644 (file)
index 0000000..28ec7f0
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stddef.h>
+#include "pthread_impl.h"
+#include "libc.h"
+
+void *__tls_get_new(size_t *) ATTR_LIBC_VISIBILITY;
+
+void *__tls_get_addr(size_t *v)
+{
+       pthread_t self = __pthread_self();
+#ifdef SHARED
+       if (v[0]<=(size_t)self->dtv[0])
+               return (char *)self->dtv[v[0]]+v[1];
+       return __tls_get_new(v);
+#else
+       return (char *)self->dtv[1]+v[1];
+#endif
+}