Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 25 Jul 2004 10:50:50 GMT
From:      Doug Rabson <dfr@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 58124 for review
Message-ID:  <200407251050.i6PAooJ0033902@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=58124

Change 58124 by dfr@dfr_home on 2004/07/25 10:49:58

	Add code to migrate values from the bootstrap TLS segment created
	by rtld to the main thread's TLS segment when the thread library
	initialises. While we are here, make sure we properly initialise
	the static TLS blocks for all modules, not just those in the
	initial exec group. Also fix a bug which mis-sized the static TLS
	block when there were non-TLS-using modules present in the initial
	exec group.

Affected files ...

.. //depot/projects/kse/lib/libpthread/arch/alpha/alpha/pthread_md.c#2 edit
.. //depot/projects/kse/lib/libpthread/arch/alpha/include/pthread_md.h#3 edit
.. //depot/projects/kse/lib/libpthread/arch/amd64/amd64/pthread_md.c#3 edit
.. //depot/projects/kse/lib/libpthread/arch/amd64/include/pthread_md.h#4 edit
.. //depot/projects/kse/lib/libpthread/arch/arm/arm/pthread_md.c#2 edit
.. //depot/projects/kse/lib/libpthread/arch/arm/include/pthread_md.h#3 edit
.. //depot/projects/kse/lib/libpthread/arch/i386/i386/pthread_md.c#3 edit
.. //depot/projects/kse/lib/libpthread/arch/i386/include/pthread_md.h#4 edit
.. //depot/projects/kse/lib/libpthread/arch/ia64/ia64/pthread_md.c#3 edit
.. //depot/projects/kse/lib/libpthread/arch/ia64/include/pthread_md.h#4 edit
.. //depot/projects/kse/lib/libpthread/arch/powerpc/include/pthread_md.h#2 edit
.. //depot/projects/kse/lib/libpthread/arch/powerpc/powerpc/pthread_md.c#2 edit
.. //depot/projects/kse/lib/libpthread/arch/sparc64/include/pthread_md.h#3 edit
.. //depot/projects/kse/lib/libpthread/arch/sparc64/sparc64/pthread_md.c#2 edit
.. //depot/projects/kse/lib/libpthread/thread/thr_kern.c#4 edit
.. //depot/projects/kse/lib/libthr/arch/i386/i386/_setcurthread.c#3 edit
.. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#8 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.c#12 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld.h#7 edit
.. //depot/projects/kse/libexec/rtld-elf/rtld_tls.h#2 edit

Differences ...

==== //depot/projects/kse/lib/libpthread/arch/alpha/alpha/pthread_md.c#2 (text+ko) ====

@@ -35,7 +35,7 @@
  * The constructors.
  */
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
 

==== //depot/projects/kse/lib/libpthread/arch/alpha/include/pthread_md.h#3 (text+ko) ====

@@ -80,7 +80,7 @@
 /*
  * The kcb and tcb constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *);
 struct kcb	*_kcb_ctor(struct kse *kse);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/amd64/amd64/pthread_md.c#3 (text+ko) ====

@@ -35,11 +35,18 @@
  * The constructors.
  */
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
+	void *oldtls;
 
