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).
master
Rich Felker 12 years ago
parent
commit
5ba238e1e4
  1. 5
      src/env/__init_tls.c
  2. 12
      src/ldso/dynlink.c
  3. 17
      src/thread/__tls_get_addr.c

5
src/env/__init_tls.c

@ -53,11 +53,6 @@ void *__copy_tls(unsigned char *mem)
return td; return td;
} }
void *__tls_get_addr(size_t *v)
{
return (char *)__pthread_self()->dtv[1]+v[1];
}
#if ULONG_MAX == 0xffffffff #if ULONG_MAX == 0xffffffff
typedef Elf32_Phdr Phdr; typedef Elf32_Phdr Phdr;
#else #else

12
src/ldso/dynlink.c

@ -1031,17 +1031,15 @@ void *__copy_tls(unsigned char *mem)
return td; return td;
} }
void *__tls_get_addr(size_t *v) void *__tls_get_new(size_t *v)
{ {
pthread_t self = __pthread_self(); 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 */ /* Block signals to make accessing new TLS async-signal-safe */
sigset_t set; sigset_t set;
pthread_sigmask(SIG_BLOCK, SIGALL_SET, &set); __block_all_sigs(&set);
if (v[0]<=(size_t)self->dtv[0]) { 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]; 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); memcpy(mem, p->tls_image, p->tls_len);
if (p->tls_id == v[0]) break; if (p->tls_id == v[0]) break;
} }
pthread_sigmask(SIG_SETMASK, &set, 0); __restore_sigs(&set);
return mem + v[1]; return mem + v[1];
} }
@ -1442,6 +1440,8 @@ static int invalid_dso_handle(void *h)
return 1; return 1;
} }
void *__tls_get_addr(size_t *);
static void *do_dlsym(struct dso *p, const char *s, void *ra) static void *do_dlsym(struct dso *p, const char *s, void *ra)
{ {
size_t i; size_t i;

17
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
}
Loading…
Cancel
Save