about summary refs log tree commit diff
path: root/src/env
diff options
context:
space:
mode:
Diffstat (limited to 'src/env')
-rw-r--r--src/env/__init_tls.c55
-rw-r--r--src/env/__stack_chk_fail.c8
2 files changed, 50 insertions, 13 deletions
diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c
index dbfe62e7..8ac0036b 100644
--- a/src/env/__init_tls.c
+++ b/src/env/__init_tls.c
@@ -7,8 +7,28 @@
 #include "atomic.h"
 #include "syscall.h"
 
+int __init_tp(void *p)
+{
+	pthread_t td = p;
+	td->self = td;
+	if (__set_thread_area(TP_ADJ(p)) < 0)
+		return -1;
+	td->tid = td->pid = __syscall(SYS_set_tid_address, &td->tid);
+	td->errno_ptr = &td->errno_val;
+	/* Currently, both of these predicates depend in the same thing:
+	 * successful initialization of the thread pointer. However, in
+	 * the future, we may support setups where setting the thread
+	 * pointer is possible but threads other than the main thread
+	 * cannot work, so it's best to keep the predicates separate. */
+	libc.has_thread_pointer = 1;
+	libc.can_do_threads = 1;
+	return 0;
+}
+
 #ifndef SHARED
 
+static long long builtin_tls[(sizeof(struct pthread) + 64)/sizeof(long long)];
+
 struct tls_image {
 	void *image;
 	size_t len, size, align;
@@ -62,10 +82,11 @@ typedef Elf64_Phdr Phdr;
 
 void __init_tls(size_t *aux)
 {
-	unsigned char *p, *mem;
+	unsigned char *p;
 	size_t n;
 	Phdr *phdr, *tls_phdr=0;
 	size_t base = 0;
+	void *mem;
 
 	libc.tls_size = sizeof(struct pthread);
 
@@ -76,28 +97,38 @@ void __init_tls(size_t *aux)
 		if (phdr->p_type == PT_TLS)
 			tls_phdr = phdr;
 	}
-	if (!tls_phdr) return;
 
-	T.image = (void *)(base + tls_phdr->p_vaddr);
-	T.len = tls_phdr->p_filesz;
-	T.size = tls_phdr->p_memsz;
-	T.align = tls_phdr->p_align;
+	if (tls_phdr) {
+		T.image = (void *)(base + tls_phdr->p_vaddr);
+		T.len = tls_phdr->p_filesz;
+		T.size = tls_phdr->p_memsz;
+		T.align = tls_phdr->p_align;
+	}
 
 	T.size += (-T.size - (uintptr_t)T.image) & (T.align-1);
 	if (T.align < 4*sizeof(size_t)) T.align = 4*sizeof(size_t);
 
 	libc.tls_size = 2*sizeof(void *)+T.size+T.align+sizeof(struct pthread);
 
-	mem = (void *)__syscall(
+	if (libc.tls_size > sizeof builtin_tls) {
+		mem = (void *)__syscall(
 #ifdef SYS_mmap2
-		SYS_mmap2,
+			SYS_mmap2,
 #else
-		SYS_mmap,
+			SYS_mmap,
 #endif
-		0, libc.tls_size, PROT_READ|PROT_WRITE,
-		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+			0, libc.tls_size, PROT_READ|PROT_WRITE,
+			MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+		/* -4095...-1 cast to void * will crash on dereference anyway,
+		 * so don't bloat the init code checking for error codes and
+		 * explicitly calling a_crash(). */
+	} else {
+		mem = builtin_tls;
+	}
 
-	if (!__install_initial_tls(__copy_tls(mem))) a_crash();
+	/* Failure to initialize thread pointer is fatal if TLS is used. */
+	if (__init_tp(__copy_tls(mem)) < 0 && tls_phdr)
+		a_crash();
 }
 #else
 void __init_tls(size_t *auxv) { }
diff --git a/src/env/__stack_chk_fail.c b/src/env/__stack_chk_fail.c
index daa1b078..00634d38 100644
--- a/src/env/__stack_chk_fail.c
+++ b/src/env/__stack_chk_fail.c
@@ -7,7 +7,13 @@ uintptr_t __stack_chk_guard;
 
 void __init_ssp(void *entropy)
 {
-	pthread_t self = __pthread_self_init();
+	/* Here the thread pointer is used without checking whether
+	 * it is available; this will crash if it's not. However,
+	 * this function is only meant to be called if the program
+	 * being run uses stack protector, and in that case, it would
+	 * crash without a thread pointer anyway, so it's better to
+	 * crash early before there is state to be lost on crash. */
+	pthread_t self = __pthread_self();
 	uintptr_t canary;
 	if (entropy) memcpy(&canary, entropy, sizeof canary);
 	else canary = (uintptr_t)&canary * 1103515245;