Date: Thu, 8 Apr 2004 01:17:06 -0700 (PDT) From: Doug Rabson <dfr@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 50650 for review Message-ID: <200404080817.i388H65H098920@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=50650 Change 50650 by dfr@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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200404080817.i388H65H098920>