about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/ldso/dynlink.c31
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;