about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--elf/rtld.c14
-rw-r--r--linuxthreads/Makefile12
-rw-r--r--linuxthreads/descr.h4
-rw-r--r--linuxthreads/libc_pthread_init.c3
-rw-r--r--linuxthreads/sysdeps/i386/tls.h21
-rw-r--r--linuxthreads/sysdeps/ia64/tls.h64
-rw-r--r--linuxthreads/sysdeps/pthread/bits/libc-lock.h4
-rw-r--r--linuxthreads/sysdeps/sparc/sparc32/tls.h61
-rw-r--r--linuxthreads/sysdeps/sparc/sparc64/tls.h61
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h60
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h2
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile3
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h118
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h99
-rw-r--r--linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h98
-rw-r--r--linuxthreads/sysdeps/x86_64/tls.h5
-rw-r--r--nptl/ChangeLog26
-rw-r--r--nptl/Makefile4
-rw-r--r--nptl/descr.h2
-rw-r--r--nptl/sysdeps/i386/tls.h6
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/dl-sysdep.h26
-rw-r--r--nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h5
-rw-r--r--nptl/tst-cancel4.c6
-rw-r--r--sysdeps/generic/libc-start.c4
-rw-r--r--sysdeps/generic/libc-tls.c21
-rw-r--r--sysdeps/unix/common/pause.c12
-rw-r--r--sysdeps/unix/sysv/linux/i386/sysdep.h5
-rw-r--r--sysdeps/unix/sysv/linux/ia64/sysdep.h101
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/pipe.S10
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/socket.S7
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S28
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h52
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/pipe.S7
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/socket.S6
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S10
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h50
36 files changed, 907 insertions, 110 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index d510018cb4..b8e7f9af6b 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1150,6 +1150,10 @@ of this helper program; chances are you did not intend to run this program.\n\
     /* Assign a module ID.  */
     GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
 
+# ifndef TLS_INIT_TP_EXPENSIVE
+#  define TLS_INIT_TP_EXPENSIVE 0
+# endif
+
   /* We do not initialize any of the TLS functionality unless any of the
      initial modules uses TLS.  This makes dynamic loading of modules with
      TLS impossible, but to support it requires either eagerly doing setup
@@ -1157,7 +1161,7 @@ of this helper program; chances are you did not intend to run this program.\n\
      an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
      used.  Trying to do it lazily is too hairy to try when there could be
      multiple threads (from a non-TLS-using libpthread).  */
-  if (GL(dl_tls_max_dtv_idx) > 0)
+  if (GL(dl_tls_max_dtv_idx) > 0 || !TLS_INIT_TP_EXPENSIVE)
     {
       struct link_map *l;
       size_t nelem;
@@ -1565,8 +1569,12 @@ cannot allocate TLS data structures for initial thread");
      we need it in the memory handling later.  */
   GL(dl_initial_searchlist) = *GL(dl_main_searchlist);
 
+#ifndef NONTLS_INIT_TP
+# define NONTLS_INIT_TP do { } while (0)
+#endif
+
 #ifdef USE_TLS
-  if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD)
+  if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
     {
       /* Now that we have completed relocation, the initializer data
 	 for the TLS blocks has its final values and we can copy them
@@ -1579,7 +1587,9 @@ cannot allocate TLS data structures for initial thread");
       if (__builtin_expect (lossage != NULL, 0))
 	_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
     }
+  else
 #endif
+    NONTLS_INIT_TP;
 
   {
     /* Initialize _r_debug.  */
diff --git a/linuxthreads/Makefile b/linuxthreads/Makefile
index e9cbf5e8b8..6425108389 100644
--- a/linuxthreads/Makefile
+++ b/linuxthreads/Makefile
@@ -74,8 +74,12 @@ endif
 librt-tests = ex10 ex11
 tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \
 	tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
-	ex17 ex18 tst-cancel tst-context bug-sleep
+	ex17 ex18 tst-cancel tst-context bug-sleep \
+	tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
+	tst-cancel6
 test-srcs = tst-signal
+# These tests are linked with libc before libpthread
+tests-reverse += tst-cancel5
 
 ifeq ($(build-static),yes)
 tests += tststatic tst-static-locale
@@ -149,8 +153,12 @@ $(objpfx)libpthread.so: $(libc-link.so) $(common-objpfx)libc_nonshared.a
 # Make sure we link with the thread library.
 ifeq ($(build-shared),yes)
 $(addprefix $(objpfx), \
-  $(filter-out $(tests-static) unload, \
+  $(filter-out $(tests-static) $(tests-reverse) unload, \
     $(tests) $(test-srcs))): $(objpfx)libpthread.so
+# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
+# since otherwise libpthread.so comes before libc.so when linking.
+$(addprefix $(objpfx), $(tests-reverse)): \
+  $(objpfx)../libc.so $(objpfx)libpthread.so
 $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so
 $(objpfx)unload: $(common-objpfx)dlfcn/libdl.so
 $(objpfx)unload.out: $(objpfx)libpthread.so
diff --git a/linuxthreads/descr.h b/linuxthreads/descr.h
index 94ad893979..74ef25e1f4 100644
--- a/linuxthreads/descr.h
+++ b/linuxthreads/descr.h
@@ -20,6 +20,7 @@
 #include <sched.h>
 #include <setjmp.h>
 #include <signal.h>
+#include <stdint.h>
 #include <sys/types.h>
 #include <hp-timing.h>
 #include <bits/libc-tsd.h> /* for _LIBC_TSD_KEY_N */
@@ -107,6 +108,9 @@ struct _pthread_descr_struct {
       union dtv *dtvp;
       pthread_descr self;	/* Pointer to this structure */
       int multiple_threads;
+#ifdef NEED_DL_SYSINFO
+      uintptr_t sysinfo;
+#endif
     } data;
     void *__padding[16];
   } p_header;
diff --git a/linuxthreads/libc_pthread_init.c b/linuxthreads/libc_pthread_init.c
index 901d333fbf..c952b22d07 100644
--- a/linuxthreads/libc_pthread_init.c
+++ b/linuxthreads/libc_pthread_init.c
@@ -17,9 +17,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <locale.h>
+#include <stdlib.h>
 #include <string.h>
 #include <tls.h>
-#include <locale.h>
 #include "internals.h"
 #include <sysdep-cancel.h>
 
diff --git a/linuxthreads/sysdeps/i386/tls.h b/linuxthreads/sysdeps/i386/tls.h
index c244801bf4..761a8ca943 100644
--- a/linuxthreads/sysdeps/i386/tls.h
+++ b/linuxthreads/sysdeps/i386/tls.h
@@ -20,10 +20,12 @@
 #ifndef _TLS_H
 #define _TLS_H
 
+# include <dl-sysdep.h>
 # include <pt-machine.h>
 
 #ifndef __ASSEMBLER__
 # include <stddef.h>
+# include <stdint.h>
 
 /* Type for the dtv.  */
 typedef union dtv
@@ -39,9 +41,17 @@ typedef struct
 			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
+#ifdef NEED_DL_SYSINFO
+  uintptr_t sysinfo;
+#endif
 } tcbhead_t;
 #endif
 
