summaryrefslogtreecommitdiff
path: root/src/ldso
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2015-04-13 18:07:10 -0400
committerRich Felker <dalias@aerifal.cx>2015-04-13 18:07:10 -0400
commit0f66fcec2584706116df70cf1db7f2f8815f4444 (patch)
tree72d239c570ee75e3abbe8f1c390470f29b61073c /src/ldso
parentf630df09b1fd954eda16e2f779da0b5ecc9d80d3 (diff)
downloadmusl-0f66fcec2584706116df70cf1db7f2f8815f4444.tar.gz
stabilize dynamic linker's layout of static TLS
previously, the layout of the static TLS block was perturbed by the size of the dtv; dtv size increasing from 0 to 1 perturbed both TLS arch types, and the TLS-above-TP type's layout was perturbed by the specific number of dtv slots (libraries with TLS). this behavior made it virtually impossible to setup a tentative thread pointer address before loading libraries and keep it unchanged as long as the libraries' TLS size/alignment requirements fit. the new code fixes the location of the dtv and pthread structure at opposite ends of the static TLS block so that they will not move unless size or alignment changes.
Diffstat (limited to 'src/ldso')
-rw-r--r--src/ldso/dynlink.c15
1 files changed, 6 insertions, 9 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c
index 1008e3ea..b049142b 100644
--- a/src/ldso/dynlink.c
+++ b/src/ldso/dynlink.c
@@ -1025,17 +1025,11 @@ void *__copy_tls(unsigned char *mem)
{
pthread_t td;
struct dso *p;
-
- void **dtv = (void *)mem;
- dtv[0] = (void *)tls_cnt;
- if (!tls_cnt) {
- td = (void *)(dtv+1);
- td->dtv = td->dtv_copy = dtv;
- return td;
- }
+ void **dtv;
#ifdef TLS_ABOVE_TP
- mem += sizeof(void *) * (tls_cnt+1);
+ dtv = (void **)(mem + libc.tls_size) - (tls_cnt + 1);
+
mem += -((uintptr_t)mem + sizeof(struct pthread)) & (tls_align-1);
td = (pthread_t)mem;
mem += sizeof(struct pthread);
@@ -1046,6 +1040,8 @@ void *__copy_tls(unsigned char *mem)
memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
}
#else
+ dtv = (void **)mem;
+
mem += libc.tls_size - sizeof(struct pthread);
mem -= (uintptr_t)mem & (tls_align-1);
td = (pthread_t)mem;
@@ -1056,6 +1052,7 @@ void *__copy_tls(unsigned char *mem)
memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
}
#endif
+ dtv[0] = (void *)tls_cnt;
td->dtv = td->dtv_copy = dtv;
return td;
}