diff options
-rw-r--r-- | src/ldso/dynlink.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index b049142b..31f59392 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -1159,7 +1159,15 @@ _Noreturn void __dls3(size_t *sp) char **argv = (void *)(sp+1); char **argv_orig = argv; char **envp = argv+argc+1; - void *initial_tls; + + /* Setup early thread pointer in builtin_tls for ldso/libc itself to + * use during dynamic linking. If possible it will also serve as the + * thread pointer at runtime. */ + libc.tls_size = sizeof builtin_tls; + if (__init_tp(__copy_tls((void *)builtin_tls)) < 0) { + dprintf(2, "%s: Thread-local storage not supported by kernel.\n", argv[0]); + _exit(127); + } /* Find aux vector just past environ[] */ for (i=argc+1; argv[i]; i++) @@ -1336,19 +1344,26 @@ _Noreturn void __dls3(size_t *sp) reloc_all(&app); update_tls_size(); - if (libc.tls_size > sizeof builtin_tls) { - initial_tls = calloc(libc.tls_size, 1); + if (libc.tls_size > sizeof builtin_tls || tls_align > MIN_TLS_ALIGN) { + void *initial_tls = calloc(libc.tls_size, 1); if (!initial_tls) { dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n", argv[0], libc.tls_size); _exit(127); } + if (__init_tp(__copy_tls(initial_tls)) < 0) { + dprintf(2, "%s: Failed to switch to new thread pointer.\n", argv[0]); + _exit(127); + } } else { - initial_tls = builtin_tls; - } - if (__init_tp(__copy_tls(initial_tls)) < 0 && tls_cnt) { - dprintf(2, "%s: Thread-local storage not supported by kernel.\n", argv[0]); - _exit(127); + size_t tmp_tls_size = libc.tls_size; + pthread_t self = __pthread_self(); + /* Temporarily set the tls size to the full size of + * builtin_tls so that __copy_tls will use the same layout + * as it did for before. Then check, just to be safe. */ + libc.tls_size = sizeof builtin_tls; + if (__copy_tls((void*)builtin_tls) != self) a_crash(); + libc.tls_size = tmp_tls_size; } static_tls_cnt = tls_cnt; |