+#ifdef NEED_DL_SYSINFO
+/* Offset of the SYSINFO element in tcbhead_t.  */
+# define SYSINFO_OFFSET 24
+#endif
 
 /* We can support TLS only if the floating-stack support is available.
    However, we want to compile in the support and test at runtime whether
@@ -174,6 +184,12 @@ TLS_DO_MODIFY_LDT_KERNEL_CHECK(						      \
   TLS_DO_MODIFY_LDT ((descr), 0)
 #  endif
 
+#if defined NEED_DL_SYSINFO && defined SHARED
+# define INIT_SYSINFO \
+  head->sysinfo = GL(dl_sysinfo)
+#else
+# define INIT_SYSINFO
+#endif
 
 /* Code to initially initialize the thread pointer.  This might need
    special attention since 'errno' is not yet available and if the
@@ -189,9 +205,14 @@ TLS_DO_MODIFY_LDT_KERNEL_CHECK(						      \
     /* For now the thread descriptor is at the same address.  */	      \
     head->self = _descr;						      \
 									      \
+    INIT_SYSINFO;							      \
     TLS_SETUP_GS_SEGMENT (_descr, secondcall);				      \
   })
 
+/* Indicate that dynamic linker shouldn't try to initialize TLS even
+   when no PT_TLS segments are found in the program and libraries
+   it is linked against.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
 
 /* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
diff --git a/linuxthreads/sysdeps/ia64/tls.h b/linuxthreads/sysdeps/ia64/tls.h
new file mode 100644
index 0000000000..c270795254
--- /dev/null
+++ b/linuxthreads/sysdeps/ia64/tls.h
@@ -0,0 +1,64 @@
+/* Definitions for thread-local data handling.  linuxthreads/IA-64 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+
+/* FIXME: Only temporary.  When TLS is supported on IA-64,
+   pthread_descr struct needs to be immediately below r13 and
+   at r13 a struct { dtv_t *dtv; void *private; }.  */
+typedef struct
+{
+  void *tcb;		/* Pointer to the TCB.  Not necessary the
+			   thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
+} tcbhead_t;
+#endif /* __ASSEMBLER__ */
+
+#undef USE_TLS
+
+#if USE_TLS
+
+#else
+
+#define NONTLS_INIT_TP \
+  do { 								\
+    static const tcbhead_t nontls_init_tp			\
+      = { .multiple_threads = 0 };				\
+    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;	\
+  } while (0)
+
+#endif /* USE_TLS */
+
+#endif	/* tls.h */
diff --git a/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/linuxthreads/sysdeps/pthread/bits/libc-lock.h
index 217b0be253..cb839fa42e 100644
--- a/linuxthreads/sysdeps/pthread/bits/libc-lock.h
+++ b/linuxthreads/sysdeps/pthread/bits/libc-lock.h
@@ -97,7 +97,7 @@ typedef pthread_key_t __libc_key_t;
 #if defined _LIBC && defined IS_IN_libpthread
 # define __libc_maybe_call(FUNC, ARGS, ELSE) FUNC ARGS
 #else
-# ifdef __PIC__
+# if defined __PIC__ || (defined _LIBC && defined SHARED)
 #  define __libc_maybe_call(FUNC, ARGS, ELSE) \
   (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
                     _fn != NULL ? (*_fn) ARGS : ELSE; }))
@@ -106,7 +106,7 @@ typedef pthread_key_t __libc_key_t;
   (FUNC != NULL ? FUNC ARGS : ELSE)
 # endif
 #endif