-	tcb = _rtld_allocate_tls(sizeof(struct tcb), 16);
+	if (initial) {
+		__asm __volatile("movq %%fs:0, %0" : "=r" (oldtls));
+	} else {
+		oldtls = NULL;
+	}
+
+	tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
 	if (tcb) {
 		tcb->tcb_thread = thread;
 		bzero(&tcb->tcb_tmbx, sizeof(tcb->tcb_tmbx));

==== //depot/projects/kse/lib/libpthread/arch/amd64/include/pthread_md.h#4 (text+ko) ====

@@ -140,7 +140,7 @@
 /*
  * The constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *tcb);
 struct kcb	*_kcb_ctor(struct kse *);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/arm/arm/pthread_md.c#2 (text+ko) ====

@@ -40,7 +40,7 @@
 #include "pthread_md.h"
 
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
 	void *addr;

==== //depot/projects/kse/lib/libpthread/arch/arm/include/pthread_md.h#3 (text+ko) ====

@@ -91,7 +91,7 @@
 /*
  * The kcb and tcb constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *);
 struct kcb	*_kcb_ctor(struct kse *kse);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/i386/i386/pthread_md.c#3 (text+ko) ====

@@ -43,11 +43,18 @@
 #include "pthread_md.h"
 
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
+	void *oldtls;
 
-	tcb = _rtld_allocate_tls(sizeof(struct tcb), 16);
+	if (initial) {
+		__asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+	} else {
+		oldtls = NULL;
+	}
+
+	tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
 	if (tcb) {
 		tcb->tcb_thread = thread;
 		tcb->tcb_spare = 0;

==== //depot/projects/kse/lib/libpthread/arch/i386/include/pthread_md.h#4 (text+ko) ====

@@ -139,7 +139,7 @@
 /*
  * The constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *tcb);
 struct kcb	*_kcb_ctor(struct kse *);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/ia64/ia64/pthread_md.c#3 (text+ko) ====

@@ -35,11 +35,12 @@
  * The constructors.
  */
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct ia64_tp *tp;
 
-	tp = _rtld_allocate_tls(sizeof(struct ia64_tp), 16);
+	tp = _rtld_allocate_tls(initial ? _tp : NULL,
+	    sizeof(struct ia64_tp), 16);
 	if (tp == NULL)
 		return (NULL);
 

==== //depot/projects/kse/lib/libpthread/arch/ia64/include/pthread_md.h#4 (text+ko) ====

@@ -75,7 +75,7 @@
 /*
  * The kcb and tcb constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *);
 struct kcb	*_kcb_ctor(struct kse *kse);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/powerpc/include/pthread_md.h#2 (text+ko) ====

@@ -92,7 +92,7 @@
 /*
  * The kcb and tcb constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *);
 struct kcb	*_kcb_ctor(struct kse *kse);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/powerpc/powerpc/pthread_md.c#2 (text+ko) ====

@@ -35,7 +35,7 @@
  * The constructors.
  */
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
 

==== //depot/projects/kse/lib/libpthread/arch/sparc64/include/pthread_md.h#3 (text+ko) ====

@@ -91,7 +91,7 @@
 /*
  * The kcb and tcb constructors.
  */
-struct tcb	*_tcb_ctor(struct pthread *);
+struct tcb	*_tcb_ctor(struct pthread *, int);
 void		_tcb_dtor(struct tcb *);
 struct kcb	*_kcb_ctor(struct kse *kse);
 void		_kcb_dtor(struct kcb *);

==== //depot/projects/kse/lib/libpthread/arch/sparc64/sparc64/pthread_md.c#2 (text+ko) ====

@@ -40,7 +40,7 @@
 #include "pthread_md.h"
 
 struct tcb *
-_tcb_ctor(struct pthread *thread)
+_tcb_ctor(struct pthread *thread, int initial)
 {
 	struct tcb *tcb;
 	void *addr;

==== //depot/projects/kse/lib/libpthread/thread/thr_kern.c#4 (text+ko) ====

@@ -2384,7 +2384,7 @@
 	if ((thread == NULL) &&
 	    ((thread = malloc(sizeof(struct pthread))) != NULL)) {
 		bzero(thread, sizeof(struct pthread));
-		if ((thread->tcb = _tcb_ctor(thread)) == NULL) {
+		if ((thread->tcb = _tcb_ctor(thread, curthread == NULL)) == NULL) {
 			free(thread);
 			thread = NULL;
 		} else {

==== //depot/projects/kse/lib/libthr/arch/i386/i386/_setcurthread.c#3 (text+ko) ====

@@ -61,15 +61,22 @@
 {
 	union descriptor desc;
 	struct tcb *tcb;
+	void *oldtls;
 	int ldt_index;
 
 	*err = 0;
 
+	if (uc == NULL) {
+		__asm __volatile("movl %%gs:0, %0" : "=r" (oldtls));
+	} else {
+		oldtls = NULL;
+	}
+
 	/*
 	 * Allocate and initialise a new TLS block with enough extra
 	 * space for our self pointer.
 	 */
-	tcb = _rtld_allocate_tls(sizeof(struct tcb), 16);
+	tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16);
 
 	/*
 	 * Cache the address of the thread structure here, after

==== //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#8 (text+ko) ====

@@ -349,14 +349,14 @@
 }
 
 void *
-allocate_tls(Objlist* list, size_t tcbsize, size_t tcbalign)
+allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign)
 {
-    Objlist_Entry *entry;
     Obj_Entry *obj;
     size_t size;
     char *tls;
-    Elf_Addr *dtv;
-    Elf_Addr segbase, addr;
+    Elf_Addr *dtv, *olddtv;
+    Elf_Addr segbase, oldsegbase, addr;
+    int i;
 
     size = round(tls_static_space, tcbalign);
 
@@ -370,17 +370,45 @@
 
     dtv[0] = tls_dtv_generation;
     dtv[1] = tls_max_index;
-    STAILQ_FOREACH(entry, list, link) {
-	obj = entry->obj;
-	if (obj->tlsoffset) {
-	    addr = segbase - obj->tlsoffset;
-	    memset((void*) (addr + obj->tlsinitsize),
-		   0, obj->tlssize - obj->tlsinitsize);
-	    if (obj->tlsinit)
-		memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize);
-	    dtv[obj->tlsindex + 1] = addr;
-	} else if (obj->tlsindex) {
-	    dtv[obj->tlsindex + 1] = 0;
+
+    if (oldtls) {
+	/*
+	 * Copy the static TLS block over whole.
+	 */
+	oldsegbase = (Elf_Addr) oldtls;
+	memcpy((void *)(segbase - tls_static_space),
+	       (const void *)(oldsegbase - tls_static_space),
+	       tls_static_space);
+
+	/*
+	 * If any dynamic TLS blocks have been created tls_get_addr(),
+	 * move them over.
+	 */
+	olddtv = ((Elf_Addr**)oldsegbase)[1];
+	for (i = 0; i < olddtv[1]; i++) {
+	    if (olddtv[i+2] < oldsegbase - size || olddtv[i+2] > oldsegbase) {
+		dtv[i+2] = olddtv[i+2];
+		olddtv[i+2] = 0;
+	    }
+	}
+
+	/*
+	 * We assume that this block was the one we created below with
+	 * allocate_initial_tls().
+	 */
+	free_tls(oldtls, 2*sizeof(Elf_Addr), 4);
+    } else {
+	for (obj = objs; obj; obj = obj->next) {
+	    if (obj->tlsoffset) {
+		addr = segbase - obj->tlsoffset;
+		memset((void*) (addr + obj->tlsinitsize),
+		       0, obj->tlssize - obj->tlsinitsize);
+		if (obj->tlsinit)
+		    memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize);
+		dtv[obj->tlsindex + 1] = addr;
+	    } else if (obj->tlsindex) {
+		dtv[obj->tlsindex + 1] = 0;
+	    }
 	}
     }
 
@@ -388,7 +416,7 @@
 }
 
 void
-free_tls(Objlist *list, void *tls, size_t tcbsize, size_t tcbalign)
+free_tls(void *tls, size_t tcbsize, size_t tcbalign)
 {
     size_t size;
     Elf_Addr* dtv;
@@ -415,7 +443,7 @@
 }
 
 void
-allocate_initial_tls(Objlist *list)
+allocate_initial_tls(Obj_Entry *objs)
 {
     void* tls;
     union descriptor ldt;
@@ -427,7 +455,7 @@
      * use.
      */
     tls_static_space = tls_last_offset + 64;
-    tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4);
+    tls = allocate_tls(objs, NULL, 2*sizeof(Elf_Addr), 4);
 
     memset(&ldt, 0, sizeof(ldt));
     ldt.sd.sd_lolimit = 0xffff;	/* 4G limit */

==== //depot/projects/kse/libexec/rtld-elf/rtld.c#12 (text+ko) ====

@@ -419,7 +419,7 @@
 	 */
 	allocate_tls_offset(entry->obj);
     }
-    allocate_initial_tls(&list_main);
+    allocate_initial_tls(obj_list);
 
     /* Make a list of init functions to call. */
     objlist_init(&initlist);
@@ -2538,6 +2538,14 @@
 {
     size_t off;
 
+    if (obj->tls_done)
+	return true;
+
+    if (obj->tlssize == 0) {
+	obj->tls_done = true;
+	return true;
+    }
+
     if (obj->tlsindex == 1)
 	off = calculate_first_tls_offset(obj->tlssize, obj->tlsalign);
     else
@@ -2563,13 +2571,13 @@
 }
 
 void *
-_rtld_allocate_tls(size_t tcbsize, size_t tcbalign)
+_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
 {
-    return allocate_tls(&list_main, tcbsize, tcbalign);
+    return allocate_tls(obj_list, oldtls, tcbsize, tcbalign);
 }
 
 void
 _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign)
 {
-    free_tls(&list_main, tcb, tcbsize, tcbalign);
+    free_tls(tcb, tcbsize, tcbalign);
 }

