diff options
Diffstat (limited to 'src/ldso')
-rw-r--r-- | src/ldso/dynlink.c | 22 |
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]; } |