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