==== //depot/projects/kse/libexec/rtld-elf/rtld.h#7 (text+ko) ====

@@ -242,8 +242,8 @@
 int reloc_non_plt(Obj_Entry *, Obj_Entry *);
 int reloc_plt(Obj_Entry *);
 int reloc_jmpslots(Obj_Entry *);
-void *allocate_tls(Objlist *, size_t, size_t);
-void free_tls(Objlist *, void *, size_t, size_t);
-void allocate_initial_tls(Objlist *);
+void *allocate_tls(Obj_Entry *, void *, size_t, size_t);
+void free_tls(void *, size_t, size_t);
+void allocate_initial_tls(Obj_Entry *);
 
 #endif /* } */

==== //depot/projects/kse/libexec/rtld-elf/rtld_tls.h#2 (text+ko) ====

@@ -42,14 +42,22 @@
  * 'Variant I' TLS, the thread local storage follows the TCB, and for
  * 'Variant II', the thread local storage precedes it. For
  * architectures using the 'Variant II' model (e.g. i386, amd64,
- * sparc64), the TCB begin with two pointer fields which are used by
- * rtld for its TLS implementation. For the 'Variant I' model, the TCB
- * must begin with a single pointer field for rtld's implementation.
+ * sparc64), the TCB must begin with two pointer fields which are used
+ * by rtld for its TLS implementation. For the 'Variant I' model, the
+ * TCB must begin with a single pointer field for rtld's
+ * implementation.
+ *
+ * If the value of 'oldtls' is non-NULL, the new TLS block will be
+ * initialised using the values contained in 'oldtls' and 'oldtls'
+ * will be freed. This is typically used when initialising a thread
+ * library to migrate from using the initial bootstrap TLS block
+ * created by rtld to one which contains suitable thread library
+ * private data.
  *
  * The value returned from this function is suitable for installing
  * directly into the thread pointer register.
  */
-extern void *_rtld_allocate_tls(size_t tcbsize, size_t tcbalign);
+extern void *_rtld_allocate_tls(void* oldtls, size_t tcbsize, size_t tcbalign);
 
 /*
  * Free a TLS block allocated using _rtld_allocate_tls(). The tcbsize



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200407251050.i6PAooJ0033902>