diff options
| author | Rich Felker <dalias@aerifal.cx> | 2014-06-19 02:59:44 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2014-06-19 02:59:44 -0400 | 
| commit | 5ba238e1e48d2fe4107e09903b26b2b36aa9e9ff (patch) | |
| tree | 2933bdc33c131122acea9b188186443da2e6a37b | |
| parent | 4e0b4a5de735ecb241fadb1e15381c947e16e71f (diff) | |
| download | musl-5ba238e1e48d2fe4107e09903b26b2b36aa9e9ff.tar.gz | |
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).
| -rw-r--r-- | src/env/__init_tls.c | 5 | ||||
| -rw-r--r-- | src/ldso/dynlink.c | 12 | ||||
| -rw-r--r-- | src/thread/__tls_get_addr.c | 17 | 
3 files changed, 23 insertions, 11 deletions
| diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c index f7eab8d6..13cf2eea 100644 --- a/src/env/__init_tls.c +++ b/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 diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 2b6f0c94..bc4f2f6f 100644 --- a/src/ldso/dynlink.c +++ b/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; diff --git a/src/thread/__tls_get_addr.c b/src/thread/__tls_get_addr.c new file mode 100644 index 00000000..28ec7f02 --- /dev/null +++ b/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 +} | 
