Date: Thu, 1 Apr 2004 01:16:41 -0800 (PST) From: Doug Rabson <dfr@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 50112 for review Message-ID: <200404010916.i319GfUB072254@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=50112 Change 50112 by dfr@dfr_home on 2004/04/01 01:16:06 Prototype TLS support in rtld (i386 only to start with). Affected files ... .. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#2 edit .. //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#2 edit .. //depot/projects/kse/libexec/rtld-elf/map_object.c#2 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.c#2 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.h#2 edit Differences ... ==== //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#2 (text+ko) ==== @@ -33,6 +33,8 @@ #include <sys/param.h> #include <sys/mman.h> +#include <machine/segments.h> +#include <machine/sysarch.h> #include <dlfcn.h> #include <err.h> @@ -47,6 +49,31 @@ #include "debug.h" #include "rtld.h" +#ifndef R_386_TLS_TPOFF + +#define R_386_TLS_TPOFF 14 +#define R_386_TLS_IE 15 +#define R_386_TLS_GOTIE 16 +#define R_386_TLS_LE 17 +#define R_386_TLS_GD 18 +#define R_386_TLS_LDM 19 +#define R_386_TLS_GD_32 24 +#define R_386_TLS_GD_PUSH 25 +#define R_386_TLS_GD_CALL 26 +#define R_386_TLS_GD_POP 27 +#define R_386_TLS_LDM_32 28 +#define R_386_TLS_LDM_PUSH 29 +#define R_386_TLS_LDM_CALL 30 +#define R_386_TLS_LDM_POP 31 +#define R_386_TLS_LDO_32 32 +#define R_386_TLS_IE_32 33 +#define R_386_TLS_LE_32 34 +#define R_386_TLS_DTPMOD32 35 +#define R_386_TLS_DTPOFF32 36 +#define R_386_TLS_TPOFF32 37 + +#endif + /* * Process the special R_386_COPY relocations in the main program. These * copy data from a shared object into a region in the main program's BSS @@ -202,6 +229,48 @@ *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; + + *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 +331,76 @@ obj->jmpslots_done = true; return 0; } + +void +allocate_initial_tls(Obj_Entry *list) +{ + Obj_Entry *obj; + size_t size; + char *tls; + Elf_Addr *dtv; + union descriptor ldt; + Elf_Addr segbase; + int sel; + + size = 0; + for (obj = list; obj; obj = obj->next) { + if (obj->tlsoffset > size) + size = obj->tlsoffset; + } + + tls = malloc(size + 2*sizeof(Elf_Addr)); + 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; + for (obj = list; obj; obj = obj->next) { + Elf_Addr 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] = addr; + } + + memset(&ldt, 0, sizeof(ldt)); + ldt.sd.sd_lolimit = 4; + ldt.sd.sd_lobase = segbase & 0xffffff; + ldt.sd.sd_type = SDT_MEMRWA; + ldt.sd.sd_dpl = SEL_UPL; + ldt.sd.sd_p = 1; /* present */ + ldt.sd.sd_hilimit = 0; + ldt.sd.sd_def32 = 1; /* 32 bit */ + ldt.sd.sd_gran = 0; /* limit in bytes */ + ldt.sd.sd_hibase = (segbase >> 24) & 0xff; + sel = i386_set_ldt(LDT_AUTO_ALLOC, &ldt, 1); + __asm __volatile("movl %0,%%gs" : : "rm" ((sel << 3) | 7)); +} + +/* GNU 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); +} + +/* 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); +} ==== //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#2 (text+ko) ==== @@ -58,4 +58,16 @@ #define call_initfini_pointer(obj, target) \ (((InitFunc)(target))()) +#define calculate_tls_offset(prev_offset, size, align) \ + (((prev_offset) + (size) + ((1 << (align)) - 1)) \ + & ~((1 << (align)) - 1)) + +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 ==== //depot/projects/kse/libexec/rtld-elf/map_object.c#2 (text+ko) ==== @@ -63,6 +63,7 @@ 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 @@ 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,10 @@ case PT_DYNAMIC: phdyn = phdr; break; + + case PT_TLS: + phtls = phdr; + break; } ++phdr; @@ -228,7 +233,16 @@ } 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->tlsinitsize = phtls->p_filesz; + obj->tlsinit = mapbase + phtls->p_vaddr; + obj->tlsoffset = calculate_tls_offset(tls_last_offset, + phtls->p_memsz, phtls->p_align); + tls_last_offset = obj->tlsoffset; + } return obj; } ==== //depot/projects/kse/libexec/rtld-elf/rtld.c#2 (text+ko) ==== @@ -178,6 +178,9 @@ (func_ptr_type) &dllockinit, (func_ptr_type) &dlinfo, (func_ptr_type) &_rtld_thread_init, +#ifdef __i386__ + (func_ptr_type) &___tls_get_addr, +#endif NULL }; @@ -189,6 +192,13 @@ char **environ; /* + * Globals to control TLS allocation. + */ +size_t tls_last_offset; /* TLS offset of last module */ +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 * alloca and we want that to occur within the scope of the caller. @@ -390,6 +400,12 @@ dbg("initializing thread locks"); lockdflt_init(); + /* setup TLS for main thread */ + dbg("initializing initial thread local storage (size %d)", + tls_last_offset); + allocate_initial_tls(obj_list); + dbg("foo"); + /* Make a list of init functions to call. */ objlist_init(&initlist); initlist_add_objects(obj_list, preload_tail, &initlist); @@ -726,6 +742,15 @@ case PT_DYNAMIC: obj->dynamic = (const Elf_Dyn *) ph->p_vaddr; break; + + case PT_TLS: + obj->tlsindex = 1; + obj->tlsoffset = calculate_tls_offset(0, ph->p_memsz, + ph->p_align); + tls_last_offset = obj->tlsoffset; + obj->tlsinitsize = ph->p_filesz; + obj->tlsinit = (void*) ph->p_vaddr; + break; } } if (nsegs < 1) { @@ -2433,4 +2458,58 @@ elm->obj->refcount--; } +/* + * 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; + 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); + *dtvp = newdtv; + } + + /* Dynamically allocate module TLS if necessary */ + if (!dtv[index + 1]) + dtv[index + 1] = (Elf_Addr)allocate_tls(index); + + return (void*) (dtv[index + 1] + offset); +} + +/* + * Allocate TLS block for module with given index. + */ +void * +allocate_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; +} ==== //depot/projects/kse/libexec/rtld-elf/rtld.h#2 (text+ko) ==== @@ -63,6 +63,10 @@ #define false 0 #define true 1 +extern size_t tls_last_offset; +extern int tls_dtv_generation; +extern int tls_max_index; + struct stat; struct Struct_Obj_Entry; @@ -137,6 +141,13 @@ 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 TLS block for this module */ + /* Items from the dynamic section. */ Elf_Addr *pltgot; /* PLT or GOT, depending on architecture */ const Elf_Rel *rel; /* Relocation entries */ @@ -216,6 +227,8 @@ 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(int index); /* * MD function declarations. @@ -224,5 +237,6 @@ int reloc_non_plt(Obj_Entry *, Obj_Entry *); int reloc_plt(Obj_Entry *); int reloc_jmpslots(Obj_Entry *); +void allocate_initial_tls(Obj_Entry *); #endif /* } */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200404010916.i319GfUB072254>
