summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzabolcs Nagy <nsz@port70.net>2019-05-13 18:47:11 +0000
committerRich Felker <dalias@aerifal.cx>2019-05-16 21:48:39 -0400
commita60b9e06861e56c0810bae0249b421e1758d281a (patch)
tree94cfc88638aa6a872e29be5df6690588e5a7275c
parent6104dae9088da7ffd9346671be867a43a4b03295 (diff)
downloadmusl-a60b9e06861e56c0810bae0249b421e1758d281a.tar.gz
fix tls offsets when p_vaddr%p_align != 0 on TLS_ABOVE_TP targets
currently the bfd linker does not seem to create tls segments where p_vaddr%p_align != 0, but this is valid in ELF and then the runtime computed tls offset must satisfy offset%p_align == (base+p_vaddr)%p_align and in case of local exec tls (main executable) the smallest such offset must be used (otherwise it is incompatible with the offset computed by the static linker). the !TLS_ABOVE_TP case is handled correctly (the offset is negative then in the formula). the ldso code for TLS_ABOVE_TP is changed so the static tls offset of each module satisfies the formula.
-rw-r--r--ldso/dynlink.c7
-rw-r--r--src/env/__init_tls.c3
2 files changed, 6 insertions, 4 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index 967f1fd9..1398ff45 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -1125,8 +1125,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
p->tls_id = ++tls_cnt;
tls_align = MAXP2(tls_align, p->tls.align);
#ifdef TLS_ABOVE_TP
- p->tls.offset = tls_offset + ( (tls_align-1) &
- -(tls_offset + (uintptr_t)p->tls.image) );
+ p->tls.offset = tls_offset + ( (p->tls.align-1) &
+ (-tls_offset + (uintptr_t)p->tls.image) );
tls_offset = p->tls.offset + p->tls.size;
#else
tls_offset += p->tls.size + p->tls.align - 1;
@@ -1796,7 +1796,8 @@ _Noreturn void __dls3(size_t *sp)
app.tls_id = tls_cnt = 1;
#ifdef TLS_ABOVE_TP
app.tls.offset = GAP_ABOVE_TP;
- app.tls.offset += -GAP_ABOVE_TP & (app.tls.align-1);
+ app.tls.offset += (-GAP_ABOVE_TP + (uintptr_t)app.tls.image)
+ & (app.tls.align-1);
tls_offset = app.tls.offset + app.tls.size;
#else
tls_offset = app.tls.offset = app.tls.size
diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c
index 5f12500c..772baba3 100644
--- a/src/env/__init_tls.c
+++ b/src/env/__init_tls.c
@@ -115,7 +115,8 @@ static void static_init_tls(size_t *aux)
& (main_tls.align-1);
#ifdef TLS_ABOVE_TP
main_tls.offset = GAP_ABOVE_TP;
- main_tls.offset += -GAP_ABOVE_TP & (main_tls.align-1);
+ main_tls.offset += (-GAP_ABOVE_TP + (uintptr_t)main_tls.image)
+ & (main_tls.align-1);
#else
main_tls.offset = main_tls.size;
#endif