diff options
| -rw-r--r-- | src/env/__init_tls.c | 10 | ||||
| -rw-r--r-- | src/ldso/dynlink.c | 94 | 
2 files changed, 77 insertions, 27 deletions
| diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c index 4a840cf2..aff388bd 100644 --- a/src/env/__init_tls.c +++ b/src/env/__init_tls.c @@ -7,13 +7,14 @@  #ifndef SHARED  static void *image; -static size_t len, bss, align; +static size_t len, size, align;  void *__copy_tls(unsigned char *mem, size_t cnt)  { +	mem += -size & (4*sizeof(size_t)-1);  	mem += ((uintptr_t)image - (uintptr_t)mem) & (align-1);  	memcpy(mem, image, len); -	return mem + len + bss; +	return mem + size;  }  static void *simple(void *p) @@ -53,13 +54,12 @@ void __init_tls(size_t *auxv)  	}  	if (!tls_phdr) return; -	libc.tls_size = len+bss+align+4*sizeof(size_t)+sizeof(struct pthread); +	libc.tls_size = size+align+8*sizeof(size_t)+sizeof(struct pthread);  	image = (void *)(base + tls_phdr->p_vaddr);  	len = tls_phdr->p_filesz; -	bss = tls_phdr->p_memsz - len; +	size = tls_phdr->p_memsz;  	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(); diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 1447e205..4e0b9f4e 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -67,6 +67,8 @@ struct dso {  	char relocated;  	char constructed;  	struct dso **deps; +	void *tls_image; +	size_t tls_len, tls_size, tls_align, tls_id;  	char *shortname;  	char buf[];  }; @@ -74,6 +76,7 @@ struct dso {  #include "reloc.h"  void __init_ssp(size_t *); +void *__install_initial_tls(void *);  static struct dso *head, *tail, *libc;  static char *env_path, *sys_path, *r_path; @@ -86,6 +89,7 @@ static jmp_buf rtld_fail;  static pthread_rwlock_t lock;  static struct debug debug;  static size_t *auxv; +static size_t tls_cnt, tls_size;  struct debug *_dl_debug_addr = &debug; @@ -278,7 +282,7 @@ static void reclaim_gaps(unsigned char *base, Phdr *ph, size_t phent, size_t phc  	}  } -static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dynp) +static void *map_library(int fd, struct dso *dso)  {  	Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];  	size_t phsize; @@ -290,6 +294,7 @@ static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dy  	unsigned prot;  	unsigned char *map, *base;  	size_t dyn; +	size_t tls_image=0;  	size_t i;  	ssize_t l = read(fd, buf, sizeof buf); @@ -306,6 +311,12 @@ static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dy  	for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {  		if (ph->p_type == PT_DYNAMIC)  			dyn = ph->p_vaddr; +		if (ph->p_type == PT_TLS) { +			tls_image = ph->p_vaddr; +			dso->tls_align = ph->p_align; +			dso->tls_len = ph->p_filesz; +			dso->tls_size = ph->p_memsz; +		}  		if (ph->p_type != PT_LOAD) continue;  		if (ph->p_vaddr < addr_min) {  			addr_min = ph->p_vaddr; @@ -360,9 +371,11 @@ static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dy  		}  	if (!runtime) reclaim_gaps(base, (void *)((char *)buf + eh->e_phoff),  		eh->e_phentsize, eh->e_phnum); -	*lenp = map_len; -	*basep = base; -	*dynp = dyn; +	dso->map = map; +	dso->map_len = map_len; +	dso->base = base; +	dso->dynv = (void *)(base+dyn); +	if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);  	return map;  error:  	munmap(map, map_len); @@ -402,7 +415,7 @@ static struct dso *load_library(const char *name)  	const char *pathname;  	unsigned char *base, *map;  	size_t dyno, map_len; -	struct dso *p; +	struct dso *p, temp_dso = {0};  	int fd;  	struct stat st; @@ -469,21 +482,21 @@ static struct dso *load_library(const char *name)  			return p;  		}  	} -	map = map_library(fd, &map_len, &base, &dyno); +	map = map_library(fd, &temp_dso);  	close(fd);  	if (!map) return 0; -	p = calloc(1, sizeof *p + strlen(pathname) + 1); +	p = malloc(sizeof *p + strlen(pathname) + 1);  	if (!p) {  		munmap(map, map_len);  		return 0;  	} - -	p->map = map; -	p->map_len = map_len; -	p->base = base; -	p->dynv = (void *)(base + dyno); +	memcpy(p, &temp_dso, sizeof temp_dso);  	decode_dyn(p); - +	if (p->tls_image) { +		p->tls_id = ++tls_cnt; +		tls_size += p->tls_size + p->tls_align + 8*sizeof(size_t) - 1 +			& -4*sizeof(size_t); +	}  	p->dev = st.st_dev;  	p->ino = st.st_ino;  	p->refcnt = 1; @@ -622,6 +635,25 @@ void _dl_debug_state(void)  {  } +void *__copy_tls(unsigned char *mem, size_t cnt) +{ +	struct dso *p; +	void **dtv = (void *)mem; +	dtv[0] = (void *)cnt; +	mem = (void *)(dtv + cnt + 1); +	for (p=tail; p; p=p->prev) { +		if (p->tls_id-1 >= cnt) continue; +		mem += -p->tls_len & (4*sizeof(size_t)-1); +		mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) +			& (p->tls_align-1); +		dtv[p->tls_id] = mem; +		memcpy(mem, p->tls_image, p->tls_len); +		mem += p->tls_size; +	} +	((pthread_t)mem)->dtv = dtv; +	return mem; +} +  void *__dynlink(int argc, char **argv)  {  	size_t aux[AUX_CNT] = {0}; @@ -676,6 +708,7 @@ void *__dynlink(int argc, char **argv)  	if (aux[AT_PHDR]) {  		size_t interp_off = 0; +		size_t tls_image = 0;  		/* Find load address of the main program, via AT_PHDR vs PT_PHDR. */  		phdr = (void *)aux[AT_PHDR];  		for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { @@ -683,7 +716,14 @@ void *__dynlink(int argc, char **argv)  				app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);  			else if (phdr->p_type == PT_INTERP)  				interp_off = (size_t)phdr->p_vaddr; +			else if (phdr->p_type == PT_TLS) { +				tls_image = phdr->p_vaddr; +				app->tls_len = phdr->p_filesz; +				app->tls_size = phdr->p_memsz; +				app->tls_align = phdr->p_align; +			}  		} +		if (app->tls_size) app->tls_image = (char *)app->base + tls_image;  		if (interp_off) lib->name = (char *)app->base + interp_off;  		app->name = argv[0];  		app->dynv = (void *)(app->base + find_dyn( @@ -709,7 +749,7 @@ void *__dynlink(int argc, char **argv)  			_exit(1);  		}  		runtime = 1; -		ehdr = (void *)map_library(fd, &app->map_len, &app->base, &dyno); +		ehdr = (void *)map_library(fd, app);  		if (!ehdr) {  			dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]);  			_exit(1); @@ -718,9 +758,13 @@ void *__dynlink(int argc, char **argv)  		close(fd);  		lib->name = ldname;  		app->name = argv[0]; -		app->dynv = (void *)(app->base + dyno);  		aux[AT_ENTRY] = ehdr->e_entry;  	} +	if (app->tls_size) { +		app->tls_id = ++tls_cnt; +		tls_size += app->tls_size+app->tls_align + 8*sizeof(size_t)-1 +			& -4*sizeof(size_t); +	}  	app->global = 1;  	app->constructed = 1;  	decode_dyn(app); @@ -791,8 +835,19 @@ 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); +	tls_size += sizeof(struct pthread) + 4*sizeof(size_t); +	__libc.tls_size = tls_size; +	__libc.tls_cnt = tls_cnt; +	if (tls_cnt) { +		void *mem = mmap(0, __libc.tls_size, PROT_READ|PROT_WRITE, +			MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +		if (mem==MAP_FAILED || +		    !__install_initial_tls(__copy_tls(mem, tls_cnt))) { +			dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n", +				argv[0], tls_size); +			_exit(127); +		} +	}  	if (ssp_used) __init_ssp(auxv);  	do_init_fini(tail); @@ -807,11 +862,6 @@ 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; | 
