about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ldso/dynlink.c25
-rw-r--r--src/env/__init_tls.c16
-rw-r--r--src/env/__reset_tls.c9
-rw-r--r--src/internal/pthread_impl.h5
-rw-r--r--src/thread/__tls_get_addr.c4
5 files changed, 28 insertions, 31 deletions
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index c2892b90..a3ca3cdf 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -72,7 +72,7 @@ struct dso {
 	struct tls_module tls;
 	size_t tls_id;
 	size_t relro_start, relro_end;
-	void **new_dtv;
+	uintptr_t *new_dtv;
 	unsigned char *new_tls;
 	volatile int new_dtv_idx, new_tls_idx;
 	struct td_index *td_index;
@@ -445,7 +445,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
 				new->next = dso->td_index;
 				dso->td_index = new;
 				new->args[0] = def.dso->tls_id;
-				new->args[1] = tls_val + addend;
+				new->args[1] = tls_val + addend - DTP_OFFSET;
 				reloc_addr[0] = (size_t)__tlsdesc_dynamic;
 				reloc_addr[1] = (size_t)new;
 			} else {
@@ -1345,9 +1345,9 @@ hidden void *__tls_get_new(tls_mod_off_t *v)
 	/* Block signals to make accessing new TLS async-signal-safe */
 	sigset_t set;
 	__block_all_sigs(&set);
-	if (v[0]<=(size_t)self->dtv[0]) {
+	if (v[0] <= self->dtv[0]) {
 		__restore_sigs(&set);
-		return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET;
+		return (void *)(self->dtv[v[0]] + v[1]);
 	}
 
 	/* This is safe without any locks held because, if the caller
@@ -1357,15 +1357,12 @@ hidden void *__tls_get_new(tls_mod_off_t *v)
 	struct dso *p;
 	for (p=head; p->tls_id != v[0]; p=p->next);
 
-	/* Get new DTV space from new DSO if needed */
-	if (v[0] > (size_t)self->dtv[0]) {
-		void **newdtv = p->new_dtv +
-			(v[0]+1)*a_fetch_add(&p->new_dtv_idx,1);
-		memcpy(newdtv, self->dtv,
-			((size_t)self->dtv[0]+1) * sizeof(void *));
-		newdtv[0] = (void *)v[0];
-		self->dtv = self->dtv_copy = newdtv;
-	}
+	/* Get new DTV space from new DSO */
+	uintptr_t *newdtv = p->new_dtv +
+		(v[0]+1)*a_fetch_add(&p->new_dtv_idx,1);
+	memcpy(newdtv, self->dtv, (self->dtv[0]+1) * sizeof(uintptr_t));
+	newdtv[0] = v[0];
+	self->dtv = self->dtv_copy = newdtv;
 
 	/* Get new TLS memory from all new DSOs up to the requested one */
 	unsigned char *mem;
@@ -1375,7 +1372,7 @@ hidden void *__tls_get_new(tls_mod_off_t *v)
 			* a_fetch_add(&p->new_tls_idx,1);
 		mem += ((uintptr_t)p->tls.image - (uintptr_t)mem)
 			& (p->tls.align-1);
-		self->dtv[p->tls_id] = mem;
+		self->dtv[p->tls_id] = (uintptr_t)mem + DTP_OFFSET;
 		memcpy(mem, p->tls.image, p->tls.len);
 		if (p->tls_id == v[0]) break;
 	}
diff --git a/src/env/__init_tls.c b/src/env/__init_tls.c
index 96d0e284..842886f6 100644
--- a/src/env/__init_tls.c
+++ b/src/env/__init_tls.c
@@ -36,32 +36,32 @@ void *__copy_tls(unsigned char *mem)
 	pthread_t td;
 	struct tls_module *p;
 	size_t i;
-	void **dtv;
+	uintptr_t *dtv;
 
 #ifdef TLS_ABOVE_TP
-	dtv = (void **)(mem + libc.tls_size) - (libc.tls_cnt + 1);
+	dtv = (uintptr_t*)(mem + libc.tls_size) - (libc.tls_cnt + 1);
 
 	mem += -((uintptr_t)mem + sizeof(struct pthread)) & (libc.tls_align-1);
 	td = (pthread_t)mem;
 	mem += sizeof(struct pthread);
 
 	for (i=1, p=libc.tls_head; p; i++, p=p->next) {
-		dtv[i] = mem + p->offset;
-		memcpy(dtv[i], p->image, p->len);
+		dtv[i] = (uintptr_t)(mem + p->offset) + DTP_OFFSET;
+		memcpy(mem + p->offset, p->image, p->len);
 	}
 #else
-	dtv = (void **)mem;
+	dtv = (uintptr_t *)mem;
 
 	mem += libc.tls_size - sizeof(struct pthread);
 	mem -= (uintptr_t)mem & (libc.tls_align-1);
 	td = (pthread_t)mem;
 
 	for (i=1, p=libc.tls_head; p; i++, p=p->next) {
-		dtv[i] = mem - p->offset;
-		memcpy(dtv[i], p->image, p->len);
+		dtv[i] = (uintptr_t)(mem - p->offset) + DTP_OFFSET;
+		memcpy(mem - p->offset, p->image, p->len);
 	}
 #endif
-	dtv[0] = (void *)libc.tls_cnt;
+	dtv[0] = libc.tls_cnt;
 	td->dtv = td->dtv_copy = dtv;
 	return td;
 }