-#if defined _LIBC && !defined NOT_IN_libc && defined __PIC__
+#if defined _LIBC && !defined NOT_IN_libc && defined SHARED
 # define __libc_maybe_call2(FUNC, ARGS, ELSE) \
   ({__libc_pthread_functions.ptr_##FUNC != NULL \
     ? __libc_pthread_functions.ptr_##FUNC ARGS : ELSE; })
diff --git a/linuxthreads/sysdeps/sparc/sparc32/tls.h b/linuxthreads/sysdeps/sparc/sparc32/tls.h
new file mode 100644
index 0000000000..1b316d0b33
--- /dev/null
+++ b/linuxthreads/sysdeps/sparc/sparc32/tls.h
@@ -0,0 +1,61 @@
+/* Definitions for thread-local data handling.  linuxthreads/sparc32 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+typedef struct
+{
+  void *tcb;		/* Pointer to the TCB.  Not necessary the
+			   thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
+} tcbhead_t;
+
+#endif /* __ASSEMBLER__ */
+
+#undef USE_TLS
+
+#if USE_TLS
+
+#else
+
+#define NONTLS_INIT_TP \
+  do { 								\
+    static const tcbhead_t nontls_init_tp			\
+      = { .multiple_threads = 0 };				\
+    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;	\
+  } while (0)
+
+#endif /* USE_TLS */
+
+#endif	/* tls.h */
diff --git a/linuxthreads/sysdeps/sparc/sparc64/tls.h b/linuxthreads/sysdeps/sparc/sparc64/tls.h
new file mode 100644
index 0000000000..039ad2bc48
--- /dev/null
+++ b/linuxthreads/sysdeps/sparc/sparc64/tls.h
@@ -0,0 +1,61 @@
+/* Definitions for thread-local data handling.  linuxthreads/sparc64 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+typedef struct
+{
+  void *tcb;		/* Pointer to the TCB.  Not necessary the
+			   thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
+} tcbhead_t;
+
+#endif /* __ASSEMBLER__ */
+
+#undef USE_TLS
+
+#if USE_TLS
+
+#else
+
+#define NONTLS_INIT_TP \
+  do { 								\
+    static const tcbhead_t nontls_init_tp			\
+      = { .multiple_threads = 0 };				\
+    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;	\
+  } while (0)
+
+#endif /* USE_TLS */
+
+#endif	/* tls.h */
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h b/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h
new file mode 100644
index 0000000000..ac19ac78a4
--- /dev/null
+++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/dl-sysdep.h
@@ -0,0 +1,60 @@
+/* System-specific settings for dynamic linker code.  IA-32 version.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _DL_SYSDEP_H
+#define _DL_SYSDEP_H	1
+
+/* This macro must be defined to either 0 or 1.
+
+   If 1, then an errno global variable hidden in ld.so will work right with
+   all the errno-using libc code compiled for ld.so, and there is never a
+   need to share the errno location with libc.  This is appropriate only if
+   all the libc functions that ld.so uses are called without PLT and always
+   get the versions linked into ld.so rather than the libc ones.  */
+
+#ifdef IS_IN_rtld
+# define RTLD_PRIVATE_ERRNO 1
+#else
+# define RTLD_PRIVATE_ERRNO 0
+#endif
+
+/* Traditionally system calls have been made using int $0x80.  A
+   second method was introduced which, if possible, will use the
+   sysenter/syscall instructions.  To signal the presence and where to
+   find the code the kernel passes an AT_SYSINFO value in the
+   auxiliary vector to the application.
+   sysenter/syscall is not useful on i386 through i586, but the dynamic
+   linker and dl code in libc.a has to be able to load i686 compiled
+   libraries.  */
+#define NEED_DL_SYSINFO	1
+#undef USE_DL_SYSINFO
+
+#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__
+extern void _dl_sysinfo_int80 (void) attribute_hidden;
+# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80
+# define DL_SYSINFO_IMPLEMENTATION \
+  asm (".type _dl_sysinfo_int80,@function\n\t"				      \
+       ".hidden _dl_sysinfo_int80\n"					      \
+       "_dl_sysinfo_int80:\n\t"						      \
+       "int $0x80;\n\t"							      \
+       "ret;\n\t"							      \
+       ".size _dl_sysinfo_int80,.-_dl_sysinfo_int80");
+#endif
+
+#endif	/* dl-sysdep.h */
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
index 30be0b9c5f..d449527900 100644
--- a/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
+++ b/linuxthreads/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h
@@ -25,7 +25,7 @@
 #endif
 
 #if defined FLOATING_STACKS && USE___THREAD
-# define MULTIPLE_THREADS_OFFSET	12
+# define MULTIPLE_THREADS_OFFSET	20
 #endif
 
 #if !defined NOT_IN_libc || defined IS_IN_libpthread
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile
new file mode 100644
index 0000000000..e03aee99fc
--- /dev/null
+++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile
@@ -0,0 +1,3 @@
+ifeq ($(subdir),linuxthreads)
+libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask
+endif
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h
new file mode 100644
index 0000000000..d74c044981
--- /dev/null
+++ b/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef ASSEMBLER
+# include <linuxthreads/internals.h>
+#endif
+
+#define MULTIPLE_THREADS_OFFSET	40
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+.text;									      \
+ENTRY (name)								      \
+     adds r14 = MULTIPLE_THREADS_OFFSET, r13;;				      \
+     ld4 r14 = [r14];							      \
+     mov r15 = SYS_ify(syscall_name);;					      \
+     cmp4.ne p6, p7 = 0, r14;						      \
+(p6) br.cond.spnt .Lpseudo_cancel;;					      \
+     break __BREAK_SYSCALL;;						      \
+     cmp.eq p6,p0=-1,r10;						      \
+(p6) br.cond.spnt.few __syscall_error;					      \
+     ret;;								      \
+.Lpseudo_cancel:							      \
+     .prologue;								      \
+     .regstk args, 5, args, 0;						      \
+     .save ar.pfs, loc0;						      \
+     alloc loc0 = ar.pfs, args, 5, args, 0;				      \
+     .save rp, loc1;							      \
+     mov loc1 = rp;;							      \
+     .body;								      \
+     CENABLE;;								      \
+     mov loc2 = r8;							      \
+     COPY_ARGS_##args							      \
+     mov r15 = SYS_ify(syscall_name);					      \
+     break __BREAK_SYSCALL;;						      \
+     mov loc3 = r8;							      \
+     mov loc4 = r10;							      \
+     mov out0 = loc2;							      \
+     CDISABLE;;								      \
+     cmp.eq p6,p0=-1,loc4;						      \
+(p6) br.cond.spnt.few __syscall_error_##args;				      \
+     mov r8 = loc3;							      \
+     mov rp = loc1;							      \
+     mov ar.pfs = loc0;							      \
+.Lpseudo_end:								      \
+     ret;								      \
+     .endp name;							      \
+.section .gnu.linkonce.t.__syscall_error_##args, "ax";			      \
+     .align 32;								      \
+     .proc __syscall_error_##args;					      \
+     .global __syscall_error_##args;					      \
+     .hidden __syscall_error_##args;					      \
+__syscall_error_##args:							      \
+     .prologue;								      \
+     .regstk args, 5, args, 0;						      \
+     .save ar.pfs, loc0;						      \
+     .save rp, loc1;							      \
+     .body;								      \
+     mov loc4 = r1;;							      \
+     br.call.sptk.many b0 = __errno_location;;				      \
+     st4 [r8] = loc3;							      \
+     mov r1 = loc4;							      \
+     mov rp = loc1;							      \
+     mov r8 = -1;							      \
+     mov ar.pfs = loc0
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	br.call.sptk.many b0 = __pthread_enable_asynccancel
+#  define CDISABLE	br.call.sptk.many b0 = __pthread_disable_asynccancel
+# else
+#  define CENABLE	br.call.sptk.many b0 = __libc_enable_asynccancel
+#  define CDISABLE	br.call.sptk.many b0 = __libc_disable_asynccancel
+# endif
+
+#define COPY_ARGS_0	/* Nothing */
+#define COPY_ARGS_1	COPY_ARGS_0 mov out0 = in0;
+#define COPY_ARGS_2	COPY_ARGS_1 mov out1 = in1;
+#define COPY_ARGS_3	COPY_ARGS_2 mov out2 = in2;
+#define COPY_ARGS_4	COPY_ARGS_3 mov out3 = in3;
+#define COPY_ARGS_5	COPY_ARGS_4 mov out4 = in4;
+#define COPY_ARGS_6	COPY_ARGS_5 mov out5 = in5;
+#define COPY_ARGS_7	COPY_ARGS_6 mov out6 = in6;
+
+# ifndef ASSEMBLER
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \
+				   p_header.data.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P \
+  adds r14 = MULTIPLE_THREADS_OFFSET, r13 ;; ld4 r14 = [r14] ;; cmp4.ne p6, p7 = 0, r14 ;;
+# endif
+
+#elif !defined ASSEMBLER
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
new file mode 100644
index 0000000000..ff03f631e3
--- /dev/null
+++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep-cancel.h
@@ -0,0 +1,99 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef ASSEMBLER
+# include <linuxthreads/internals.h>
+#endif
+
+#define MULTIPLE_THREADS_OFFSET	20
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+	.text;								      \
+ENTRY(name)								      \
+	ld [%g6 + MULTIPLE_THREADS_OFFSET], %g1;			      \
+	cmp %g1, 0;							      \
+	bne 1f;								      \
+	 mov SYS_ify(syscall_name), %g1;				      \
+	ta 0x10;							      \
+	bcs __syscall_error_handler;					      \
+	 nop;								      \
+	.subsection 2;							      \
+1:	save %sp, -96, %sp;						      \
+	CENABLE;							      \
+	 nop;								      \
+	mov %o0, %l0;							      \
+	COPY_ARGS_##args						      \
+	mov SYS_ify(syscall_name), %g1;					      \
+	ta 0x10;							      \
+	bcs __syscall_error_handler2;					      \
+	 mov %o0, %l1;							      \
+	CDISABLE;							      \
+	 mov %l0, %o0;							      \
+	jmpl %i7 + 8, %g0;						      \
+	 restore %g0, %l1, %o0;						      \
+	.previous;							      \
+	SYSCALL_ERROR_HANDLER						      \
+	SYSCALL_ERROR_HANDLER2
+
+#define SYSCALL_ERROR_HANDLER2						      \
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler2)			      \
+	.global __errno_location;					      \
+        .type   __errno_location,@function;				      \
+	call   __errno_location;					      \
+	 nop;								      \
+	st	%l1, [%o0];						      \
+	jmpl	%i7 + 8, %g0;						      \
+	 restore %g0, -1, %o0;						      \
+	.previous;
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	call __pthread_enable_asynccancel
+#  define CDISABLE	call __pthread_disable_asynccancel
+# else
+#  define CENABLE	call __libc_enable_asynccancel
+#  define CDISABLE	call __libc_disable_asynccancel
+# endif
+
+#define COPY_ARGS_0	/* Nothing */
+#define COPY_ARGS_1	COPY_ARGS_0 mov %i0, %o0;
+#define COPY_ARGS_2	COPY_ARGS_1 mov %i1, %o1;
+#define COPY_ARGS_3	COPY_ARGS_2 mov %i2, %o2;
+#define COPY_ARGS_4	COPY_ARGS_3 mov %i3, %o3;
+#define COPY_ARGS_5	COPY_ARGS_4 mov %i4, %o4;
+#define COPY_ARGS_6	COPY_ARGS_5 mov %i5, %o5;
+
+# ifndef ASSEMBLER
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \
+				   p_header.data.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P ld [%g6 + MULTIPLE_THREADS_OFFSET], %g1
+# endif
+
+#elif !defined ASSEMBLER
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
diff --git a/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
new file mode 100644
index 0000000000..8b9585d2d7
--- /dev/null
+++ b/linuxthreads/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep-cancel.h
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef ASSEMBLER
+# include <linuxthreads/internals.h>
+#endif
+
+#define MULTIPLE_THREADS_OFFSET	40
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+	.text;								      \
+ENTRY(name)								      \
+	ld [%g6 + MULTIPLE_THREADS_OFFSET], %g1;			      \
+	brz,pn %g1, 1f;							      \
+	 mov SYS_ify(syscall_name), %g1;				      \
+	ta 0x6d;							      \
+	bcs,pn %xcc, __syscall_error_handler;				      \
+	 nop;								      \
+	.subsection 2;							      \
+1:	save %sp, -192, %sp;						      \
+	CENABLE;							      \
+	 nop;								      \
+	mov %o0, %l0;							      \
+	COPY_ARGS_##args						      \
+	mov SYS_ify(syscall_name), %g1;					      \
+	ta 0x6d;							      \
+	bcs,pn %xcc, __syscall_error_handler2;				      \
+	 mov %o0, %l1;							      \
+	CDISABLE;							      \
+	 mov %l0, %o0;							      \
+	jmpl %i7 + 8, %g0;						      \
+	 restore %g0, %l1, %o0;						      \
+	.previous;							      \
+	SYSCALL_ERROR_HANDLER						      \
+	SYSCALL_ERROR_HANDLER2
+
+#define SYSCALL_ERROR_HANDLER2						      \
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler2)			      \
+	.global __errno_location;					      \
+        .type   __errno_location,@function;				      \
+	call   __errno_location;					      \
+	 nop;								      \
+	st	%l1, [%o0];						      \
+	jmpl	%i7 + 8, %g0;						      \
+	 restore %g0, -1, %o0;						      \
+	.previous;
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	call __pthread_enable_asynccancel
+#  define CDISABLE	call __pthread_disable_asynccancel
+# else
+#  define CENABLE	call __libc_enable_asynccancel
+#  define CDISABLE	call __libc_disable_asynccancel
+# endif
+
+#define COPY_ARGS_0	/* Nothing */
+#define COPY_ARGS_1	COPY_ARGS_0 mov %i0, %o0;
+#define COPY_ARGS_2	COPY_ARGS_1 mov %i1, %o1;
+#define COPY_ARGS_3	COPY_ARGS_2 mov %i2, %o2;
+#define COPY_ARGS_4	COPY_ARGS_3 mov %i3, %o3;
+#define COPY_ARGS_5	COPY_ARGS_4 mov %i4, %o4;
+#define COPY_ARGS_6	COPY_ARGS_5 mov %i5, %o5;
+
+# ifndef ASSEMBLER
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \
+				   p_header.data.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P ld [%g6 + MULTIPLE_THREADS_OFFSET], %g1
+# endif
+
+#elif !defined ASSEMBLER
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
diff --git a/linuxthreads/sysdeps/x86_64/tls.h b/linuxthreads/sysdeps/x86_64/tls.h
index a649898f3f..67e20b2ed9 100644
--- a/linuxthreads/sysdeps/x86_64/tls.h
+++ b/linuxthreads/sysdeps/x86_64/tls.h
@@ -109,6 +109,11 @@ typedef struct
     _result ? "cannot set %fs base address for thread-local storage" : 0;     \
   })
 
