PERFORCE change 50650 for review

Doug Rabson dfr at FreeBSD.org
Thu Apr 8 01:17:07 PDT 2004


http://perforce.freebsd.org/chv.cgi?CH=50650

Change 50650 by dfr at dfr_home on 2004/04/08 01:16:13

	Add TLS support for ia64. Still untested since my ia64 box has
	been switched off for about a year.

Affected files ...

.. //depot/projects/kse/lib/libpthread/arch/ia64/ia64/pthread_md.c#2 edit
.. //depot/projects/kse/lib/libpthread/arch/ia64/include/pthread_md.h#2 edit
.. //depot/projects/kse/lib/libthr/arch/ia64/ia64/_curthread.c#2 edit
.. //depot/projects/kse/libexec/rtld-elf/ia64/reloc.c#3 edit

Differences ...

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

@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <strings.h>
 #include "pthread_md.h"
+#include "rtld_tls.h"
 
 /*
  * The constructors.
@@ -36,12 +37,16 @@
 struct tcb *
 _tcb_ctor(struct pthread *thread)
 {
-	struct tcb *tcb;
+	struct ia64_tp *tp;
+
+	tp = _rtld_allocate_tls(sizeof(struct ia64_tp), 16);
+	if (tp == NULL)
+		return (NULL);
 
 	if ((tcb = malloc(sizeof(struct tcb))) != NULL) {
 		bzero(tcb, sizeof(struct tcb));
 		tcb->tcb_thread = thread;
-		/* Allocate TDV */
+		tcb->tcb_tp = tp;
 	}
 	return (tcb);
 }
@@ -49,7 +54,8 @@
 void
 _tcb_dtor(struct tcb *tcb)
 {
-	/* Free TDV */
+
+	_rtld_free_tls(tcb->tcb_tp, sizeof(struct ia64_tp), 16);
 	free(tcb);
 }
 

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

@@ -44,19 +44,13 @@
 struct kse;
 struct pthread;
 struct tcb;
-struct tdv;	/* We don't know what this is yet? */
 
 /*
- * tp points to one of these. We define the static TLS as an array
- * of long double to enforce 16-byte alignment of the TLS memory,
- * struct ia64_tp, struct tcb and also struct kcb. Both static and
- * dynamic allocation of any of these structures will result in a
- * valid, well-aligned thread pointer.
+ * tp points to one of these.
  */
 struct ia64_tp {
-	struct tdv		*tp_tdv;	/* dynamic TLS */
-	uint64_t		_reserved_;
-	long double		tp_tls[0];	/* static TLS */
+	void			*tp_dtv;	/* required by rtld */
+	struct tcb		*tp_tcb;	/* real tcb for thread */
 };
 
 struct tcb {
@@ -64,7 +58,7 @@
 	struct pthread		*tcb_thread;
 	struct kcb		*tcb_curkcb;
 	long			tcb_isfake;
-	struct ia64_tp		tcb_tp;
+	struct ia64_tp		*tcb_tp;
 };
 
 struct kcb {
@@ -76,7 +70,7 @@
 
 register struct ia64_tp *_tp __asm("%r13");
 
-#define	_tcb	((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp)))
+#define	_tcb	(_tp->tp_tcb)
 
 /*
  * The kcb and tcb constructors.
@@ -90,8 +84,6 @@
 static __inline void
 _kcb_set(struct kcb *kcb)
 {
-	/* There is no thread yet; use the fake tcb. */
-	_tp = &kcb->kcb_faketcb.tcb_tp;
 }
 
 /*
@@ -103,6 +95,7 @@
 static __inline struct kcb *
 _kcb_get(void)
 {
+
 	return (_tcb->tcb_curkcb);
 }
 
@@ -165,22 +158,25 @@
 static __inline void
 _tcb_set(struct kcb *kcb, struct tcb *tcb)
 {
+
 	if (tcb == NULL)
 		tcb = &kcb->kcb_faketcb;
 	kcb->kcb_curtcb = tcb;
 	tcb->tcb_curkcb = kcb;
-	_tp = &tcb->tcb_tp;
+	_tp = tcb->tcb_tp;
 }
 
 static __inline struct tcb *
 _tcb_get(void)
 {
+
 	return (_tcb);
 }
 
 static __inline struct pthread *
 _get_curthread(void)
 {
+
 	return (_tcb->tcb_thread);
 }
 
@@ -204,6 +200,7 @@
 static __inline int
 _thread_enter_uts(struct tcb *tcb, struct kcb *kcb)
 {
+
 	if (_ia64_save_context(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) {
 		/* Make the fake tcb the current thread. */
 		kcb->kcb_curtcb = &kcb->kcb_faketcb;

==== //depot/projects/kse/lib/libthr/arch/ia64/ia64/_curthread.c#2 (text+ko) ====

@@ -33,27 +33,38 @@
 #include <pthread.h>
 #include "thr_private.h"
 
