From 610c5a8524c3d6cd3ac5a5f1231422e7648a3791 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Sat, 2 Jun 2018 01:52:01 +0200 Subject: fix TLS layout of TLS variant I when there is a gap above TP In TLS variant I the TLS is above TP (or above a fixed offset from TP) but on some targets there is a reserved gap above TP before TLS starts. This matters for the local-exec tls access model when the offsets of TLS variables from the TP are hard coded by the linker into the executable, so the libc must compute these offsets the same way as the linker. The tls offset of the main module has to be alignup(GAP_ABOVE_TP, main_tls_align). If there is no TLS in the main module then the gap can be ignored since musl does not use it and the tls access models of shared libraries are not affected. The previous setup only worked if (tls_align & -GAP_ABOVE_TP) == 0 (i.e. TLS did not require large alignment) because the gap was treated as a fixed offset from TP. Now the TP points at the end of the pthread struct (which is aligned) and there is a gap above it (which may also need alignment). The fix required changing TP_ADJ and __pthread_self on affected targets (aarch64, arm and sh) and in the tlsdesc asm the offset to access the dtv changed too. --- src/env/__init_tls.c | 10 ++++++++-- src/ldso/aarch64/tlsdesc.s | 5 ++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c index 1c5d98a0..31d324a8 100644 --- a/src/env/__init_tls.c +++ b/src/env/__init_tls.c @@ -104,13 +104,19 @@ static void static_init_tls(size_t *aux) main_tls.size += (-main_tls.size - (uintptr_t)main_tls.image) & (main_tls.align-1); - if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; -#ifndef TLS_ABOVE_TP +#ifdef TLS_ABOVE_TP + main_tls.offset = GAP_ABOVE_TP; + main_tls.offset += -GAP_ABOVE_TP & (main_tls.align-1); +#else main_tls.offset = main_tls.size; #endif + if (main_tls.align < MIN_TLS_ALIGN) main_tls.align = MIN_TLS_ALIGN; libc.tls_align = main_tls.align; libc.tls_size = 2*sizeof(void *) + sizeof(struct pthread) +#ifdef TLS_ABOVE_TP + + main_tls.offset +#endif + main_tls.size + main_tls.align + MIN_TLS_ALIGN-1 & -MIN_TLS_ALIGN; diff --git a/src/ldso/aarch64/tlsdesc.s b/src/ldso/aarch64/tlsdesc.s index 8ed5c267..8e4004d7 100644 --- a/src/ldso/aarch64/tlsdesc.s +++ b/src/ldso/aarch64/tlsdesc.s @@ -14,7 +14,7 @@ __tlsdesc_static: // size_t __tlsdesc_dynamic(size_t *a) // { // struct {size_t modidx,off;} *p = (void*)a[1]; -// size_t *dtv = *(size_t**)(tp + 16 - 8); +// size_t *dtv = *(size_t**)(tp - 8); // if (p->modidx <= dtv[0]) // return dtv[p->modidx] + p->off - tp; // return __tls_get_new(p) - tp; @@ -28,8 +28,7 @@ __tlsdesc_dynamic: mrs x1,tpidr_el0 // tp ldr x0,[x0,#8] // p ldr x2,[x0] // p->modidx - add x3,x1,#8 - ldr x3,[x3] // dtv + ldr x3,[x1,#-8] // dtv ldr x4,[x3] // dtv[0] cmp x2,x4 b.hi 1f -- cgit v1.2.1