From: David Xu Date: Tue, 22 Mar 2005 22:56:36 +0000 (+0000) Subject: Add support for TLS. X-Git-Tag: v2.0.1~8062 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/55b88caed3c495a98cb20eec637bea0b2bb9e688 Add support for TLS. Obtained from : FreeBSD --- diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index c6b505729f..52d40cde1b 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/i386/reloc.c,v 1.6.2.2 2002/06/16 20:02:09 dillon Exp $ - * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.3 2005/02/04 00:24:23 joerg Exp $ + * $DragonFly: src/libexec/rtld-elf/i386/reloc.c,v 1.4 2005/03/22 22:56:36 davidxu Exp $ */ /* @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -203,6 +204,64 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) *where += (Elf_Addr) obj->relocbase; break; + case R_386_TLS_TPOFF: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false, cache); + if (def == NULL) + goto done; + + /* + * We lazily allocate offsets for static TLS as we + * see the first relocation that references the + * TLS block. This allows us to support (small + * amounts of) static TLS in dynamically loaded + * modules. If we run out of space, we generate an + * error. + */ + if (!defobj->tls_done) { + if (!allocate_tls_offset((Obj_Entry*) defobj)) { + _rtld_error("%s: No space available for static " + "Thread Local Storage", obj->path); + goto done; + } + } + + *where += (Elf_Addr) (def->st_value - defobj->tlsoffset); + } + break; + + case R_386_TLS_DTPMOD32: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false, cache); + if (def == NULL) + goto done; + + *where += (Elf_Addr) defobj->tlsindex; + } + break; + + case R_386_TLS_DTPOFF32: + { + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, + false, cache); + if (def == NULL) + goto done; + + *where += (Elf_Addr) def->st_value; + } + break; + default: _rtld_error("%s: Unsupported relocation type %d" " in non-PLT relocations\n", obj->path, @@ -262,3 +321,48 @@ reloc_jmpslots(Obj_Entry *obj) obj->jmpslots_done = true; return 0; } + +void +allocate_initial_tls(Obj_Entry *objs) +{ + struct tls_info ti; + void* tls; + int sel; + + /* + * Fix the size of the static TLS block by using the maximum + * offset allocated so far and adding a bit for dynamic modules to + * use. + */ + tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + tls = allocate_tls(objs, NULL, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + ti.base = tls; + ti.size = 2 * sizeof(Elf_Addr); + sel = sys_set_tls_area(0, &ti, sizeof(ti)); + __asm __volatile("movl %0,%%gs" : : "rm" (sel)); +} + +/* GNU ABI */ +__attribute__((__regparm__(1))) +void *___tls_get_addr(tls_index *ti) +{ + Elf_Addr** segbase; + Elf_Addr* dtv; + + __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); + dtv = segbase[1]; + + return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); +} + +/* Sun ABI */ +void *__tls_get_addr(tls_index *ti) +{ + Elf_Addr** segbase; + Elf_Addr* dtv; + + __asm __volatile("movl %%gs:0, %0" : "=r" (segbase)); + dtv = segbase[1]; + + return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); +} diff --git a/libexec/rtld-elf/i386/rtld_machdep.h b/libexec/rtld-elf/i386/rtld_machdep.h index 43e755b78d..18b1083b28 100644 --- a/libexec/rtld-elf/i386/rtld_machdep.h +++ b/libexec/rtld-elf/i386/rtld_machdep.h @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.3.2.2 2002/07/02 04:10:51 jdp Exp $ - * $DragonFly: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.5 2004/01/20 21:32:47 dillon Exp $ + * $DragonFly: src/libexec/rtld-elf/i386/rtld_machdep.h,v 1.6 2005/03/22 22:56:36 davidxu Exp $ */ #ifndef RTLD_MACHDEP_H @@ -63,4 +63,20 @@ atomic_add_int(volatile int *p, int val) : "cc"); } +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) +#define calculate_first_tls_offset(size, align) \ + round(size, align) +#define calculate_tls_offset(prev_offset, prev_size, size, align) \ + round((prev_offset) + (size), align) +#define calculate_tls_end(off, size) (off) + +typedef struct { + unsigned long ti_module; + unsigned long ti_offset; +} tls_index; + +extern void *___tls_get_addr(tls_index *ti) __attribute__((__regparm__(1))); +extern void *__tls_get_addr(tls_index *ti); + #endif diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 6726869d45..6a9513e3ff 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/map_object.c,v 1.7.2.2 2002/12/28 19:49:41 dillon Exp $ - * $DragonFly: src/libexec/rtld-elf/map_object.c,v 1.5 2005/02/05 22:54:49 joerg Exp $ + * $DragonFly: src/libexec/rtld-elf/map_object.c,v 1.6 2005/03/22 22:56:36 davidxu Exp $ */ #include @@ -63,6 +63,7 @@ map_object(int fd, const char *path, const struct stat *sb) Elf_Phdr *phdyn; Elf_Phdr *phphdr; Elf_Phdr *phinterp; + Elf_Phdr *phtls; caddr_t mapbase; size_t mapsize; Elf_Off base_offset; @@ -96,7 +97,7 @@ map_object(int fd, const char *path, const struct stat *sb) phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff); phlimit = phdr + hdr->e_phnum; nsegs = -1; - phdyn = phphdr = phinterp = NULL; + phdyn = phphdr = phinterp = phtls = NULL; segs = alloca(sizeof(segs[0]) * hdr->e_phnum); while (phdr < phlimit) { switch (phdr->p_type) { @@ -121,6 +122,9 @@ map_object(int fd, const char *path, const struct stat *sb) case PT_DYNAMIC: phdyn = phdr; break; + case PT_TLS: + phtls = phdr; + break; } ++phdr; @@ -234,7 +238,14 @@ map_object(int fd, const char *path, const struct stat *sb) } if (phinterp != NULL) obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr); - + if (phtls != NULL) { + tls_dtv_generation++; + obj->tlsindex = ++tls_max_index; + obj->tlssize = phtls->p_memsz; + obj->tlsalign = phtls->p_align; + obj->tlsinitsize = phtls->p_filesz; + obj->tlsinit = mapbase + phtls->p_vaddr; + } return obj; } @@ -299,6 +310,9 @@ obj_free(Obj_Entry *obj) { Objlist_Entry *elm; + if (obj->tls_done) { + free_tls_offset(obj); + } free(obj->origin_path); free(obj->path); while (obj->needed != NULL) { diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 9553a687df..d2916f90c5 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.43.2.15 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.16 2005/02/24 16:05:22 joerg Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.17 2005/03/22 22:56:36 davidxu Exp $ */ /* @@ -54,6 +54,7 @@ #include "debug.h" #include "rtld.h" +#include "rtld_tls.h" #define PATH_RTLD "/usr/libexec/ld-elf.so.1" #define LD_ARY_CACHE 16 @@ -182,6 +183,12 @@ static func_ptr_type exports[] = { (func_ptr_type) &dladdr, (func_ptr_type) &dllockinit, (func_ptr_type) &dlinfo, +#ifdef __i386__ + (func_ptr_type) &___tls_get_addr, +#endif + (func_ptr_type) &__tls_get_addr, + (func_ptr_type) &_rtld_allocate_tls, + (func_ptr_type) &_rtld_free_tls, NULL }; @@ -192,6 +199,15 @@ static func_ptr_type exports[] = { char *__progname; char **environ; +/* + * Globals to control TLS allocation. + */ +size_t tls_last_offset; /* Static TLS offset of last module */ +size_t tls_last_size; /* Static TLS size of last module */ +size_t tls_static_space; /* Static TLS space allocated */ +int tls_dtv_generation = 1; /* Used to detect when dtv size changes */ +int tls_max_index = 1; /* Largest module index allocated */ + /* * Fill in a DoneList with an allocation large enough to hold all of * the currently-loaded objects. Keep this as a macro since it calls @@ -260,6 +276,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) Elf_Auxinfo *aux; Elf_Auxinfo *auxp; const char *argv0; + Objlist_Entry *entry; Obj_Entry *obj; Objlist initlist; @@ -420,6 +437,17 @@ resident_skip1: exit (0); } + /* setup TLS for main thread */ + dbg("initializing initial thread local storage"); + STAILQ_FOREACH(entry, &list_main, link) { + /* + * Allocate all the initial objects out of the static TLS + * block even if they didn't ask for it. + */ + allocate_tls_offset(entry->obj); + } + allocate_initial_tls(obj_list); + if (relocate_objects(obj_main, ld_bind_now != NULL && *ld_bind_now != '\0') == -1) die(); @@ -788,6 +816,14 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path) case PT_DYNAMIC: obj->dynamic = (const Elf_Dyn *) ph->p_vaddr; break; + + case PT_TLS: + obj->tlsindex = 1; + obj->tlssize = ph->p_memsz; + obj->tlsalign = ph->p_align; + obj->tlsinitsize = ph->p_filesz; + obj->tlsinit = (void*) ph->p_vaddr; + break; } } if (nsegs < 1) { @@ -2525,3 +2561,351 @@ unref_dag(Obj_Entry *root) if (needed->obj != NULL) unref_dag(needed->obj); } + +/* + * Common code for MD __tls_get_addr(). + */ +void * +tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) +{ + Elf_Addr* dtv = *dtvp; + + /* Check dtv generation in case new modules have arrived */ + if (dtv[0] != tls_dtv_generation) { + Elf_Addr* newdtv; + int to_copy; + + wlock_acquire(); + + newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); + to_copy = dtv[1]; + if (to_copy > tls_max_index) + to_copy = tls_max_index; + memcpy(&newdtv[2], &dtv[2], to_copy * sizeof(Elf_Addr)); + newdtv[0] = tls_dtv_generation; + newdtv[1] = tls_max_index; + free(dtv); + + wlock_release(); + + *dtvp = newdtv; + } + + /* Dynamically allocate module TLS if necessary */ + if (!dtv[index + 1]) { + /* XXX + * here we should avoid to be re-entered by signal handler + * code, I assume wlock_acquire will masked all signals, + * otherwise there is race and dead lock thread itself. + */ + wlock_acquire(); + if (!dtv[index + 1]) + dtv[index + 1] = (Elf_Addr)allocate_module_tls(index); + wlock_release(); + } + + return (void*) (dtv[index + 1] + offset); +} + +/* XXX not sure what variants to use for arm. */ + +#if defined(__ia64__) || defined(__powerpc__) + +/* + * Allocate Static TLS using the Variant I method. + */ +void * +allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +{ + Obj_Entry *obj; + size_t size; + char *tls; + Elf_Addr *dtv, *olddtv; + Elf_Addr addr; + int i; + + size = tls_static_space; + + tls = malloc(size); + dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr)); + + *(Elf_Addr**) tls = dtv; + + dtv[0] = tls_dtv_generation; + dtv[1] = tls_max_index; + + if (oldtls) { + /* + * Copy the static TLS block over whole. + */ + memcpy(tls + tcbsize, oldtls + tcbsize, tls_static_space - tcbsize); + + /* + * If any dynamic TLS blocks have been created tls_get_addr(), + * move them over. + */ + olddtv = *(Elf_Addr**) oldtls; + for (i = 0; i < olddtv[1]; i++) { + if (olddtv[i+2] < (Elf_Addr)oldtls || + olddtv[i+2] > (Elf_Addr)oldtls + tls_static_space) { + dtv[i+2] = olddtv[i+2]; + olddtv[i+2] = 0; + } + } + + /* + * We assume that all tls blocks are allocated with the same + * size and alignment. + */ + free_tls(oldtls, tcbsize, tcbalign); + } else { + for (obj = objs; obj; obj = obj->next) { + if (obj->tlsoffset) { + addr = (Elf_Addr)tls + 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; + } + } + } + + return tls; +} + +void +free_tls(void *tls, size_t tcbsize, size_t tcbalign) +{ + 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 = tls_static_space; + + 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); +} + +#endif + +#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ + defined(__arm__) + +/* + * Allocate Static TLS using the Variant II method. + */ +void * +allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) +{ + Obj_Entry *obj; + size_t size; + char *tls; + Elf_Addr *dtv, *olddtv; + Elf_Addr segbase, oldsegbase, addr; + int i; + + size = round(tls_static_space, tcbalign); + + assert(tcbsize >= 2*sizeof(Elf_Addr)); + tls = malloc(size + tcbsize); + dtv = malloc((tls_max_index + 2) * sizeof(Elf_Addr)); + + segbase = (Elf_Addr)(tls + size); + ((Elf_Addr*)segbase)[0] = segbase; + ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; + + dtv[0] = tls_dtv_generation; + dtv[1] = tls_max_index; + + 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 with + * allocate_initial_tls(). + */ + free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + } 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; + } + } + } + + return (void*) segbase; +} + +void +free_tls(void *tls, size_t tcbsize, size_t tcbalign) +{ + 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 = round(tls_static_space, tcbalign); + + dtv = ((Elf_Addr**)tls)[1]; + dtvsize = dtv[1]; + tlsend = (Elf_Addr) tls; + tlsstart = tlsend - size; + for (i = 0; i < dtvsize; i++) { + if (dtv[i+2] < tlsstart || dtv[i+2] > tlsend) { + free((void*) dtv[i+2]); + } + } + + free((void*) tlsstart); +} + +#endif + +/* + * Allocate TLS block for module with given index. + */ +void * +allocate_module_tls(int index) +{ + Obj_Entry* obj; + char* p; + + for (obj = obj_list; obj; obj = obj->next) { + if (obj->tlsindex == index) + break; + } + if (!obj) { + _rtld_error("Can't find module with TLS index %d", index); + die(); + } + + p = malloc(obj->tlssize); + memcpy(p, obj->tlsinit, obj->tlsinitsize); + memset(p + obj->tlsinitsize, 0, obj->tlssize - obj->tlsinitsize); + + return p; +} + +bool +allocate_tls_offset(Obj_Entry *obj) +{ + 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 + off = calculate_tls_offset(tls_last_offset, tls_last_size, + obj->tlssize, obj->tlsalign); + + /* + * If we have already fixed the size of the static TLS block, we + * must stay within that size. When allocating the static TLS, we + * leave a small amount of space spare to be used for dynamically + * loading modules which use static TLS. + */ + if (tls_static_space) { + if (calculate_tls_end(off, obj->tlssize) > tls_static_space) + return false; + } + + tls_last_offset = obj->tlsoffset = off; + tls_last_size = obj->tlssize; + obj->tls_done = true; + + return true; +} + +void +free_tls_offset(Obj_Entry *obj) +{ +#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ + defined(__arm__) + /* + * If we were the last thing to allocate out of the static TLS + * block, we give our space back to the 'allocator'. This is a + * simplistic workaround to allow libGL.so.1 to be loaded and + * unloaded multiple times. We only handle the Variant II + * mechanism for now - this really needs a proper allocator. + */ + if (calculate_tls_end(obj->tlsoffset, obj->tlssize) + == calculate_tls_end(tls_last_offset, tls_last_size)) { + tls_last_offset -= obj->tlssize; + tls_last_size = 0; + } +#endif +} + +void * +_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +{ + void *ret; + + wlock_acquire(); + ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); + wlock_release(); + + return (ret); +} + +void +_rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) +{ + wlock_acquire(); + free_tls(tcb, tcbsize, tcbalign); + wlock_release(); +} diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 65cbd095ba..78842748d8 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.h,v 1.15.2.6 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.h,v 1.6 2005/02/05 22:54:49 joerg Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.h,v 1.7 2005/03/22 22:56:36 davidxu Exp $ */ #ifndef RTLD_H /* { */ @@ -51,6 +51,12 @@ typedef unsigned char bool; #define false 0 #define true 1 +extern size_t tls_last_offset; +extern size_t tls_last_size; +extern size_t tls_static_space; +extern int tls_dtv_generation; +extern int tls_max_index; + struct stat; struct Struct_Obj_Entry; @@ -125,6 +131,14 @@ typedef struct Struct_Obj_Entry { size_t phsize; /* Size of program header in bytes */ const char *interp; /* Pathname of the interpreter, if any */ + /* TLS information */ + int tlsindex; /* Index in DTV for this module */ + void *tlsinit; /* Base address of TLS init block */ + size_t tlsinitsize; /* Size of TLS init block for this module */ + size_t tlssize; /* Size of TLS block for this module */ + size_t tlsoffset; /* Offset of static TLS block for this module */ + size_t tlsalign; /* Alignment of static TLS block */ + /* Items from the dynamic section. */ Elf_Addr *pltgot; /* PLT or GOT, depending on architecture */ const Elf_Rel *rel; /* Relocation entries */ @@ -158,6 +172,7 @@ typedef struct Struct_Obj_Entry { bool traced; /* Already printed in ldd trace output */ bool jmpslots_done; /* Already have relocated the jump slots */ bool init_done; /* Already have added object to init list */ + bool tls_done; /* Already allocated offset for static TLS */ struct link_map linkmap; /* for GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ @@ -169,6 +184,8 @@ typedef struct Struct_Obj_Entry { #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 +#define RTLD_STATIC_TLS_EXTRA 64 + /* * Symbol cache entry used during relocation to avoid multiple lookups * of the same symbol. @@ -210,4 +227,11 @@ void _rtld_bind_start(void); const Elf_Sym *symlook_obj(const char *, unsigned long, const Obj_Entry *, bool); +void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); +void *allocate_tls(Obj_Entry *, void *, size_t, size_t); +void free_tls(void *, size_t, size_t); +void *allocate_module_tls(int index); +bool allocate_tls_offset(Obj_Entry *obj); +void free_tls_offset(Obj_Entry *obj); +void allocate_initial_tls(Obj_Entry *); #endif /* } */ diff --git a/libexec/rtld-elf/rtld_tls.h b/libexec/rtld-elf/rtld_tls.h new file mode 100644 index 0000000000..438d4fe7f7 --- /dev/null +++ b/libexec/rtld-elf/rtld_tls.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2004 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/libexec/rtld-elf/rtld_tls.h,v 1.1 2004/08/03 08:50:58 dfr Exp $ + * $DragonFly: src/libexec/rtld-elf/Attic/rtld_tls.h,v 1.1 2005/03/22 22:56:36 davidxu Exp $ + */ + +/* + * Semi-public interface from thread libraries to rtld for managing + * TLS. + */ + +#ifndef _RTLD_TLS_H_ +#define _RTLD_TLS_H_ + +/* + * Allocate a TLS block for a new thread. The memory allocated will + * include 'tcbsize' bytes aligned to a 'tcbalign' boundary (in bytes) + * for the thread library's private purposes. The location of the TCB + * block is returned by this function. For architectures using + * '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 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(void* oldtls, size_t tcbsize, size_t tcbalign); + +/* + * Free a TLS block allocated using _rtld_allocate_tls(). The tcbsize + * and tcbalign parameters must be the same as those used to allocate + * the block. + */ +extern void _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign); + +#endif