+/* Indicate that dynamic linker shouldn't try to initialize TLS even
+   when no PT_TLS segments are found in the program and libraries
+   it is linked against.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
+
 /* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
   ({ struct _pthread_descr_struct *__descr;				      \
diff --git a/nptl/ChangeLog b/nptl/ChangeLog
index fdfcf7c580..e9beee6d68 100644
--- a/nptl/ChangeLog
+++ b/nptl/ChangeLog
@@ -1,3 +1,29 @@
+2002-12-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* descr.h (struct pthread): Move header.data.list to the back of the
+	struct.
+	* sysdeps/i386/tls.h (tcbhead_t): Move list to the back of the struct.
+	(MULTIPLE_THREADS_OFFSET): Adjust offset.
+	(SYSINFO_OFFSEET): Likewise.
+
+2002-12-27  Jakub Jelinek  <jakub@redhat.com>
+
+	* sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h (USE_DL_SYSINFO):
+	Define.
+	(DL_SYSINFO_DEFAULT): Cast to uintptr_t to avoid warnings.
+	* sysdeps/unix/sysv/linux/i386/dl-sysdep.h (NEED_DL_SYSINFO,
+	DL_SYSINFO_DEFAULT, DL_SYSINFO_IMPLEMENTATION): Define.
+	(USE_DL_SYSINFO): Undef.
+
+2002-12-22  Jakub Jelinek  <jakub@redhat.com>
+
+	* Makefile (tests-reverse): Use $(objpfx)../libc.so instead of
+	$(common-objpfx)libc.so.
+	* tst-cancel4.c (tf_write, tf_writev): Increase buf sizes so that
+	it is bigger than pipe buffer size even on arches with bigger
+	page size.
+	(tf_usleep): Cast usleep argument to useconds_t to avoid warnings.
+
 2002-12-25  Ulrich Drepper  <drepper@redhat.com>
 
 	* sysdeps/unix/sysv/linux/i386/i486/lowlevelsem.S: Implement
diff --git a/nptl/Makefile b/nptl/Makefile
index 33b5e9adea..198f2b3a1f 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -217,8 +217,10 @@ $(addprefix $(objpfx), \
     $(tests) $(test-srcs))): $(objpfx)libpthread.so \
 			     $(objpfx)libpthread_nonshared.a
 $(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so
+# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
+# since otherwise libpthread.so comes before libc.so when linking.
 $(addprefix $(objpfx), $(tests-reverse)): \
-  $(common-objpfx)libc.so $(objpfx)libpthread.so \
+  $(objpfx)../libc.so $(objpfx)libpthread.so \
   $(objpfx)libpthread_nonshared.a
 $(addprefix $(objpfx),$(tests-static)): $(objpfx)libpthread.a
 else
diff --git a/nptl/descr.h b/nptl/descr.h
index 734d339813..883078be69 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -66,11 +66,11 @@ struct pthread
                                    the address of this thread descriptor.  */
       union dtv *dtvp;
       struct pthread *self;       /* Pointer to this structure */
