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]

Re: new syscall stub support for ia64 libc


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]