Browse Source

separate __tls_get_addr implementation from dynamic linker/init_tls

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).
Rich Felker 10 năm trước cách đây
mục cha
commit
5ba238e1e4
3 tập tin đã thay đổi với 23 bổ sung11 xóa
  1. 0 5
      src/env/__init_tls.c
  2. 6 6
      src/ldso/dynlink.c
  3. 17 0
      src/thread/__tls_get_addr.c

+ 0 - 5
src/env/__init_tls.c

@@ -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

+ 6 - 6
src/ldso/dynlink.c

@@ -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;

+ 17 - 0
src/thread/__tls_get_addr.c

@@ -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
+}