-      list_t list;
       int multiple_threads;
 #ifdef NEED_DL_SYSINFO
       uintptr_t sysinfo;
 #endif
+      list_t list;
     } data;
     void *__padding[16];
   } header;
diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h
index 984094c00e..4f8ddb2d28 100644
--- a/nptl/sysdeps/i386/tls.h
+++ b/nptl/sysdeps/i386/tls.h
@@ -42,9 +42,9 @@ typedef struct
 			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
-  list_t list;
   int multiple_threads;
   uintptr_t sysinfo;
+  list_t list;
 } tcbhead_t;
 #endif
 
@@ -62,11 +62,11 @@ typedef struct
 #define STACK_ALIGN	16
 
 /* Offset of the MULTIPLE_THREADS element in tcbhead_t.  */
-#define MULTIPLE_THREADS_OFFSET 20
+#define MULTIPLE_THREADS_OFFSET 12
 
 #ifdef NEED_DL_SYSINFO
 /* Offset of the SYSINFO element in tcbhead_t.  */
-# define SYSINFO_OFFSET 24
+# define SYSINFO_OFFSET 16
 #endif
 
 
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/dl-sysdep.h b/nptl/sysdeps/unix/sysv/linux/i386/dl-sysdep.h
index 0eb5f32ac3..5e59962a48 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/dl-sysdep.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/dl-sysdep.h
@@ -1,4 +1,4 @@
-/* System-specific settings for dynamic linker code.  Generic version.
+/* System-specific settings for dynamic linker code.  IA-32 version.
    Copyright (C) 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -42,4 +42,28 @@
 
 #define RTLD_CORRECT_DYNAMIC_WEAK	1
 
+
+/* Traditionally system calls have been made using int $0x80.  A
+   second method was introduced which, if possible, will use the
+   sysenter/syscall instructions.  To signal the presence and where to
+   find the code the kernel passes an AT_SYSINFO value in the
+   auxiliary vector to the application.
+   sysenter/syscall is not useful on i386 through i586, but the dynamic
+   linker and dl code in libc.a has to be able to load i686 compiled
+   libraries.  */
+#define NEED_DL_SYSINFO	1
+#undef USE_DL_SYSINFO
+
+#if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__
+extern void _dl_sysinfo_int80 (void) attribute_hidden;
+# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80
+# define DL_SYSINFO_IMPLEMENTATION \
+  asm (".type _dl_sysinfo_int80,@function\n\t"				      \
+       ".hidden _dl_sysinfo_int80\n"					      \
+       "_dl_sysinfo_int80:\n\t"						      \
+       "int $0x80;\n\t"							      \
+       "ret;\n\t"							      \
+       ".size _dl_sysinfo_int80,.-_dl_sysinfo_int80");
+#endif
+
 #endif	/* dl-sysdep.h */
diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h b/nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h
index f0d4ac7a88..d7328fe219 100644
--- a/nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h
+++ b/nptl/sysdeps/unix/sysv/linux/i386/i686/dl-sysdep.h
@@ -1,4 +1,4 @@
-/* System-specific settings for dynamic linker code.  Generic version.
+/* System-specific settings for dynamic linker code.  IA-32 version.
    Copyright (C) 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -49,10 +49,11 @@
    find the code the kernel passes an AT_SYSINFO value in the
    auxiliary vector to the application.  */
 #define NEED_DL_SYSINFO	1
+#define USE_DL_SYSINFO	1
 
 #if defined NEED_DL_SYSINFO && !defined __ASSEMBLER__
 extern void _dl_sysinfo_int80 (void) attribute_hidden;
-# define DL_SYSINFO_DEFAULT _dl_sysinfo_int80
+# define DL_SYSINFO_DEFAULT (uintptr_t) _dl_sysinfo_int80
 # define DL_SYSINFO_IMPLEMENTATION \
   asm (".type _dl_sysinfo_int80,@function\n\t"				      \
        ".hidden _dl_sysinfo_int80\n"					      \
diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c
index 371f2f7f26..7ab7bd60da 100644
--- a/nptl/tst-cancel4.c
+++ b/nptl/tst-cancel4.c
@@ -113,7 +113,7 @@ tf_write  (void *arg)
       exit (1);
     }
 
-  char buf[10000];
+  char buf[100000];
   memset (buf, '\0', sizeof (buf));
   ssize_t s = write (fds[1], buf, sizeof (buf));
 
@@ -133,7 +133,7 @@ tf_writev  (void *arg)
       exit (1);
     }
 
-  char buf[10000];
+  char buf[100000];
   memset (buf, '\0', sizeof (buf));
   struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
   ssize_t s = writev (fds[1], iov, 1);
@@ -172,7 +172,7 @@ tf_usleep (void *arg)
       exit (1);
     }
 
-  usleep (ULONG_MAX);
+  usleep ((useconds_t) ULONG_MAX);
 
   printf ("%s: usleep returns\n", __FUNCTION__);
 
diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c
index 5b2728b8ba..b4c29dd3c8 100644
--- a/sysdeps/generic/libc-start.c
+++ b/sysdeps/generic/libc-start.c
@@ -32,7 +32,7 @@ extern void *__libc_stack_end;
 #ifndef SHARED
 # include <dl-osinfo.h>
 extern void __pthread_initialize_minimal (void)
-# if !(USE_TLS - 0)
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
      __attribute__ ((weak))
 # endif
      ;
@@ -97,7 +97,7 @@ BP_SYM (__libc_start_main) (int (*main) (int, char **, char **),
      we need to setup errno.  If there is no thread library and we
      handle TLS the function is defined in the libc to initialized the
      TLS handling.  */
-# if !(USE_TLS - 0)
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
   if (__pthread_initialize_minimal)
 # endif
     __pthread_initialize_minimal ();
diff --git a/sysdeps/generic/libc-tls.c b/sysdeps/generic/libc-tls.c
index ce1f9d5f07..1461bf8543 100644
--- a/sysdeps/generic/libc-tls.c
+++ b/sysdeps/generic/libc-tls.c
@@ -135,8 +135,13 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
 	}
 
   if (memsz == 0 && tcbsize <= TLS_INIT_TCB_SIZE)
-    /* We do not need a TLS block and no thread descriptor.  */
-    return;
+    {
+      /* We do not need a TLS block and no thread descriptor.  */
+#ifdef NONTLS_INIT_TP
+      NONTLS_INIT_TP;
+#endif
+      return;
+    }
 
 
   /* We have to set up the TCB block which also (possibly) contains
@@ -249,4 +254,16 @@ __pthread_initialize_minimal (void)
 {
   __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
 }
+
+#elif defined NONTLS_INIT_TP
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  NONTLS_INIT_TP;
+}
+
 #endif
diff --git a/sysdeps/unix/common/pause.c b/sysdeps/unix/common/pause.c
index 9a2e44e996..508a3e0b53 100644
--- a/sysdeps/unix/common/pause.c
+++ b/sysdeps/unix/common/pause.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1996, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -18,7 +18,7 @@
 
 #include <signal.h>
 #include <unistd.h>
-
+#include <sysdep-cancel.h>
 
 /* Suspend the process until a signal arrives.
    This always returns -1 and sets errno to EINTR.  */
@@ -26,6 +26,12 @@
 int
 __libc_pause (void)
 {
-  return __sigpause (__sigblock (0), 0);
+  if (SINGLE_THREAD_P)
+    return __sigpause (__sigblock (0), 0);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+  int result = __sigpause (__sigblock (0), 0);
+  LIBC_CANCEL_RESET (oldtype);
+  return result;
 }
 weak_alias (__libc_pause, pause)
diff --git a/sysdeps/unix/sysv/linux/i386/sysdep.h b/sysdeps/unix/sysv/linux/i386/sysdep.h
index 6478af7f63..25208a00a8 100644
--- a/sysdeps/unix/sysv/linux/i386/sysdep.h
+++ b/sysdeps/unix/sysv/linux/i386/sysdep.h
@@ -24,7 +24,7 @@
 #include <sysdeps/unix/i386/sysdep.h>
 #include <bp-sym.h>
 #include <bp-asm.h>
-/* Defines RTLD_PRIVATE_ERRNO and NEED_DL_SYSINFO.  */
+/* Defines RTLD_PRIVATE_ERRNO and USE_DL_SYSINFO.  */
 #include <dl-sysdep.h>
 #include <tls.h>
 
@@ -36,7 +36,8 @@
 #undef SYS_ify
 #define SYS_ify(syscall_name)	__NR_##syscall_name
 
-#if defined NEED_DL_SYSINFO && !defined IS_IN_rtld
+#if defined USE_DL_SYSINFO \
+    && (!defined NOT_IN_libc || defined IS_IN_libpthread)
 # define I386_USE_SYSENTER	1
 #else
 # undef I386_USE_SYSENTER
diff --git a/sysdeps/unix/sysv/linux/ia64/sysdep.h b/sysdeps/unix/sysv/linux/ia64/sysdep.h
index 57f7a7a40b..0a2c1bdc4b 100644
--- a/sysdeps/unix/sysv/linux/ia64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/ia64/sysdep.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Jes Sorensen, <Jes.Sorensen@cern.ch>, April 1999.
    Based on code originally written by David Mosberger-Tang
@@ -83,7 +83,7 @@
 #define	PSEUDO(name, syscall_name, args)	\
   ENTRY(name)					\
     DO_CALL (SYS_ify(syscall_name));		\
-	cmp.eq p6,p0=-1,r10;;			\
+	cmp.eq p6,p0=-1,r10;			\
 (p6)	br.cond.spnt.few __syscall_error;
 
 #define DO_CALL(num)				\
@@ -102,11 +102,98 @@
 
 #else /* not __ASSEMBLER__ */
 
-/* Define a macro which expands into the inline wrapper code for a system
-   call.  */
-#if 0
+/* On IA-64 we have stacked registers for passing arguments.  The
+   "out" registers end up being the called function's "in"
+   registers.
+
+   Also, since we have plenty of registers we have two return values
+   from a syscall.  r10 is set to -1 on error, whilst r8 contains the
+   (non-negative) errno on error or the return value on success.
+ */
 #undef INLINE_SYSCALL
