diff options
Diffstat (limited to 'src/ldso/dynlink.c')
| -rw-r--r-- | src/ldso/dynlink.c | 140 | 
1 files changed, 54 insertions, 86 deletions
| diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index ac755d94..0326baf0 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -70,8 +70,8 @@ struct dso {  	char kernel_mapped;  	struct dso **deps, *needed_by;  	char *rpath_orig, *rpath; -	void *tls_image; -	size_t tls_len, tls_size, tls_align, tls_id, tls_offset; +	struct tls_module tls; +	size_t tls_id;  	size_t relro_start, relro_end;  	void **new_dtv;  	unsigned char *new_tls; @@ -99,6 +99,7 @@ struct symdef {  int __init_tp(void *);  void __init_libc(char **, char *); +void *__copy_tls(unsigned char *);  const char *__libc_get_version(void); @@ -123,6 +124,7 @@ static int noload;  static jmp_buf *rtld_fail;  static pthread_rwlock_t lock;  static struct debug debug; +static struct tls_module *tls_tail;  static size_t tls_cnt, tls_offset, tls_align = MIN_TLS_ALIGN;  static size_t static_tls_cnt;  static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE }; @@ -397,14 +399,14 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri  			break;  #ifdef TLS_ABOVE_TP  		case REL_TPOFF: -			*reloc_addr = tls_val + def.dso->tls_offset + TPOFF_K + addend; +			*reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend;  			break;  #else  		case REL_TPOFF: -			*reloc_addr = tls_val - def.dso->tls_offset + addend; +			*reloc_addr = tls_val - def.dso->tls.offset + addend;  			break;  		case REL_TPOFF_NEG: -			*reloc_addr = def.dso->tls_offset - tls_val + addend; +			*reloc_addr = def.dso->tls.offset - tls_val + addend;  			break;  #endif  		case REL_TLSDESC: @@ -426,10 +428,10 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri  			} else {  				reloc_addr[0] = (size_t)__tlsdesc_static;  #ifdef TLS_ABOVE_TP -				reloc_addr[1] = tls_val + def.dso->tls_offset +				reloc_addr[1] = tls_val + def.dso->tls.offset  					+ TPOFF_K + addend;  #else -				reloc_addr[1] = tls_val - def.dso->tls_offset +				reloc_addr[1] = tls_val - def.dso->tls.offset  					+ addend;  #endif  			} @@ -567,9 +569,9 @@ static void *map_library(int fd, struct dso *dso)  			dyn = ph->p_vaddr;  		} else 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; +			dso->tls.align = ph->p_align; +			dso->tls.len = ph->p_filesz; +			dso->tls.size = ph->p_memsz;  		} else if (ph->p_type == PT_GNU_RELRO) {  			dso->relro_start = ph->p_vaddr & -PAGE_SIZE;  			dso->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; @@ -694,7 +696,7 @@ static void *map_library(int fd, struct dso *dso)  done_mapping:  	dso->base = base;  	dso->dynv = laddr(dso, dyn); -	if (dso->tls_size) dso->tls_image = laddr(dso, tls_image); +	if (dso->tls.size) dso->tls.image = laddr(dso, tls_image);  	if (!runtime) reclaim_gaps(dso);  	free(allocated_buf);  	return map; @@ -1011,8 +1013,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by)  	 * extended DTV capable of storing an additional slot for  	 * the newly-loaded DSO. */  	alloc_size = sizeof *p + strlen(pathname) + 1; -	if (runtime && temp_dso.tls_image) { -		size_t per_th = temp_dso.tls_size + temp_dso.tls_align +	if (runtime && temp_dso.tls.image) { +		size_t per_th = temp_dso.tls.size + temp_dso.tls.align  			+ sizeof(void *) * (tls_cnt+3);  		n_th = libc.threads_minus_1 + 1;  		if (n_th > SSIZE_MAX / per_th) alloc_size = SIZE_MAX; @@ -1033,22 +1035,25 @@ static struct dso *load_library(const char *name, struct dso *needed_by)  	strcpy(p->name, pathname);  	/* Add a shortname only if name arg was not an explicit pathname. */  	if (pathname != name) p->shortname = strrchr(p->name, '/')+1; -	if (p->tls_image) { +	if (p->tls.image) {  		p->tls_id = ++tls_cnt; -		tls_align = MAXP2(tls_align, p->tls_align); +		tls_align = MAXP2(tls_align, p->tls.align);  #ifdef TLS_ABOVE_TP -		p->tls_offset = tls_offset + ( (tls_align-1) & -			-(tls_offset + (uintptr_t)p->tls_image) ); -		tls_offset += p->tls_size; +		p->tls.offset = tls_offset + ( (tls_align-1) & +			-(tls_offset + (uintptr_t)p->tls.image) ); +		tls_offset += p->tls.size;  #else -		tls_offset += p->tls_size + p->tls_align - 1; -		tls_offset -= (tls_offset + (uintptr_t)p->tls_image) -			& (p->tls_align-1); -		p->tls_offset = tls_offset; +		tls_offset += p->tls.size + p->tls.align - 1; +		tls_offset -= (tls_offset + (uintptr_t)p->tls.image) +			& (p->tls.align-1); +		p->tls.offset = tls_offset;  #endif  		p->new_dtv = (void *)(-sizeof(size_t) &  			(uintptr_t)(p->name+strlen(p->name)+sizeof(size_t)));  		p->new_tls = (void *)(p->new_dtv + n_th*(tls_cnt+1)); +		if (tls_tail) tls_tail->next = &p->tls; +		else libc.tls_head = &p->tls; +		tls_tail = &p->tls;  	}  	tail->next = p; @@ -1238,53 +1243,8 @@ static void dl_debug_state(void)  weak_alias(dl_debug_state, _dl_debug_state); -void __reset_tls() +void __init_tls(size_t *auxv)  { -	pthread_t self = __pthread_self(); -	struct dso *p; -	for (p=head; p; p=p->next) { -		if (!p->tls_id || !self->dtv[p->tls_id]) continue; -		memcpy(self->dtv[p->tls_id], p->tls_image, p->tls_len); -		memset((char *)self->dtv[p->tls_id]+p->tls_len, 0, -			p->tls_size - p->tls_len); -		if (p->tls_id == (size_t)self->dtv[0]) break; -	} -} - -void *__copy_tls(unsigned char *mem) -{ -	pthread_t td; -	struct dso *p; -	void **dtv; - -#ifdef TLS_ABOVE_TP -	dtv = (void **)(mem + libc.tls_size) - (tls_cnt + 1); - -	mem += -((uintptr_t)mem + sizeof(struct pthread)) & (tls_align-1); -	td = (pthread_t)mem; -	mem += sizeof(struct pthread); - -	for (p=head; p; p=p->next) { -		if (!p->tls_id) continue; -		dtv[p->tls_id] = mem + p->tls_offset; -		memcpy(dtv[p->tls_id], p->tls_image, p->tls_len); -	} -#else -	dtv = (void **)mem; - -	mem += libc.tls_size - sizeof(struct pthread); -	mem -= (uintptr_t)mem & (tls_align-1); -	td = (pthread_t)mem; - -	for (p=head; p; p=p->next) { -		if (!p->tls_id) continue; -		dtv[p->tls_id] = mem - p->tls_offset; -		memcpy(dtv[p->tls_id], p->tls_image, p->tls_len); -	} -#endif -	dtv[0] = (void *)tls_cnt; -	td->dtv = td->dtv_copy = dtv; -	return td;  }  __attribute__((__visibility__("hidden"))) @@ -1321,12 +1281,12 @@ void *__tls_get_new(size_t *v)  	unsigned char *mem;  	for (p=head; ; p=p->next) {  		if (!p->tls_id || self->dtv[p->tls_id]) continue; -		mem = p->new_tls + (p->tls_size + p->tls_align) +		mem = p->new_tls + (p->tls.size + p->tls.align)  			* a_fetch_add(&p->new_tls_idx,1); -		mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) -			& (p->tls_align-1); +		mem += ((uintptr_t)p->tls.image - (uintptr_t)mem) +			& (p->tls.align-1);  		self->dtv[p->tls_id] = mem; -		memcpy(mem, p->tls_image, p->tls_len); +		memcpy(mem, p->tls.image, p->tls.len);  		if (p->tls_id == v[0]) break;  	}  	__restore_sigs(&set); @@ -1335,6 +1295,8 @@ void *__tls_get_new(size_t *v)  static void update_tls_size()  { +	libc.tls_cnt = tls_cnt; +	libc.tls_align = tls_align;  	libc.tls_size = ALIGN(  		(1+tls_cnt) * sizeof(void *) +  		tls_offset + @@ -1445,6 +1407,7 @@ _Noreturn void __dls3(size_t *sp)  	 * use during dynamic linking. If possible it will also serve as the  	 * thread pointer at runtime. */  	libc.tls_size = sizeof builtin_tls; +	libc.tls_align = tls_align;  	if (__init_tp(__copy_tls((void *)builtin_tls)) < 0) {  		a_crash();  	} @@ -1472,13 +1435,13 @@ _Noreturn void __dls3(size_t *sp)  				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; +				app.tls.len = phdr->p_filesz; +				app.tls.size = phdr->p_memsz; +				app.tls.align = phdr->p_align;  			}  		}  		if (DL_FDPIC) app.loadmap = app_loadmap; -		if (app.tls_size) app.tls_image = laddr(&app, tls_image); +		if (app.tls.size) app.tls.image = laddr(&app, tls_image);  		if (interp_off) ldso.name = laddr(&app, interp_off);  		if ((aux[0] & (1UL<<AT_EXECFN))  		    && strncmp((char *)aux[AT_EXECFN], "/proc/", 6)) @@ -1547,19 +1510,20 @@ _Noreturn void __dls3(size_t *sp)  			dprintf(1, "\t%s (%p)\n", ldso.name, ldso.base);  		}  	} -	if (app.tls_size) { +	if (app.tls.size) { +		libc.tls_head = &app.tls;  		app.tls_id = tls_cnt = 1;  #ifdef TLS_ABOVE_TP -		app.tls_offset = 0; -		tls_offset = app.tls_size -			+ ( -((uintptr_t)app.tls_image + app.tls_size) -			& (app.tls_align-1) ); +		app.tls.offset = 0; +		tls_offset = app.tls.size +			+ ( -((uintptr_t)app.tls.image + app.tls.size) +			& (app.tls.align-1) );  #else -		tls_offset = app.tls_offset = app.tls_size -			+ ( -((uintptr_t)app.tls_image + app.tls_size) -			& (app.tls_align-1) ); +		tls_offset = app.tls.offset = app.tls.size +			+ ( -((uintptr_t)app.tls.image + app.tls.size) +			& (app.tls.align-1) );  #endif -		tls_align = MAXP2(tls_align, app.tls_align); +		tls_align = MAXP2(tls_align, app.tls.align);  	}  	app.global = 1;  	decode_dyn(&app); @@ -1668,6 +1632,7 @@ _Noreturn void __dls3(size_t *sp)  void *dlopen(const char *file, int mode)  {  	struct dso *volatile p, *orig_tail, *next; +	struct tls_module *orig_tls_tail;  	size_t orig_tls_cnt, orig_tls_offset, orig_tls_align;  	size_t i;  	int cs; @@ -1680,6 +1645,7 @@ void *dlopen(const char *file, int mode)  	__inhibit_ptc();  	p = 0; +	orig_tls_tail = tls_tail;  	orig_tls_cnt = tls_cnt;  	orig_tls_offset = tls_offset;  	orig_tls_align = tls_align; @@ -1706,6 +1672,8 @@ void *dlopen(const char *file, int mode)  			unmap_library(p);  			free(p);  		} +		if (!orig_tls_tail) libc.tls_head = 0; +		tls_tail = orig_tls_tail;  		tls_cnt = orig_tls_cnt;  		tls_offset = orig_tls_offset;  		tls_align = orig_tls_align; @@ -1922,7 +1890,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void  		info.dlpi_adds      = gencnt;  		info.dlpi_subs      = 0;  		info.dlpi_tls_modid = current->tls_id; -		info.dlpi_tls_data  = current->tls_image; +		info.dlpi_tls_data  = current->tls.image;  		ret = (callback)(&info, sizeof (info), data); | 
