Re: rtld to support __thread tls

看板DFBSD_kernel作者時間21年前 (2005/03/05 15:32), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串9/10 (看更多)
This is a multi-part message in MIME format. --------------050503010701060005080703 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Matthew Dillon wrote: > Well, lets not let this slip through the cracks. We want __thread / TLS > support and we have the GDT infrastructure to do it now. Maybe you > should push your current patch set to David Xu with a quick summary and > you and he can discuss architectural issues over the weekend. > > -Matt > Matthew Dillon > <dillon@backplane.com> Hi All, Because Joerg is working on rtld, I just picked up an relative easier task --- hack all necessary code to support __thread for static libary, I have spent two hours to work out all patches, please see attached file, they works on my machine (a SMP box). I don't know what was committed into rtld by Joerg yet, since I have to fix some broken code due to FreeBSD's swappable kernel stack issue, not have enough time. =( Note, this only works for static library! the patches do not affect shared objects, however applying the patch should be safe. you should use gcc3 to compile sample code tls_test.c. the gcc 2.95 does not support __thread. I use csh, so: # setenv CCVER gcc34 # cc -o tls_test tls_test.c -static -lthread_xu David Xu --------------050503010701060005080703 Content-Type: text/plain; name="csu.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="csu.diff" Index: i386/crt1.c =================================================================== RCS file: /cvs/src/lib/csu/i386/crt1.c,v retrieving revision 1.1 diff -u -r1.1 crt1.c --- i386/crt1.c 15 Jun 2004 08:53:09 -0000 1.1 +++ i386/crt1.c 5 Mar 2005 07:04:41 -0000 @@ -39,6 +39,7 @@ extern void _fini(void); extern void _init(void); extern int main(int, char **, char **); +extern void _init_tls(void); #ifdef GCRT extern void _mcleanup(void); @@ -85,6 +86,8 @@ if(&_DYNAMIC != NULL) atexit(rtld_cleanup); + else + _init_tls(); #ifdef GCRT atexit(_mcleanup); --------------050503010701060005080703 Content-Type: text/plain; name="kern.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="kern.diff" Index: kern/imgact_elf.c =================================================================== RCS file: /cvs/src/sys/kern/imgact_elf.c,v retrieving revision 1.25 diff -u -r1.25 imgact_elf.c --- kern/imgact_elf.c 26 Feb 2005 20:32:36 -0000 1.25 +++ kern/imgact_elf.c 5 Mar 2005 07:02:31 -0000 @@ -542,6 +542,17 @@ phdr[i].p_filesz, prot)) != 0) goto fail; + /* + * If this segment contains the program headers, + * remember their virtual address for the AT_PHDR + * aux entry. Static binaries don't usually include + * a PT_PHDR entry. + */ + if (phdr[i].p_offset == 0 && + hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize + <= phdr[i].p_filesz) + proghdr = phdr[i].p_vaddr + hdr->e_phoff; + seg_addr = trunc_page(phdr[i].p_vaddr); seg_size = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - seg_addr); --------------050503010701060005080703 Content-Type: text/plain; name="libc.diffs" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="libc.diffs" Index: gen/Makefile.inc =================================================================== RCS file: /cvs/src/lib/libc/gen/Makefile.inc,v retrieving revision 1.7 diff -u -r1.7 Makefile.inc --- gen/Makefile.inc 20 Feb 2005 01:52:25 -0000 1.7 +++ gen/Makefile.inc 5 Mar 2005 06:57:37 -0000 @@ -28,7 +28,7 @@ shmat.c shmctl.c shmdt.c shmget.c siginterrupt.c siglist.c signal.c \ sigsetops.c sigwait.c sleep.c srand48.c stringlist.c strtofflags.c \ sysconf.c sysctl.c sysctlbyname.c sysctlnametomib.c \ - syslog.c telldir.c termios.c time.c times.c timezone.c ttyname.c \ + syslog.c telldir.c termios.c time.c times.c timezone.c tls.c ttyname.c \ ttyslot.c ualarm.c ulimit.c uname.c unvis.c usleep.c utime.c \ valloc.c vis.c \ wait.c wait3.c waitpid.c Index: i386/gen/Makefile.inc =================================================================== RCS file: /cvs/src/lib/libc/i386/gen/Makefile.inc,v retrieving revision 1.2 diff -u -r1.2 Makefile.inc --- i386/gen/Makefile.inc 17 Jun 2003 04:26:42 -0000 1.2 +++ i386/gen/Makefile.inc 5 Mar 2005 06:57:37 -0000 @@ -2,5 +2,5 @@ # $FreeBSD: src/lib/libc/i386/gen/Makefile.inc,v 1.10.2.1 2001/02/07 00:12:45 peter Exp $ # $DragonFly: src/lib/libc/i386/gen/Makefile.inc,v 1.2 2003/06/17 04:26:42 dillon Exp $ -SRCS+= _setjmp.S alloca.S fabs.S frexp.c infinity.c isinf.c ldexp.c modf.S \ - rfork_thread.S setjmp.S sigsetjmp.S +SRCS+= _set_tp.c _setjmp.S alloca.S fabs.S frexp.c infinity.c isinf.c \ + ldexp.c modf.S rfork_thread.S setjmp.S sigsetjmp.S Index: include/libc_private.h =================================================================== RCS file: /cvs/src/lib/libc/include/libc_private.h,v retrieving revision 1.3 diff -u -r1.3 libc_private.h --- include/libc_private.h 31 Jan 2005 22:29:29 -0000 1.3 +++ include/libc_private.h 5 Mar 2005 06:57:37 -0000 @@ -72,4 +72,14 @@ int _fseeko(FILE *, __off_t, int); #endif +/* + * Initialise TLS static programs + */ +void _init_tls(void); + +/* + * Set the TLS thread pointer + */ +void _set_tp(void *p, int size); + #endif /* _LIBC_PRIVATE_H_ */ --- /dev/null 2005-03-05 14:01:56.000000000 +0000 +++ gen/tls.c 2005-03-05 14:51:56.000000000 +0000 @@ -0,0 +1,301 @@ +/*- + * 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/lib/libc/gen/tls.c,v 1.7 2005/03/01 23:42:00 davidxu Exp $ + * $DragonFly$ + */ + +/* + * Define stubs for TLS internals so that programs and libraries can + * link. These functions will be replaced by functional versions at + * runtime from ld-elf.so.1. + */ + +#include <stdlib.h> +#include <string.h> +#include <elf.h> +#include <assert.h> +#include "libc_private.h" + +/* XXX not sure what variants to use for arm. */ + +#if defined(__ia64__) || defined(__powerpc__) +#define TLS_VARIANT_I +#endif +#if defined(__i386__) || defined(__amd64__) || defined(__sparc64__) || \ + defined(__arm__) +#define TLS_VARIANT_II +#endif + +#ifndef PIC + +#define round(size, align) \ + (((size) + (align) - 1) & ~((align) - 1)) + +static size_t tls_static_space; +static size_t tls_init_size; +#ifdef TLS_VARIANT_I +static size_t tls_init_offset; +#endif +static void *tls_init; +#endif + +void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); +void _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign); +void *__tls_get_addr(void *); + +#ifdef __i386__ + +extern void *___tls_get_addr(void *ti) __attribute__((__regparm__(1))); + +#pragma weak ___tls_get_addr +__attribute__((__regparm__(1))) +void * +___tls_get_addr(void *ti __unused) +{ + return (0); +} + +#endif + +#pragma weak __tls_get_addr +void * +__tls_get_addr(void *ti __unused) +{ + return (0); +} + +#ifdef TLS_VARIANT_I + +#pragma weak _rtld_free_tls +/* + * Free Static TLS using the Variant I method. + */ +void +_rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign) +{ +#ifndef PIC + Elf_Addr* dtv; + + dtv = ((Elf_Addr**)tls)[0]; + free(tls); + free(dtv); +#endif +} + +#pragma weak _rtld_allocate_tls +/* + * Allocate Static TLS using the Variant I method. + */ +void * +_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +{ +#ifndef PIC + size_t size; + char *tls; + Elf_Addr *dtv; + + size = tls_static_space; + if (size < tcbsize) + size = tcbsize; + + tls = malloc(size); + dtv = malloc(3 * sizeof(Elf_Addr)); + + *(Elf_Addr**) tls = dtv; + + dtv[0] = 1; + dtv[1] = 1; + dtv[2] = (Elf_Addr)(tls + tls_init_offset); + if (oldtls) { + /* + * Copy the static TLS block over whole. + */ + memcpy(tls + tls_init_offset, + (char*) oldtls + tls_init_offset, + tls_static_space - tls_init_offset); + + /* + * We assume that this block was the one we created with + * allocate_initial_tls(). + */ + _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + } else { + memcpy(tls + tls_init_offset, tls_init, tls_init_size); + memset(tls + tls_init_offset + tls_init_size, + 0, tls_static_space - tls_init_size); + } + + return tls; +#else + return (0); +#endif +} + +#endif + +#ifdef TLS_VARIANT_II + +/* + * Free Static TLS using the Variant II method. + */ +#pragma weak _rtld_free_tls +void +_rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) +{ +#ifndef PIC + size_t size; + Elf_Addr* dtv; + 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**)tcb)[1]; + tlsend = (Elf_Addr) tcb; + tlsstart = tlsend - size; + free((void*) tlsstart); + free(dtv); +#endif +} + +#pragma weak _rtld_allocate_tls +/* + * Allocate Static TLS using the Variant II method. + */ +void * +_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) +{ +#ifndef PIC + size_t size; + char *tls; + Elf_Addr *dtv; + Elf_Addr segbase, oldsegbase; + + size = round(tls_static_space, tcbalign); + + assert(tcbsize >= 2*sizeof(Elf_Addr)); + tls = malloc(size + tcbsize); + dtv = malloc(3 * sizeof(Elf_Addr)); + + segbase = (Elf_Addr)(tls + size); + ((Elf_Addr*)segbase)[0] = segbase; + ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv; + + dtv[0] = 1; + dtv[1] = 1; + dtv[2] = segbase - tls_static_space; + + 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); + + /* + * We assume that this block was the one we created with + * allocate_initial_tls(). + */ + _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); + } else { + memcpy((void *)(segbase - tls_static_space), + tls_init, tls_init_size); + memset((void *)(segbase - tls_static_space + tls_init_size), + 0, tls_static_space - tls_init_size); + } + + return (void*) segbase; +#else + return (0); +#endif +} + +#endif /* TLS_VARIANT_II */ + +extern char **environ; + +void +_init_tls() +{ +#ifndef PIC + Elf_Addr *sp; + Elf_Auxinfo *aux, *auxp; + Elf_Phdr *phdr; + size_t phent, phnum; + int i; + void *tls; + + sp = (Elf_Addr *) environ; + while (*sp++ != 0) + ; + aux = (Elf_Auxinfo *) sp; + phdr = 0; + phent = phnum = 0; + for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { + switch (auxp->a_type) { + case AT_PHDR: + phdr = auxp->a_un.a_ptr; + break; + + case AT_PHENT: + phent = auxp->a_un.a_val; + break; + + case AT_PHNUM: + phnum = auxp->a_un.a_val; + break; + } + } + if (phdr == 0 || phent != sizeof(Elf_Phdr) || phnum == 0) + return; + + for (i = 0; (unsigned)i < phnum; i++) { + if (phdr[i].p_type == PT_TLS) { +#ifdef TLS_VARIANT_I + tls_static_space = round(2*sizeof(Elf_Addr), + phdr[i].p_align) + phdr[i].p_memsz; + tls_init_offset = round(2*sizeof(Elf_Addr), + phdr[i].p_align); +#else + tls_static_space = round(phdr[i].p_memsz, + phdr[i].p_align); +#endif + tls_init_size = phdr[i].p_filesz; + tls_init = (void*) phdr[i].p_vaddr; + } + } + + tls = _rtld_allocate_tls(NULL, 2*sizeof(Elf_Addr), + sizeof(Elf_Addr)); + + _set_tp(tls, 2 * sizeof(Elf_Addr)); +#endif +} --- /dev/null 2005-03-05 14:01:56.000000000 +0000 +++ i386/gen/_set_tp.c 2005-03-05 14:51:07.000000000 +0000 @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2005 David Xu + * 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. + * + * $DragonFly$ + */ + +#include <sys/tls.h> + +#include "libc_private.h" + +void +_set_tp(void *tp, int size) +{ + struct tls_info t; + int seg; + + t.base = tp; + t.size = size; + seg = sys_set_tls_area(0, &t, sizeof(t)); + __asm __volatile("movl %0, %%gs" : : "r" (seg)); +} --------------050503010701060005080703 Content-Type: text/plain; name="libthread_xu.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="libthread_xu.diff" Index: arch/i386/i386/pthread_md.c =================================================================== RCS file: /cvs/src/lib/libthread_xu/arch/i386/i386/pthread_md.c,v retrieving revision 1.3 diff -u -r1.3 pthread_md.c --- arch/i386/i386/pthread_md.c 22 Feb 2005 14:56:22 -0000 1.3 +++ arch/i386/i386/pthread_md.c 5 Mar 2005 07:03:14 -0000 @@ -31,19 +31,25 @@ #include <sys/tls.h> #include <stdlib.h> +#include "rtld_tls.h" #include "pthread_md.h" struct tcb * _tcb_ctor(struct pthread *thread, int initial) { struct tcb *tcb; + void *oldtls; - if ((tcb = malloc(sizeof(struct tcb))) == NULL) - return (NULL); - tcb->tcb_self = tcb; - tcb->tcb_dtv = NULL; - tcb->tcb_thread = thread; - tcb->tcb_seg = -1; + if (initial) + __asm __volatile("movl %%gs:0, %0" : "=r" (oldtls)); + else + oldtls = NULL; + + tcb = _rtld_allocate_tls(oldtls, sizeof(struct tcb), 16); + if (tcb) { + tcb->tcb_thread = thread; + tcb->tcb_seg = -1; + } return (tcb); } @@ -62,5 +68,5 @@ void _tcb_dtor(struct tcb *tcb) { - free(tcb); + _rtld_free_tls(tcb, sizeof(struct tcb), 16); } --------------050503010701060005080703 Content-Type: text/plain; name="tls_test.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="tls_test.c" #include <stdio.h> #include <pthread.h> int __thread i; void *f(void *a) { for (i = 9; i >=0; --i) { printf("%d\n", i); sleep(1); } return (0); } void *g(void *a) { for (i = 0; i <= 9; ++i) { printf("%d\n", i); sleep(1); } return (0); } int main() { pthread_t td1, td2; pthread_create(&td1, NULL, f, NULL); pthread_create(&td2, NULL, g, NULL); pthread_join(td1, NULL); pthread_join(td2, NULL); return (0); } --------------050503010701060005080703--
文章代碼(AID): #12AM1-00 (DFBSD_kernel)
討論串 (同標題文章)
文章代碼(AID): #12AM1-00 (DFBSD_kernel)