Date: Thu, 22 Jul 2004 12:18:02 GMT From: Doug Rabson <dfr@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 57918 for review Message-ID: <200407221218.i6MCI2wP099972@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=57918 Change 57918 by dfr@dfr_home on 2004/07/22 12:17:16 Add support for small amounts of static TLS use by dynamic modules. Required for NVidia libGL. Affected files ... .. //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#6 edit .. //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#6 edit .. //depot/projects/kse/libexec/rtld-elf/ia64/rtld_machdep.h#3 edit .. //depot/projects/kse/libexec/rtld-elf/map_object.c#4 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.c#9 edit .. //depot/projects/kse/libexec/rtld-elf/rtld.h#5 edit Differences ... ==== //depot/projects/kse/libexec/rtld-elf/i386/reloc.c#6 (text+ko) ==== @@ -239,6 +239,22 @@ 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; @@ -332,6 +348,35 @@ return 0; } +bool +allocate_tls_offset(Obj_Entry *obj) +{ + size_t off; + + 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 * allocate_tls(Objlist* list, size_t tcbsize, size_t tcbalign) { @@ -340,15 +385,9 @@ size_t size; char *tls; Elf_Addr *dtv; - Elf_Addr segbase; + Elf_Addr segbase, addr; - size = 0; - STAILQ_FOREACH(entry, list, link) { - obj = entry->obj; - if (obj->tlsoffset > size) - size = obj->tlsoffset; - } - size = round(size, tcbalign); + size = round(tls_static_space, tcbalign); assert(tcbsize >= 2*sizeof(Elf_Addr)); tls = malloc(size + tcbsize); @@ -362,12 +401,16 @@ dtv[1] = tls_max_index; STAILQ_FOREACH(entry, list, link) { obj = entry->obj; - 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; + 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; @@ -376,8 +419,6 @@ 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; @@ -387,13 +428,7 @@ * 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 > size) - size = obj->tlsoffset; - } - size = round(size, tcbalign); + size = round(tls_static_space, tcbalign); dtv = ((Elf_Addr**)tls)[1]; dtvsize = dtv[1]; @@ -411,10 +446,18 @@ void allocate_initial_tls(Objlist *list) { - void* tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4); + void* tls; union descriptor ldt; 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 + 64; + tls = allocate_tls(list, 2*sizeof(Elf_Addr), 4); + memset(&ldt, 0, sizeof(ldt)); ldt.sd.sd_lolimit = 0xffff; /* 4G limit */ ldt.sd.sd_lobase = ((Elf_Addr)tls) & 0xffffff; ==== //depot/projects/kse/libexec/rtld-elf/i386/rtld_machdep.h#6 (text+ko) ==== @@ -64,6 +64,7 @@ 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; ==== //depot/projects/kse/libexec/rtld-elf/ia64/rtld_machdep.h#3 (text+ko) ==== @@ -61,6 +61,7 @@ round(16, align) #define calculate_tls_offset(prev_offset, prev_size, size, align) \ round(prev_offset + prev_size, align) +#define calculate_tls_end(off, size) ((off) + (size)) extern void *__tls_get_addr(unsigned long module, unsigned long offset); ==== //depot/projects/kse/libexec/rtld-elf/map_object.c#4 (text+ko) ==== @@ -237,18 +237,9 @@ 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; - if (obj->tlsindex == 1) - obj->tlsoffset = calculate_first_tls_offset(phtls->p_memsz, - phtls->p_align); - else - obj->tlsoffset = calculate_tls_offset(tls_last_offset, - tls_last_size, - phtls->p_memsz, - phtls->p_align); - tls_last_offset = obj->tlsoffset; - tls_last_size = obj->tlssize; } return obj; } ==== //depot/projects/kse/libexec/rtld-elf/rtld.c#9 (text+ko) ==== @@ -201,8 +201,9 @@ /* * Globals to control TLS allocation. */ -size_t tls_last_offset; /* TLS offset of last module */ -size_t tls_last_size; /* TLS size of last module */ +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 */ @@ -751,11 +752,8 @@ case PT_TLS: obj->tlsindex = 1; - obj->tlsoffset = calculate_first_tls_offset(ph->p_memsz, - ph->p_align); - tls_last_offset = obj->tlsoffset; - tls_last_size = obj->tlssize; obj->tlssize = ph->p_memsz; + obj->tlsalign = ph->p_align; obj->tlsinitsize = ph->p_filesz; obj->tlsinit = (void*) ph->p_vaddr; break; ==== //depot/projects/kse/libexec/rtld-elf/rtld.h#5 (text+ko) ==== @@ -65,6 +65,7 @@ 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; @@ -147,7 +148,8 @@ 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 */ + 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 */ @@ -182,6 +184,7 @@ 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 (%) */ @@ -238,6 +241,7 @@ int reloc_non_plt(Obj_Entry *, Obj_Entry *); int reloc_plt(Obj_Entry *); int reloc_jmpslots(Obj_Entry *); +bool allocate_tls_offset(Obj_Entry *obj); void *allocate_tls(Objlist *, size_t, size_t); void free_tls(Objlist *, void *, size_t, size_t); void allocate_initial_tls(Objlist *);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200407221218.i6MCI2wP099972>