-#define INLINE_SYSCALL(name, nr, args...)	__##name (args)
-#endif
+#define 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);					\
+    __asm __volatile ("break %3;;\n\t"				\
+                      : "=r" (_r8), "=r" (_r10), "=r" (_r15)	\
+                      : "i" (__BREAK_SYSCALL), "2" (_r15)	\
+			ASM_ARGS_##nr				\
+                      : "memory" ASM_CLOBBERS_##nr);		\
+    _retval = _r8;						\
+    if (_r10 == -1)						\
+      {								\
+        __set_errno (_retval);					\
+        _retval = -1;						\
+      }								\
+    _retval; })
+
+#undef INTERNAL_SYSCALL
+#define INTERNAL_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);					\
+    __asm __volatile ("break %3;;\n\t"				\
+                      : "=r" (_r8), "=r" (_r10), "=r" (_r15)	\
+                      : "i" (__BREAK_SYSCALL), "2" (_r15)	\
+			ASM_ARGS_##nr				\
+                      : "memory" ASM_CLOBBERS_##nr);		\
+    _retval = _r8;						\
+    if (_r10 == -1)						\
+      _retval = -_retval;					\
+    _retval; })
+
+#undef INTERNAL_SYSCALL_ERROR_P
+#define INTERNAL_SYSCALL_ERROR_P(val)	((unsigned long) (val) >= -4095UL)
+
+#undef INTERNAL_SYSCALL_ERRNO
+#define INTERNAL_SYSCALL_ERRNO(val)	(-(val))
+
+#define LOAD_ARGS_0()   do { } while (0)
+#define LOAD_ARGS_1(out0)				\
+  register long _out0 asm ("out0") = (long) (out0);	\
+  LOAD_ARGS_0 ()
+#define LOAD_ARGS_2(out0, out1)				\
+  register long _out1 asm ("out1") = (long) (out1);	\
+  LOAD_ARGS_1 (out0)
+#define LOAD_ARGS_3(out0, out1, out2)			\
+  register long _out2 asm ("out2") = (long) (out2);	\
+  LOAD_ARGS_2 (out0, out1)
+#define LOAD_ARGS_4(out0, out1, out2, out3)		\
+  register long _out3 asm ("out3") = (long) (out3);	\
+  LOAD_ARGS_3 (out0, out1, out2)
+#define LOAD_ARGS_5(out0, out1, out2, out3, out4)	\
+  register long _out4 asm ("out4") = (long) (out4);	\
+  LOAD_ARGS_4 (out0, out1, out2, out3)
+
+#define ASM_ARGS_0
+#define ASM_ARGS_1      ASM_ARGS_0, "r" (_out0)
+#define ASM_ARGS_2      ASM_ARGS_1, "r" (_out1)
+#define ASM_ARGS_3      ASM_ARGS_2, "r" (_out2)
+#define ASM_ARGS_4      ASM_ARGS_3, "r" (_out3)
+#define ASM_ARGS_5      ASM_ARGS_4, "r" (_out4)
+
+#define ASM_CLOBBERS_0	ASM_CLOBBERS_1, "out0"
+#define ASM_CLOBBERS_1	ASM_CLOBBERS_2, "out1"
+#define ASM_CLOBBERS_2	ASM_CLOBBERS_3, "out2"
+#define ASM_CLOBBERS_3	ASM_CLOBBERS_4, "out3"
+#define ASM_CLOBBERS_4	ASM_CLOBBERS_5, "out4"
+#define ASM_CLOBBERS_5	, "out5", "out6", "out7",			\
+  /* Non-stacked integer registers, minus r8, r10, r15.  */		\
+  "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",	\
+  "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",	\
+  "r28", "r29", "r30", "r31",						\
+  /* Predicate registers.  */						\
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",	\
+  /* Non-rotating fp registers.  */					\
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+  /* Branch registers.  */						\
+  "b6", "b7"
 
 #endif /* not __ASSEMBLER__ */
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/pipe.S b/sysdeps/unix/sysv/linux/sparc/sparc32/pipe.S
index 0136026be6..27ea9f8912 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/pipe.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/pipe.S
@@ -18,19 +18,19 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+
 	.globl __libc_pipe
 ENTRY (__libc_pipe)
         mov %o0, %o2            /* Save PIPEDES. */
 	mov SYS_ify(pipe),%g1
 	ta 0x10
-	bcc,a 2f
-	nop
-	SYSCALL_ERROR_HANDLER
-2:
+	bcs __syscall_error_handler
+	 nop
 	st %o0, [%o2]           /* PIPEDES[0] = %o0; */
         st %o1, [%o2 + 4]       /* PIPEDES[1] = %o1; */
 	retl
-	clr %o0
+	 clr %o0
+	SYSCALL_ERROR_HANDLER
 
 PSEUDO_END (__libc_pipe)
 weak_alias (__libc_pipe, __pipe)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S b/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S
index 449d537340..7bc734e38a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Miguel de Icaza <miguel@gnu.ai.mit.edu>, 1997.
 
@@ -67,13 +67,12 @@ ENTRY (__socket)
 	add %sp, 68, %o1		/* arg 2: parameter block */
 	LOADSYSCALL(socketcall)
 	t 0x10
-
-        bcs,a 1f
+        bcs __syscall_error_handler
 	 nop
 	retl
 	 nop
 
-1:	SYSCALL_ERROR_HANDLER
+	SYSCALL_ERROR_HANDLER
 
 END (__socket)
 
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S b/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
index 08378aba88..3b135c8e86 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/syscall.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1997, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -19,23 +19,17 @@
 #include <sysdep.h>
 	.text
 ENTRY (syscall)
-	or	%o0,%g0,%g1
-	or	%o1,%g0,%o0
-	or	%o2,%g0,%o1
-	or	%o3,%g0,%o2
-	or	%o4,%g0,%o3
-	or	%o5,%g0,%o4
+	mov	%o0, %g1
+	mov	%o1, %o0
+	mov	%o2, %o1
+	mov	%o3, %o2
+	mov	%o4, %o3
+	mov	%o5, %o4
 	ta	0x10
-	bcc	1f
-	nop
-	save %sp, -96, %sp
-	call __errno_location
-	nop
-	st %i0,[%o0]
-	restore
+	bcs	__syscall_error_handler
+	 nop
 	retl
-	mov -1, %o0
-1:
-	ret
+	 nop
+	SYSCALL_ERROR_HANDLER
 
 PSEUDO_END (syscall)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h b/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h
index e3573fd454..e362894e17 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h
@@ -31,11 +31,7 @@
 
 #ifdef __ASSEMBLER__
 
-#ifdef DONT_LOAD_G1
-# define LOADSYSCALL(x)
-#else
-# define LOADSYSCALL(x) mov __NR_##x, %g1
-#endif
+#define LOADSYSCALL(x) mov __NR_##x, %g1
 
 /* Linux/SPARC uses a different trap number */
 #undef PSEUDO
@@ -54,6 +50,21 @@
 
 #define LOC(name)  .L##name
 
+#ifdef LINKER_HANDLES_R_SPARC_WDISP22
+/* Unfortunately, we cannot do this yet.  Linker doesn't seem to
+   handle R_SPARC_WDISP22 against non-STB_LOCAL symbols properly .  */
+# define SYSCALL_ERROR_HANDLER_ENTRY(handler)				\
+	.section .gnu.linkonce.t.handler,"ax",@progbits;		\
+	.globl handler;							\
+	.hidden handler;						\
+	.type handler,@function;					\
+handler:
+#else
+# define SYSCALL_ERROR_HANDLER_ENTRY(handler)				\
+	.subsection 3;							\
+handler:
+#endif
+
 #if RTLD_PRIVATE_ERRNO
 # define SYSCALL_ERROR_HANDLER						\
 	.section .gnu.linkonce.t.__sparc.get_pic.l7,"ax",@progbits;	\
@@ -64,6 +75,7 @@ __sparc.get_pic.l7:							\
 	retl;								\
 	 add	%o7, %l7, %l7;						\
 	.previous;							\
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler)			\
 	save	%sp,-96,%sp;						\
 	sethi	%hi(_GLOBAL_OFFSET_TABLE_-4), %l7;			\
 	call	__sparc.get_pic.l7;					\
@@ -71,17 +83,20 @@ __sparc.get_pic.l7:							\
 	ld	[%l7 + errno], %l0;					\
 	st	%i0, [%l0];						\
 	jmpl	%i7+8, %g0;						\
-	 restore %g0, -1, %o0;
+	 restore %g0, -1, %o0;						\
+	.previous;
 #else