-register struct pthread *_tp __asm("%r13");
+struct tcb {
+	void		*tcb_dtv;
+	struct pthread	*tcb_thread;
+};
+
+register struct tcb *_tp __asm("%r13");
 
 struct pthread *
 _get_curthread(void)
 {
 
-	return (_tp);
+	return (_tp->tcb_thread);
 }
 
 void
 _retire_thread(void *v)
 {
+
+	_rtld_free_tls(v, sizeof(struct tcb), 16);
 }
 
 void *
 _set_curthread(ucontext_t *uc, struct pthread *thread, int *err)
 {
+	struct tcb *tcb;
+
+	tcb = _rtld_allocate_tls(sizeof(struct tcb), 16);
+	tcb->tcb_thread = thread;
 	*err = 0;
 	if (uc != NULL)
-		uc->uc_mcontext.mc_special.tp = (uint64_t)thread;
+		uc->uc_mcontext.mc_special.tp = (uint64_t)tcb;
 	else
-		_tp = thread;
-	return (NULL);
+		_tp = tcb;
+	return (tcb);
 }

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

@@ -48,6 +48,28 @@
 #include "debug.h"
 #include "rtld.h"
 
+#ifndef R_IA64_TPREL14
+
+#define R_IA64_TPREL14			0x91
+#define R_IA64_TPREL22			0x92
+#define R_IA64_TPREL64I			0x93
+#define R_IA64_TPREL64MSB		0x96
+#define R_IA64_TPREL64LSB		0x97
+#define R_IA64_LTOFF_TPREL22		0x9a
+#define R_IA64_DTPMOD64MSB		0xa6
+#define R_IA64_DTPMOD64LSB		0xa7
+#define R_IA64_LTOFF_DTPMOD22		0xaa
+#define R_IA64_DTPREL14			0xb1
+#define R_IA64_DTPREL22			0xb2
+#define R_IA64_DTPREL64I		0xb3
+#define R_IA64_DTPREL32MSB		0xb4
+#define R_IA64_DTPREL32LSB		0xb5
+#define R_IA64_DTPREL64MSB		0xb6
+#define R_IA64_DTPREL64LSB		0xb7
+#define R_IA64_LTOFF_DTPREL22		0xba
+
+#endif
+
 extern Elf_Dyn _DYNAMIC;
 
 /*
@@ -259,6 +281,48 @@
 		break;
 	}
 
+	case R_IA64_DTPMOD64LSB: {
+		const Elf_Sym *def;
+		const Obj_Entry *defobj;
+		Elf_Addr target;
+
+		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+				  false, cache);
+		if (def == NULL)
+			return -1;
+
+		store64(where, defobj->tlsindex);
+		break;
+	}
+
+	case R_IA64_DTPREL64LSB: {
+		const Elf_Sym *def;
+		const Obj_Entry *defobj;
+		Elf_Addr target;
+
+		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+				  false, cache);
+		if (def == NULL)
+			return -1;
+
+		store64(where, def->st_value + rela->r_addend);
+		break;
+	}
+
+	case R_IA64_TPREL64LSB: {
+		const Elf_Sym *def;
+		const Obj_Entry *defobj;
+		Elf_Addr target;
+
+		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
+				  false, cache);
+		if (def == NULL)
+			return -1;
+
+		store64(where, defobj->tlsoffset + def->st_value + rela->r_addend);
+		break;
+	}
+
 	case R_IA64_NONE:
 		break;
 
@@ -537,9 +601,9 @@
 }
 
 void
-allocate_initial_tls(Obj_Entry *list)
+allocate_tls(Objlist *list, size_t tcbsize, size_t tcbalign)
 {
-    register struct Elf_Addr** tp __asm__("r13");
+    Objlist_Entry *entry;
     Obj_Entry *obj;
     size_t size;
     char *tls;
@@ -548,8 +612,12 @@
     Elf_Addr segbase;
     int sel;
 
+    assert(tcbsize == 16);
+    assert(tcbalign == 16);
+
     size = 0;
-    for (obj = list; obj; obj = obj->next) {
+    STAILQ_FOREACH(entry, list, link) {
+	obj = entry->obj;
         if (obj->tlsoffset + obj->tlssize > size)
             size = obj->tlsoffset + obj->tlssize;
     }
@@ -570,7 +638,49 @@
 	dtv[obj->tlsindex] = addr;
     }
 
-    tp = (Elf_Addr**) tls;
+    return tls;
+}
+
+void
+free_tls(Objlist *list, void *tls, size_t tcbsize, size_t tcbalign)
+{
+    Objlist_Entry *entry;
+    Obj_Entry *obj;
+    size_t size;
+    Elf_Addr* dtv;
+    int dtvsize, i;
+    Elf_Addr tlsstart, tlsend;
+
+    /*
+     * Figure out the size of the initial TLS block so that we can
+     * find stuff which __tls_get_addr() allocated dynamically.
+     */
+    size = 0;
+    STAILQ_FOREACH(entry, list, link) {
+	obj = entry->obj;
+        if (obj->tlsoffset + obj->tlssize > size)
+            size = obj->tlsoffset + obj->tlssize;
+    }
+
+    dtv = ((Elf_Addr**)tls)[0];
+    dtvsize = dtv[1];
+    tlsstart = (Elf_Addr) tls;
+    tlsend = tlsstart + size;
+    for (i = 0; i < dtvsize; i++) {
+	if (dtv[i+2] < tlsstart || dtv[i+2] > tlsend) {
+	    free((void*) dtv[i+2]);
+	}
+    }
+
+    free((void*) tlsstart);
+}
+
+void
+allocate_initial_tls(Obj_Entry *list)
+{
+    register struct Elf_Addr** tp __asm__("r13");
+
+    tp = allocate_tls(list, 16, 16);
 }
 
 void *__tls_get_addr(unsigned int module, unsigned int offset)


More information about the p4-projects mailing list