diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/env/__init_tls.c | 71 | ||||
| -rw-r--r-- | src/env/__libc_start_main.c | 2 | ||||
| -rw-r--r-- | src/internal/libc.h | 1 | ||||
| -rw-r--r-- | src/ldso/dynlink.c | 10 | ||||
| -rw-r--r-- | src/thread/pthread_create.c | 23 | ||||
| -rw-r--r-- | src/thread/pthread_self.c | 24 | 
6 files changed, 117 insertions, 14 deletions
| diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c new file mode 100644 index 00000000..4a840cf2 --- /dev/null +++ b/src/env/__init_tls.c @@ -0,0 +1,71 @@ +#include <elf.h> +#include <limits.h> +#include "pthread_impl.h" +#include "libc.h" +#include "atomic.h" + +#ifndef SHARED + +static void *image; +static size_t len, bss, align; + +void *__copy_tls(unsigned char *mem, size_t cnt) +{ +	mem += ((uintptr_t)image - (uintptr_t)mem) & (align-1); +	memcpy(mem, image, len); +	return mem + len + bss; +} + +static void *simple(void *p) +{ +	*(void **)p = p; +	return __set_thread_area(p) ? 0 : p; +} + +weak_alias(simple, __install_initial_tls); + +void *__mmap(void *, size_t, int, int, int, off_t); + +#if ULONG_MAX == 0xffffffff +typedef Elf32_Phdr Phdr; +#else +typedef Elf64_Phdr Phdr; +#endif + +#define AUX_CNT 6 + +void __init_tls(size_t *auxv) +{ +	size_t i, aux[AUX_CNT] = { 0 }; +	unsigned char *p, *mem; +	size_t n, d; +	Phdr *phdr, *tls_phdr=0; +	size_t base = 0; + +	for (; auxv[0]; auxv+=2) if (auxv[0]<AUX_CNT) aux[auxv[0]] = auxv[1]; +	p = (void *)aux[AT_PHDR]; +	for (p=(void *)aux[AT_PHDR]; aux[AT_PHNUM]--; p+=aux[AT_PHENT]) { +		phdr = (void *)p; +		if (phdr->p_type == PT_PHDR) +			base = aux[AT_PHDR] - phdr->p_vaddr; +		if (phdr->p_type == PT_TLS) +			tls_phdr = phdr; +	} +	if (!tls_phdr) return; + +	libc.tls_size = len+bss+align+4*sizeof(size_t)+sizeof(struct pthread); + +	image = (void *)(base + tls_phdr->p_vaddr); +	len = tls_phdr->p_filesz; +	bss = tls_phdr->p_memsz - len; +	align = tls_phdr->p_align; +	if (align < 4*sizeof(size_t)) align = 4*sizeof(size_t); +	mem = __mmap(0, libc.tls_size, PROT_READ|PROT_WRITE, +		MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +	if (mem == MAP_FAILED) a_crash(); + +	if (!__install_initial_tls(__copy_tls(mem, 0))) a_crash(); +} +#else +void __init_tls(size_t *auxv) { } +#endif diff --git a/src/env/__libc_start_main.c b/src/env/__libc_start_main.c index f31222b2..a38569d5 100644 --- a/src/env/__libc_start_main.c +++ b/src/env/__libc_start_main.c @@ -1,5 +1,6 @@  #include "libc.h" +void __init_tls(size_t *);  void __init_security(size_t *);  int __libc_start_main( @@ -15,6 +16,7 @@ int __libc_start_main(  	libc.ldso_fini = ldso_fini;  	libc.fini = fini; +	__init_tls((void *)auxv);  	__init_security((void *)auxv);  	/* Execute constructors (static) linked into the application */ diff --git a/src/internal/libc.h b/src/internal/libc.h index ea863d67..ca06f319 100644 --- a/src/internal/libc.h +++ b/src/internal/libc.h @@ -16,6 +16,7 @@ struct __libc {  	int canceldisable;  	FILE *ofl_head;  	int ofl_lock[2]; +	volatile size_t tls_size, tls_cnt;  };  extern size_t __hwcap; diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 960e0898..1447e205 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -17,6 +17,9 @@  #include <pthread.h>  #include <ctype.h>  #include <dlfcn.h> +#include "pthread_impl.h" +#include "libc.h" +#undef libc  static int errflag;  static char errbuf[128]; @@ -788,6 +791,8 @@ void *__dynlink(int argc, char **argv)  	debug.state = 0;  	_dl_debug_state(); +	/* Stand-in until real TLS support is added to dynamic linker */ +	__libc.tls_size = sizeof(struct pthread) + 4*sizeof(size_t);  	if (ssp_used) __init_ssp(auxv);  	do_init_fini(tail); @@ -802,6 +807,11 @@ void *__dynlink(int argc, char **argv)  	return (void *)aux[AT_ENTRY];  } +void *__copy_tls(unsigned char *mem, size_t cnt) +{ +	return mem; +} +  void *dlopen(const char *file, int mode)  {  	struct dso *volatile p, *orig_tail = tail, *next; diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index d8b8f0fc..f53fc1ba 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -84,6 +84,8 @@ static void init_file_lock(FILE *f)  	if (f && f->lock<0) f->lock = 0;  } +void *__copy_tls(unsigned char *, size_t); +  int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr, void *(*entry)(void *), void *restrict arg)  {  	int ret; @@ -92,6 +94,8 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr,  	struct pthread *self = pthread_self(), *new;  	unsigned char *map, *stack, *tsd;  	unsigned flags = 0x7d8f00; +	size_t tls_cnt = libc.tls_cnt; +	size_t tls_size = libc.tls_size;  	if (!self) return ENOSYS;  	if (!libc.threaded) { @@ -109,15 +113,24 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr,  	} else {  		if (attr) {  			guard = ROUND(attr->_a_guardsize + DEFAULT_GUARD_SIZE); -			size = guard + ROUND(attr->_a_stacksize + DEFAULT_STACK_SIZE); +			size = guard + ROUND(attr->_a_stacksize +				+ DEFAULT_STACK_SIZE + tls_size);  		}  		size += __pthread_tsd_size; -		map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); -		if (map == MAP_FAILED) return EAGAIN; -		if (guard) mprotect(map, guard, PROT_NONE); +		if (guard) { +			map = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); +			if (map == MAP_FAILED) return EAGAIN; +			if (mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { +				munmap(map, size); +				return EAGAIN; +			} +		} else { +			map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); +			if (map == MAP_FAILED) return EAGAIN; +		}  		tsd = map + size - __pthread_tsd_size;  	} -	new = (void *)(tsd - sizeof *new - PAGE_SIZE%sizeof *new); +	new = __copy_tls(tsd - tls_size, tls_cnt);  	new->map_base = map;  	new->map_size = size;  	new->pid = self->pid; diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c index a8cc80b5..a93d8129 100644 --- a/src/thread/pthread_self.c +++ b/src/thread/pthread_self.c @@ -1,6 +1,6 @@  #include "pthread_impl.h" -static struct pthread main_thread; +static struct pthread *main_thread = &(struct pthread){0};  /* pthread_key_create.c overrides this */  static const void *dummy[1] = { 0 }; @@ -10,14 +10,14 @@ static int init_main_thread()  {  	__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,  		SIGPT_SET, 0, __SYSCALL_SSLEN); -	if (__set_thread_area(&main_thread) < 0) return -1; -	main_thread.canceldisable = libc.canceldisable; -	main_thread.tsd = (void **)__pthread_tsd_main; -	main_thread.errno_ptr = __errno_location(); -	main_thread.self = &main_thread; -	main_thread.tid = main_thread.pid = -		__syscall(SYS_set_tid_address, &main_thread.tid); -	libc.main_thread = &main_thread; +	if (__set_thread_area(main_thread) < 0) return -1; +	main_thread->canceldisable = libc.canceldisable; +	main_thread->tsd = (void **)__pthread_tsd_main; +	main_thread->errno_ptr = __errno_location(); +	main_thread->self = main_thread; +	main_thread->tid = main_thread->pid = +		__syscall(SYS_set_tid_address, &main_thread->tid); +	libc.main_thread = main_thread;  	return 0;  } @@ -35,3 +35,9 @@ pthread_t __pthread_self_def()  weak_alias(__pthread_self_def, pthread_self);  weak_alias(__pthread_self_def, __pthread_self_init); + +void *__install_initial_tls(void *p) +{ +	main_thread = p; +	return __pthread_self_def(); +} | 