diff --git a/src/env/__reset_tls.c b/src/env/__reset_tls.c
index 677e57f5..15685bc6 100644
--- a/src/env/__reset_tls.c
+++ b/src/env/__reset_tls.c
@@ -6,11 +6,10 @@ void __reset_tls()
 {
 	pthread_t self = __pthread_self();
 	struct tls_module *p;
-	size_t i, n = (size_t)self->dtv[0];
+	size_t i, n = self->dtv[0];
 	if (n) for (p=libc.tls_head, i=1; i<=n; i++, p=p->next) {
-		if (!self->dtv[i]) continue;
-		memcpy(self->dtv[i], p->image, p->len);
-		memset((char *)self->dtv[i]+p->len, 0,
-			p->size - p->len);
+		char *mem = (char *)(self->dtv[i] - DTP_OFFSET);
+		memcpy(mem, p->image, p->len);
+		memset(mem+p->len, 0, p->size - p->len);
 	}
 }
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index d491f975..7a25b88e 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -17,7 +17,8 @@ struct pthread {
 	/* Part 1 -- these fields may be external or
 	 * internal (accessed via asm) ABI. Do not change. */
 	struct pthread *self;
-	void **dtv, *unused1, *unused2;
+	uintptr_t *dtv;
+	void *unused1, *unused2;
 	uintptr_t sysinfo;
 	uintptr_t canary, canary2;
 
@@ -54,7 +55,7 @@ struct pthread {
 	/* Part 3 -- the positions of these fields relative to
 	 * the end of the structure is external and internal ABI. */
 	uintptr_t canary_at_end;
-	void **dtv_copy;
+	uintptr_t *dtv_copy;
 };
 
 struct start_sched_args {
diff --git a/src/thread/__tls_get_addr.c b/src/thread/__tls_get_addr.c
index 34fbc46c..d7afdabd 100644
--- a/src/thread/__tls_get_addr.c
+++ b/src/thread/__tls_get_addr.c
@@ -4,8 +4,8 @@
 void *__tls_get_addr(tls_mod_off_t *v)
 {
 	pthread_t self = __pthread_self();
-	if (v[0]<=(size_t)self->dtv[0])
-		return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET;
+	if (v[0] <= self->dtv[0])
+		return (void *)(self->dtv[v[0]] + v[1]);
 	return __tls_get_new(v);
 }