-# define SYSCALL_ERROR_HANDLER					\
-	.global __errno_location;				\
-        .type   __errno_location,@function;			\
-	save   %sp, -96, %sp;					\
-	call   __errno_location;				\
-	 nop;							\
-	st	%i0, [%o0];					\
-	jmpl	%i7+8, %g0;					\
-	 restore %g0, -1, %o0;
+# define SYSCALL_ERROR_HANDLER						\
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler)			\
+	.global __errno_location;					\
+        .type   __errno_location,@function;				\
+	save   %sp, -96, %sp;						\
+	call   __errno_location;					\
+	 nop;								\
+	st	%i0, [%o0];						\
+	jmpl	%i7+8, %g0;						\
+	 restore %g0, -1, %o0;						\
+	.previous;
 #endif
 
 #define PSEUDO(name, syscall_name, args)			\
@@ -89,10 +104,9 @@ __sparc.get_pic.l7:							\
 	ENTRY(name);						\
 	LOADSYSCALL(syscall_name);				\
 	ta 0x10;						\
-	bcc,a 9000f;						\
-	nop;							\
-	SYSCALL_ERROR_HANDLER;					\
-9000:;
+	bcs __syscall_error_handler;				\
+	 nop;							\
+	SYSCALL_ERROR_HANDLER
 
 #else  /* __ASSEMBLER__ */
 
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/pipe.S b/sysdeps/unix/sysv/linux/sparc/sparc64/pipe.S
index 5c800316d5..5ccedff21a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/pipe.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/pipe.S
@@ -23,14 +23,13 @@ ENTRY (__libc_pipe)
 	mov	%o0, %o2		/* Save PIPEDES. */
 	LOADSYSCALL(pipe)
 	ta	0x6d
-	bcc,pt	%xcc, 2f
+	bcs,pn	%xcc, __syscall_error_handler
 	 nop
-	SYSCALL_ERROR_HANDLER
-
-2:	st	%o0, [%o2]		/* PIPEDES[0] = %o0; */
+	st	%o0, [%o2]		/* PIPEDES[0] = %o0; */
 	st	%o1, [%o2 + 4]		/* PIPEDES[1] = %o1; */
 	retl
 	 clr	%o0
+	SYSCALL_ERROR_HANDLER
 PSEUDO_END (__libc_pipe)
 
 weak_alias (__libc_pipe, __pipe)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/socket.S b/sysdeps/unix/sysv/linux/sparc/sparc64/socket.S
index ed490fbaa3..750c1258ed 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/socket.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/socket.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Miguel de Icaza <miguel@gnu.ai.mit.edu>, 1997.
 
@@ -68,12 +68,12 @@ ENTRY (__socket)
 	LOADSYSCALL(socketcall)
 	ta	0x6d
 
-        bcs,pn	%xcc, 1f
+	bcs,pn	%xcc, __syscall_error_handler
 	 nop
 	retl
 	 nop
 
-1:	SYSCALL_ERROR_HANDLER
+	SYSCALL_ERROR_HANDLER
 
 END (__socket)
 
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S b/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
index 792a3a34da..27bd086206 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/syscall.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1997, 1999, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,11 +30,11 @@ ENTRY (syscall)
 
 	ta	0x6d
 
-	bcc,pt %xcc,1f
+	bcs,pn %xcc,__syscall_error_handler
 	 nop
-	SYSCALL_ERROR_HANDLER
-
-1:	retl
+	retl
 	 nop
 
+	SYSCALL_ERROR_HANDLER
+
 PSEUDO_END (syscall)
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h b/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h
index 10b764712b..a64da1a223 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sysdep.h
@@ -31,11 +31,7 @@
 
 #ifdef __ASSEMBLER__
 
-#ifdef DONT_LOAD_G1
-# define LOADSYSCALL(x)
-#else
-# define LOADSYSCALL(x) mov __NR_##x, %g1
-#endif
+#define LOADSYSCALL(x) mov __NR_##x, %g1
 
 /* Linux/SPARC uses a different trap number */
 #undef PSEUDO
@@ -47,6 +43,21 @@
 	C_LABEL(name);							\
 	.type name,@function;
 
+#ifdef LINKER_HANDLES_R_SPARC_WDISP22
+/* Unfortunately, we cannot do this yet.  Linker doesn't seem to
+   handle R_SPARC_WDISP22 against non-STB_LOCAL symbols properly .  */
+# define SYSCALL_ERROR_HANDLER_ENTRY(handler)				\
+	.section .gnu.linkonce.t.handler,"ax",@progbits;		\
+	.globl handler;							\
+	.hidden handler;						\
+	.type handler,@function;					\
+handler:
+#else
+# define SYSCALL_ERROR_HANDLER_ENTRY(handler)				\
+	.subsection 3;							\
+handler:
+#endif
+
 #if RTLD_PRIVATE_ERRNO
 # define SYSCALL_ERROR_HANDLER						\
 	.section .gnu.linkonce.t.__sparc64.get_pic.l7,"ax",@progbits;	\
@@ -57,6 +68,7 @@ __sparc64.get_pic.l7:							\
 	retl;								\
 	 add	%o7, %l7, %l7;						\
 	.previous;							\
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler)			\
 	save	%sp, -192, %sp;						\
 	sethi	%hi(_GLOBAL_OFFSET_TABLE_-4), %l7;			\
 	call	__sparc64.get_pic.l7;					\
@@ -64,17 +76,20 @@ __sparc64.get_pic.l7:							\
 	ldx	[%l7 + errno], %l0;					\
 	st	%i0, [%l0];						\
 	jmpl	%i7+8, %g0;						\
-	 restore %g0, -1, %o0;
+	 restore %g0, -1, %o0;						\
+	.previous;
 #else
-# define SYSCALL_ERROR_HANDLER					\
-	.global __errno_location;				\
-	.type   __errno_location,@function;			\
-	save	%sp, -192, %sp;					\
-	call	__errno_location;				\
-	 nop;							\
-	st	%i0, [%o0];					\
-	jmpl	%i7+8, %g0;					\
-	 restore %g0, -1, %o0;
+# define SYSCALL_ERROR_HANDLER						\
+SYSCALL_ERROR_HANDLER_ENTRY(__syscall_error_handler)			\
+	.global __errno_location;					\
+	.type   __errno_location,@function;				\
+	save	%sp, -192, %sp;						\
+	call	__errno_location;					\
+	 nop;								\
+	st	%i0, [%o0];						\
+	jmpl	%i7+8, %g0;						\
+	 restore %g0, -1, %o0;						\
+	.previous;
 #endif
 
 #define PSEUDO(name, syscall_name, args)				\
@@ -82,10 +97,9 @@ __sparc64.get_pic.l7:							\
 	ENTRY(name);							\
 	LOADSYSCALL(syscall_name);					\
 	ta	0x6d;							\
-	bcc,pt	%xcc, 1f;						\
+	bcs,pn	%xcc, __syscall_error_handler;				\
 	 nop;								\
-	SYSCALL_ERROR_HANDLER;						\
-1:
+	SYSCALL_ERROR_HANDLER
 
 #undef PSEUDO_END
 #define PSEUDO_END(name)						\