summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ldso/dynlink.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 66bca506..2b6f0c94 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -1034,13 +1034,13 @@ void *__copy_tls(unsigned char *mem)
void *__tls_get_addr(size_t *v)
{
pthread_t self = __pthread_self();
- if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]])
+ 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);
- if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]]) {
+ if (v[0]<=(size_t)self->dtv[0]) {
pthread_sigmask(SIG_SETMASK, &set, 0);
return (char *)self->dtv[v[0]]+v[1];
}
@@ -1062,12 +1062,18 @@ void *__tls_get_addr(size_t *v)
self->dtv = newdtv;
}
- /* Get new TLS memory from new DSO */
- unsigned char *mem = p->new_tls +
- (p->tls_size + p->tls_align) * a_fetch_add(&p->new_tls_idx,1);
- mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) & (p->tls_align-1);
- self->dtv[v[0]] = mem;
- memcpy(mem, p->tls_image, p->tls_len);
+ /* Get new TLS memory from all new DSOs up to the requested one */
+ unsigned char *mem;
+ for (p=head; ; p=p->next) {
+ if (!p->tls_id || self->dtv[p->tls_id]) continue;
+ mem = p->new_tls + (p->tls_size + p->tls_align)
+ * a_fetch_add(&p->new_tls_idx,1);
+ mem += ((uintptr_t)p->tls_image - (uintptr_t)mem)
+ & (p->tls_align-1);
+ self->dtv[p->tls_id] = mem;
+ memcpy(mem, p->tls_image, p->tls_len);
+ if (p->tls_id == v[0]) break;
+ }
pthread_sigmask(SIG_SETMASK, &set, 0);
return mem + v[1];
}