This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.
Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hi Jakub, >>>>> On Wed, 29 Oct 2003 08:44:36 +0100, Jakub Jelinek <jakub@redhat.com> said: Jakub> Yes, please post a forward ported complete tested patch (the last Jakub> version of the patch I and Ulrich saw was incomplete (but lead to Jakub> discovery of a linker bug)). Jakub> NPTL is now in sources CVS, so things are way easier for diffing... OK, here is a preliminary patch. Some comments: - The "assert (ph->p_vaddr == GL(dl_sysinfo_dso)" check in elf/rtld.c is too strict. On ia64, we have two LOAD segments, so the check can't possibly succeed: $ readelf -l arch/ia64/kernel/gate.so |grep LOAD LOAD 0x0000000000000000 0xa000000000010000 0xa000000000010000 LOAD 0x0000000000000000 0xa000000000020000 0xa000000000020000 The patch below simply #if's out the code, but perhaps a better fix would be to check ph->p_vaddr only for the first LOAD segment? - The changes to linuxthreads/{manager,pthread}.c are almost certainly wrong, but I'm not sure I understand how you want things set up to ensure that single-threaded apps use the new stub but linuxthread apps use the old one. - The ia64-specific vfork.S for now are done via old-style stub. I'm not sure whether this is still necessary and will look into it. - The libc-start.c change is also "wrong" but since DL_SYSDEP_OSCHECK() may do syscalls, it is necessary to do __pthread_initialize_minimal() first, as otherwise the minimal thread descriptor isn't setup. The rest should be good. With the patch applied, "make check" gets through all the tests except the linuxthread ones. I wasn't sure whether it's worth tracking those down, since the linuxthreads part is likely to change anyhow. --david Index: elf/rtld.c =================================================================== RCS file: /cvs/glibc/libc/elf/rtld.c,v retrieving revision 1.299 diff -u -r1.299 rtld.c --- elf/rtld.c 27 Oct 2003 20:08:32 -0000 1.299 +++ elf/rtld.c 30 Oct 2003 07:55:02 -0000 @@ -1169,8 +1169,10 @@ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); break; } +#if 0 if (ph->p_type == PT_LOAD) assert ((void *) ph->p_vaddr == GL(dl_sysinfo_dso)); +#endif } elf_get_dynamic_info (l, dyn_temp); _dl_setup_hash (l); Index: linuxthreads/descr.h =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/descr.h,v retrieving revision 1.14 diff -u -r1.14 descr.h --- linuxthreads/descr.h 17 Sep 2003 09:39:00 -0000 1.14 +++ linuxthreads/descr.h 30 Oct 2003 07:55:02 -0000 @@ -189,7 +189,23 @@ #endif size_t p_alloca_cutoff; /* Maximum size which should be allocated using alloca() instead of malloc(). */ +#if TLS_TCB_AT_TP /* New elements must be added at the end. */ +#else + union { + struct { + void *reserved[11]; /* reserve for future use */ + void *tcb; /* XXX do we really need this? */ + union dtv *dtvp; /* XXX do we really need this? */ + pthread_descr self; /* XXX do we really need this? */ + int multiple_threads; +#ifdef NEED_DL_SYSINFO + uintptr_t sysinfo; +#endif + } data; + void *__padding[16]; + } p_header __attribute__ ((aligned(32))); +#endif } __attribute__ ((aligned(32))); /* We need to align the structure so that doubles are aligned properly. This is 8 bytes on MIPS and 16 bytes on MIPS64. Index: linuxthreads/manager.c =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/manager.c,v retrieving revision 1.96 diff -u -r1.96 manager.c --- linuxthreads/manager.c 15 Oct 2003 05:53:06 -0000 1.96 +++ linuxthreads/manager.c 30 Oct 2003 07:55:02 -0000 @@ -650,6 +650,10 @@ #if !defined USE_TLS || !TLS_DTV_AT_TP new_thread->p_header.data.tcb = new_thread; new_thread->p_header.data.self = new_thread; +# if 1 + /* XXX why isn't this done already??? */ + new_thread->p_header.data.sysinfo = GL(dl_sysinfo); +# endif #endif #if TLS_MULTIPLE_THREADS_IN_TCB || !defined USE_TLS || !TLS_DTV_AT_TP new_thread->p_multiple_threads = 1; Index: linuxthreads/pthread.c =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/pthread.c,v retrieving revision 1.132 diff -u -r1.132 pthread.c --- linuxthreads/pthread.c 15 Oct 2003 05:53:44 -0000 1.132 +++ linuxthreads/pthread.c 30 Oct 2003 07:55:02 -0000 @@ -357,6 +357,11 @@ self = THREAD_SELF; +#if 1 + /* XXX why isn't this done already??? */ + self->p_header.data.sysinfo = GL(dl_sysinfo); +#endif + /* The memory for the thread descriptor was allocated elsewhere as part of the TLS allocation. We have to initialize the data structure by hand. This initialization must mirror the struct @@ -676,6 +681,10 @@ mgr->p_header.data.tcb = tcbp; mgr->p_header.data.self = mgr; mgr->p_header.data.multiple_threads = 1; +# if 1 + /* XXX why isn't this done already??? */ + mgr->p_header.data.sysinfo = GL(dl_sysinfo); +# endif #elif TLS_MULTIPLE_THREADS_IN_TCB mgr->p_multiple_threads = 1; #endif Index: linuxthreads/sysdeps/ia64/tcb-offsets.sym =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/sysdeps/ia64/tcb-offsets.sym,v retrieving revision 1.6 diff -u -r1.6 tcb-offsets.sym --- linuxthreads/sysdeps/ia64/tcb-offsets.sym 25 Apr 2003 22:04:27 -0000 1.6 +++ linuxthreads/sysdeps/ia64/tcb-offsets.sym 30 Oct 2003 07:55:02 -0000 @@ -4,6 +4,7 @@ -- #ifdef USE_TLS MULTIPLE_THREADS_OFFSET offsetof (struct _pthread_descr_struct, p_multiple_threads) - sizeof (struct _pthread_descr_struct) +SYSINFO_OFFSET offsetof (struct _pthread_descr_struct, p_header.data.sysinfo) - sizeof (struct _pthread_descr_struct) #else MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) #endif Index: linuxthreads/sysdeps/ia64/tls.h =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/sysdeps/ia64/tls.h,v retrieving revision 1.6 diff -u -r1.6 tls.h --- linuxthreads/sysdeps/ia64/tls.h 31 Jul 2003 19:16:34 -0000 1.6 +++ linuxthreads/sysdeps/ia64/tls.h 30 Oct 2003 07:55:02 -0000 @@ -20,10 +20,13 @@ #ifndef _TLS_H #define _TLS_H +#include <dl-sysdep.h> + #ifndef __ASSEMBLER__ # include <pt-machine.h> # include <stddef.h> +# include <stdint.h> /* Type for the dtv. */ typedef union dtv @@ -83,8 +86,10 @@ /* Code to initially initialize the thread pointer. This might need special attention since 'errno' is not yet available and if the operation can cause a failure 'errno' must not be touched. */ -# define TLS_INIT_TP(tcbp, secondcall) \ - (__thread_self = (__typeof (__thread_self)) (tcbp), NULL) +# define TLS_INIT_TP(tcbp, secondcall) \ + (__thread_self = (__typeof (__thread_self)) (tcbp), \ + THREAD_SELF->p_header.data.sysinfo = GL(dl_sysinfo), \ + NULL) /* Return the address of the dtv for the current thread. */ # define THREAD_DTV() \ Index: linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S =================================================================== RCS file: /cvs/glibc/libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S,v retrieving revision 1.4 diff -u -r1.4 vfork.S --- linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S 11 Feb 2003 06:27:53 -0000 1.4 +++ linuxthreads/sysdeps/unix/sysv/linux/ia64/vfork.S 30 Oct 2003 07:55:02 -0000 @@ -43,9 +43,13 @@ mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD mov out1=0 /* Standard sp value. */ ;; +#if 0 DO_CALL (SYS_ify (clone)) +#else + mov r15=SYS_ify(clone) + break __BREAK_SYSCALL +#endif cmp.eq p6,p0=-1,r10 - ;; (p6) br.cond.spnt.few __syscall_error ret PSEUDO_END(__vfork) Index: sysdeps/generic/libc-start.c =================================================================== RCS file: /cvs/glibc/libc/sysdeps/generic/libc-start.c,v retrieving revision 1.46 diff -u -r1.46 libc-start.c --- sysdeps/generic/libc-start.c 31 Jul 2003 19:20:39 -0000 1.46 +++ sysdeps/generic/libc-start.c 30 Oct 2003 07:55:04 -0000 @@ -123,14 +123,6 @@ # endif _dl_aux_init (auxvec); # endif -# ifdef DL_SYSDEP_OSCHECK - if (!__libc_multiple_libcs) - { - /* This needs to run to initiliaze _dl_osversion before TLS - setup might check it. */ - DL_SYSDEP_OSCHECK (__libc_fatal); - } -# endif /* Initialize the thread library at least a bit since the libgcc functions are using thread functions if these are available and @@ -142,6 +134,15 @@ # endif __pthread_initialize_minimal (); #endif + +# ifdef DL_SYSDEP_OSCHECK + if (!__libc_multiple_libcs) + { + /* This needs to run to initiliaze _dl_osversion before TLS + setup might check it. */ + DL_SYSDEP_OSCHECK (__libc_fatal); + } +# endif /* Register the destructor of the dynamic linker if there is any. */ if (__builtin_expect (rtld_fini != NULL, 1)) Index: sysdeps/unix/sysv/linux/ia64/clone2.S =================================================================== RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/ia64/clone2.S,v retrieving revision 1.7 diff -u -r1.7 clone2.S --- sysdeps/unix/sysv/linux/ia64/clone2.S 13 Mar 2003 04:36:59 -0000 1.7 +++ sysdeps/unix/sysv/linux/ia64/clone2.S 30 Oct 2003 07:55:07 -0000 @@ -25,49 +25,56 @@ /* size_t child_stack_size, int flags, void *arg, */ /* pid_t *parent_tid, void *tls, pid_t *child_tid) */ +#define CHILD p8 +#define PARENT p9 + ENTRY(__clone2) - alloc r2=ar.pfs,8,2,6,0 + .prologue + alloc r2=ar.pfs,8,0,6,0 cmp.eq p6,p0=0,in0 mov r8=EINVAL -(p6) br.cond.spnt.few __syscall_error - ;; - flushrs /* This is necessary, since the child */ - /* will be running with the same */ - /* register backing store for a few */ - /* instructions. We need to ensure */ - /* that it will not read or write the */ - /* backing store. */ - mov loc0=in0 /* save fn */ - mov loc1=in4 /* save arg */ mov out0=in3 /* Flags are first syscall argument. */ mov out1=in1 /* Stack address. */ +(p6) br.cond.spnt.many __syscall_error + ;; mov out2=in2 /* Stack size. */ mov out3=in5 /* Parent TID Pointer */ mov out4=in7 /* Child TID Pointer */ mov out5=in6 /* TLS pointer */ - DO_CALL (SYS_ify (clone2)) + /* + * clone2() is special: the child cannot execute br.ret right + * after the system call returns, because it starts out + * executing on an empty stack. Because of this, we can't use + * the new (lightweight) syscall convention here. Instead, we + * just fall back on always using "break". + * + * Furthermore, since the child starts with an empty stack, we + * need to avoid unwinding past invalid memory. To that end, + * we'll pretend now that __clone2() is the end of the + * call-chain. This is wrong for the parent, but only until + * it returns from clone2() but it's better than the + * alternative. + */ + mov r15=SYS_ify (clone2) + .save rp, r0 + break __BREAK_SYSCALL + .body cmp.eq p6,p0=-1,r10 + cmp.eq CHILD,PARENT=0,r8 /* Are we the child? */ +(p6) br.cond.spnt.many __syscall_error ;; -(p6) br.cond.spnt.few __syscall_error - -# define CHILD p6 -# define PARENT p7 - cmp.eq CHILD,PARENT=0,r8 /* Are we the child? */ - ;; -(CHILD) ld8 out1=[loc0],8 /* Retrieve code pointer. */ -(CHILD) mov out0=loc1 /* Pass proper argument to fn */ +(CHILD) ld8 out1=[in0],8 /* Retrieve code pointer. */ +(CHILD) mov out0=in4 /* Pass proper argument to fn */ (PARENT) ret ;; - ld8 gp=[loc0] /* Load function gp. */ + ld8 gp=[in0] /* Load function gp. */ mov b6=out1 - ;; - br.call.dptk.few rp=b6 /* Call fn(arg) in the child */ + br.call.dptk.many rp=b6 /* Call fn(arg) in the child */ ;; mov out0=r8 /* Argument to _exit */ .globl _exit - br.call.dpnt.few rp=_exit /* call _exit with result from fn. */ + br.call.dpnt.many rp=_exit /* call _exit with result from fn. */ ret /* Not reached. */ - PSEUDO_END(__clone2) /* For now we leave __clone undefined. This is unlikely to be a */ Index: sysdeps/unix/sysv/linux/ia64/sysdep.h =================================================================== RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/ia64/sysdep.h,v retrieving revision 1.17 diff -u -r1.17 sysdep.h --- sysdeps/unix/sysv/linux/ia64/sysdep.h 16 Aug 2003 08:00:24 -0000 1.17 +++ sysdeps/unix/sysv/linux/ia64/sysdep.h 30 Oct 2003 07:55:08 -0000 @@ -23,6 +23,7 @@ #include <sysdeps/unix/sysdep.h> #include <sysdeps/ia64/sysdep.h> +#include <tls.h> /* For Linux we can use the system call table in the header file /usr/include/asm/unistd.h @@ -95,9 +96,32 @@ cmp.eq p6,p0=-1,r10; \ (p6) br.cond.spnt.few __syscall_error; -#define DO_CALL(num) \ +#define DO_CALL_VIA_BREAK(num) \ mov r15=num; \ - break __BREAK_SYSCALL; + break __BREAK_SYSCALL + +#if defined HAVE_TLS_SUPPORT && (!defined NOT_IN_libc || defined IS_IN_libpthread) + +/* Use the lightweight stub only if (a) we have a suitably modern + thread-control block (HAVE_TLS_SUPPORT) and (b) we're not compiling + the runtime loader (which might do syscalls before being fully + relocated). */ + +#define DO_CALL(num) \ + .prologue; \ + adds r2 = SYSINFO_OFFSET, r13;; \ + ld8 r2 = [r2]; \ + .save ar.pfs, r11; \ + mov r11 = ar.pfs;; \ + .body; \ + mov r15 = num; \ + mov b7 = r2; \ + br.call.sptk.many b6 = b7;; \ + .restore sp; \ + mov ar.pfs = r11 +#else +#define DO_CALL(num) DO_CALL_VIA_BREAK(num) +#endif #undef PSEUDO_END #define PSEUDO_END(name) .endp C_SYMBOL_NAME(name); @@ -144,6 +168,47 @@ (non-negative) errno on error or the return value on success. */ #undef INLINE_SYSCALL +#undef INTERNAL_SYSCALL +#if defined HAVE_TLS_SUPPORT && (!defined NOT_IN_libc || defined IS_IN_libpthread) + +#define DO_INLINE_SYSCALL(name, nr, args...) \ + register long _r8 __asm ("r8"); \ + register long _r10 __asm ("r10"); \ + register long _r15 __asm ("r15") = __NR_##name; \ + long _retval; \ + LOAD_ARGS_##nr (args); \ + /* \ + * Don't specify any unwind info here. We mark ar.pfs as clobbered. This will force \ + * the compiler to save ar.pfs somewhere and emit appropriate unwind info for that \ + * save. \ + */ \ + __asm __volatile ("adds r2 = -8, r13;;\n" \ + "ld8 r2 = [r2];;\n" \ + "mov b7=r2;\n" \ + "br.call.sptk.many b6=b7;;\n" \ + : "=r" (_r8), "=r" (_r10), "=r" (_r15) ASM_OUTARGS_##nr \ + : "2" (_r15) ASM_ARGS_##nr \ + : "memory", "ar.pfs" ASM_CLOBBERS_##nr); \ + _retval = _r8; + +#define INLINE_SYSCALL(name, nr, args...) \ + ({ \ + DO_INLINE_SYSCALL(name, nr, args) \ + if (_r10 == -1) \ + { \ + __set_errno (_retval); \ + _retval = -1; \ + } \ + _retval; }) + +#define INTERNAL_SYSCALL(name, err, nr, args...) \ + ({ \ + DO_INLINE_SYSCALL(name, nr, args) \ + err = _r10; \ + _retval; }) + +#else /* !new syscall-stub */ + #define INLINE_SYSCALL(name, nr, args...) \ ({ \ register long _r8 asm ("r8"); \ @@ -164,10 +229,6 @@ } \ _retval; }) -#undef INTERNAL_SYSCALL_DECL -#define INTERNAL_SYSCALL_DECL(err) long int err - -#undef INTERNAL_SYSCALL #define INTERNAL_SYSCALL(name, err, nr, args...) \ ({ \ register long _r8 asm ("r8"); \ @@ -183,6 +244,11 @@ _retval = _r8; \ err = _r10; \ _retval; }) + +#endif /* !new syscall-stub */ + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) long int err #undef INTERNAL_SYSCALL_ERROR_P #define INTERNAL_SYSCALL_ERROR_P(val, err) (err == -1) Index: sysdeps/unix/sysv/linux/ia64/vfork.S =================================================================== RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/ia64/vfork.S,v retrieving revision 1.4 diff -u -r1.4 vfork.S --- sysdeps/unix/sysv/linux/ia64/vfork.S 31 Dec 2002 20:37:30 -0000 1.4 +++ sysdeps/unix/sysv/linux/ia64/vfork.S 30 Oct 2003 07:55:08 -0000 @@ -34,9 +34,13 @@ mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD mov out1=0 /* Standard sp value. */ ;; +#if 0 DO_CALL (SYS_ify (clone)) +#else + mov r15=SYS_ify(clone) + break __BREAK_SYSCALL +#endif cmp.eq p6,p0=-1,r10 - ;; (p6) br.cond.spnt.few __syscall_error ret PSEUDO_END(__vfork)
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |