summary refs log tree commit diff
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2002-11-08 02:20:41 +0000
committerRoland McGrath <roland@gnu.org>2002-11-08 02:20:41 +0000
commitc6481412ff19d5c551aba9330082a19a4a93260f (patch)
tree335acb22df9e06295318ebe74d3dc8d6dac03968
parentdfe4c900cb1d03533702c453c3a9abe6d41e545d (diff)
downloadglibc-c6481412ff19d5c551aba9330082a19a4a93260f.tar.gz
glibc-c6481412ff19d5c551aba9330082a19a4a93260f.tar.xz
glibc-c6481412ff19d5c551aba9330082a19a4a93260f.zip
* configure.in (ASM_ALPHA_NG_SYMBOL_PREFIX): Remove test.
	* configure: Regenerated.
	* config.h.in (ASM_ALPHA_NG_SYMBOL_PREFIX): Remove #undef.
	* sysdeps/alpha/dl-machine.h (TRAMPOLINE_TEMPLATE): Use !samegp.
	(RTLD_START): Likewise.  Access _dl_skip_args, _rtld_local, and
	_dl_fini via gp-relative relocations.
	* sysdeps/alpha/fpu/e_sqrt.c: Use !samegp.

	* elf/tls-macros.h: Add alpha versions.
	* sysdeps/alpha/dl-machine.h (elf_machine_rela): Handle TLS relocs.
	* sysdeps/unix/alpha/sysdep.S: Support USE___THREAD.
	* sysdeps/unix/alpha/sysdep.h: Likewise.  Add SYSCALL_ERROR_HANDLER.
	* sysdeps/unix/sysv/linux/alpha/brk.S: Use it.
	* sysdeps/unix/sysv/linux/alpha/clone.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/getitimer.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/getrusage.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/gettimeofday.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/rt_sigaction.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/select.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/setitimer.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/settimeofday.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/sigsuspend.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/syscall.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/utimes.S: Likewise.
	* sysdeps/unix/sysv/linux/alpha/wait4.S: Likewise.

	* sysdeps/unix/sysv/linux/alpha/sysdep.h: Re-include protect.
	Kill argument registers across the inline syscall.

	* sysdeps/unix/sysv/linux/alpha/clone.S: Add user_tid and tls args.

	* linuxthreads/sysdeps/alpha/tls.h: New file.
	* sysdeps/alpha/dl-tls.h: New file.
-rw-r--r--ChangeLog38
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure43
-rw-r--r--configure.in20
-rw-r--r--elf/tls-macros.h27
-rw-r--r--linuxthreads/sysdeps/alpha/tls.h111
-rw-r--r--sysdeps/alpha/dl-machine.h57
-rw-r--r--sysdeps/alpha/dl-tls.h29
-rw-r--r--sysdeps/alpha/fpu/e_sqrt.c2
-rw-r--r--sysdeps/unix/alpha/sysdep.S58
-rw-r--r--sysdeps/unix/alpha/sysdep.h100
-rw-r--r--sysdeps/unix/sysv/linux/alpha/brk.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/clone.S23
-rw-r--r--sysdeps/unix/sysv/linux/alpha/getitimer.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/getrusage.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/gettimeofday.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/rt_sigaction.S4
-rw-r--r--sysdeps/unix/sysv/linux/alpha/select.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/setitimer.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/settimeofday.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/sigsuspend.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/syscall.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/sysdep.h202
-rw-r--r--sysdeps/unix/sysv/linux/alpha/utimes.S2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/wait4.S2
27 files changed, 495 insertions, 248 deletions
diff --git a/ChangeLog b/ChangeLog
index c99038a9f0..e3cddf07a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2002-11-07  Richard Henderson  <rth@redhat.com>
+
+	* configure.in (ASM_ALPHA_NG_SYMBOL_PREFIX): Remove test.
+	* configure: Regenerated.
+	* config.h.in (ASM_ALPHA_NG_SYMBOL_PREFIX): Remove #undef.
+	* sysdeps/alpha/dl-machine.h (TRAMPOLINE_TEMPLATE): Use !samegp.
+	(RTLD_START): Likewise.  Access _dl_skip_args, _rtld_local, and
+	_dl_fini via gp-relative relocations.
+	* sysdeps/alpha/fpu/e_sqrt.c: Use !samegp.
+
+	* elf/tls-macros.h: Add alpha versions.
+	* sysdeps/alpha/dl-machine.h (elf_machine_rela): Handle TLS relocs.
+	* sysdeps/unix/alpha/sysdep.S: Support USE___THREAD.
+	* sysdeps/unix/alpha/sysdep.h: Likewise.  Add SYSCALL_ERROR_HANDLER.
+	* sysdeps/unix/sysv/linux/alpha/brk.S: Use it.
+	* sysdeps/unix/sysv/linux/alpha/clone.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/getitimer.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/getrusage.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/gettimeofday.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/rt_sigaction.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/select.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/setitimer.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/settimeofday.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/sigsuspend.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/syscall.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/utimes.S: Likewise.
+	* sysdeps/unix/sysv/linux/alpha/wait4.S: Likewise.
+
+	* sysdeps/unix/sysv/linux/alpha/sysdep.h: Re-include protect.
+	Kill argument registers across the inline syscall.
+
+	* sysdeps/unix/sysv/linux/alpha/clone.S: Add user_tid and tls args.
+
+	* linuxthreads/sysdeps/alpha/tls.h: New file.
+	* sysdeps/alpha/dl-tls.h: New file.
+
 2002-10-29  David Mosberger  <davidm@hpl.hp.com>
 
 	* sysdeps/ia64/elf/initfini.c [HAVE_INITFINI_ARRAY]
diff --git a/config.h.in b/config.h.in
index bfcac4b40e..0b0a828151 100644
--- a/config.h.in
+++ b/config.h.in
@@ -73,9 +73,6 @@
    directive.  */
 #undef	HAVE_ASM_POPSECTION_DIRECTIVE
 
-/* Define to the prefix Alpha/ELF GCC emits before ..ng symbols.  */
-#undef  ASM_ALPHA_NG_SYMBOL_PREFIX
-
 /* Define if versioning of the library is wanted.  */
 #undef	DO_VERSIONING
 
diff --git a/configure b/configure
index dc8307a46a..d149b94da9 100755
--- a/configure
+++ b/configure
@@ -5205,43 +5205,6 @@ if test $libc_cv_gcc_exceptions = yes; then
   exceptions=-fexceptions
 fi
 
-if test "$base_machine" = alpha ; then
-echo "$as_me:$LINENO: checking for function ..ng prefix" >&5
-echo $ECHO_N "checking for function ..ng prefix... $ECHO_C" >&6
-if test "${libc_cv_gcc_alpha_ng_prefix+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat > conftest.c <<\EOF
-foo () { }
-EOF
-if { ac_try='${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; };
-then
-  libc_cv_gcc_alpha_ng_prefix=yes
-else
-  libc_cv_gcc_alpha_ng_prefix=no
-fi
-rm -f conftest*
-fi
-echo "$as_me:$LINENO: result: $libc_cv_gcc_alpha_ng_prefix" >&5
-echo "${ECHO_T}$libc_cv_gcc_alpha_ng_prefix" >&6
-if test $libc_cv_gcc_alpha_ng_prefix = yes ; then
-  cat >>confdefs.h <<\_ACEOF
-#define ASM_ALPHA_NG_SYMBOL_PREFIX "$"
-_ACEOF
-
-else
-  cat >>confdefs.h <<\_ACEOF
-#define ASM_ALPHA_NG_SYMBOL_PREFIX ""
-_ACEOF
-
-fi
-fi
-
 if test "$host_cpu" = powerpc ; then
 # Check for a bug present in at least versions 2.8.x of GCC
 # and versions 1.0.x of EGCS.
@@ -5298,7 +5261,7 @@ if test "${libc_cv_gcc_dwarf2_unwind_info+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat > conftest.c <<EOF
-#line 5301 "configure"
+#line 5264 "configure"
 static char *__EH_FRAME_BEGIN__;
 _start ()
 {
@@ -5397,7 +5360,7 @@ if test "${libc_cv_gcc_builtin_expect+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat > conftest.c <<EOF
-#line 5400 "configure"
+#line 5363 "configure"
 int foo (int a)
 {
   a = __builtin_expect (a, 10);
@@ -5465,7 +5428,7 @@ if test "${libc_cv_gcc_subtract_local_labels+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat > conftest.c <<EOF
-#line 5468 "configure"
+#line 5431 "configure"
 int foo (int a)
 {
   static const int ar[] = { &&l1 - &&l1, &&l2 - &&l1 };
diff --git a/configure.in b/configure.in
index 95d7bf377d..9dc94f50e6 100644
--- a/configure.in
+++ b/configure.in
@@ -1496,26 +1496,6 @@ if test $libc_cv_gcc_exceptions = yes; then
 fi
 AC_SUBST(exceptions)dnl
 
-if test "$base_machine" = alpha ; then
-AC_CACHE_CHECK(for function ..ng prefix, libc_cv_gcc_alpha_ng_prefix, [dnl
-cat > conftest.c <<\EOF
-foo () { }
-EOF
-dnl
-if AC_TRY_COMMAND([${CC-cc} -S conftest.c -o - | fgrep "\$foo..ng" > /dev/null]);
-then
-  libc_cv_gcc_alpha_ng_prefix=yes
-else
-  libc_cv_gcc_alpha_ng_prefix=no
-fi
-rm -f conftest* ])
-if test $libc_cv_gcc_alpha_ng_prefix = yes ; then
-  AC_DEFINE(ASM_ALPHA_NG_SYMBOL_PREFIX, "$")
-else
-  AC_DEFINE(ASM_ALPHA_NG_SYMBOL_PREFIX, "")
-fi
-fi
-
 if test "$host_cpu" = powerpc ; then
 # Check for a bug present in at least versions 2.8.x of GCC
 # and versions 1.0.x of EGCS.
diff --git a/elf/tls-macros.h b/elf/tls-macros.h
index e8ed56c996..b57e4ac1d3 100644
--- a/elf/tls-macros.h
+++ b/elf/tls-macros.h
@@ -211,6 +211,33 @@
 			   "r12", "pr", "t");				      \
      __l; })
 
+#elif defined __alpha__
+
+register void *__gp __asm__("$29");
+
+# define TLS_LE(x)							\
+  ({ int *__l;								\
+     asm ("call_pal 158\n\tlda $0," #x "($0)\t\t!tprel" : "=v"(__l));	\
+     __l; })
+
+# define TLS_IE(x)							\
+  ({ char *__tp; unsigned long __o;					\
+     asm ("call_pal 158\n\tldq %1," #x "($gp)\t\t!gottprel"		\
+	  : "=v"(__tp), "=r"(__o) : "r"(__gp));				\
+     (int *)(__tp + __o); })
+
+# define TLS_LD(x)							\
+  ({ extern void *__tls_get_addr(void *); int *__l; void *__i;		\
+     asm ("lda %0," #x "($gp)\t\t!tlsldm" : "=r" (__i) : "r"(__gp));	\
+     __i = __tls_get_addr(__i);						\
+     asm ("lda %0, " #x "(%1)\t\t!dtprel" : "=r"(__l) : "r"(__i));	\
+     __l; })
+	  
+# define TLS_GD(x)							\
+  ({ extern void *__tls_get_addr(void *); void *__i;			\
+     asm ("lda %0," #x "($gp)\t\t!tlsgd" : "=r" (__i) : "r"(__gp));	\
+     (int *) __tls_get_addr(__i); })
+
 #else
 # error "No support for this architecture so far."
 #endif
diff --git a/linuxthreads/sysdeps/alpha/tls.h b/linuxthreads/sysdeps/alpha/tls.h
new file mode 100644
index 0000000000..c5cdc0a5b0
--- /dev/null
+++ b/linuxthreads/sysdeps/alpha/tls.h
@@ -0,0 +1,111 @@
+/* Definitions for thread-local data handling.  linuxthreads/Alpha 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
+{
+  dtv_t *dtv;
+
+  /* Reserved for the thread implementation.  In the case of LinuxThreads,
+     this is the thread descriptor.  */
+  void *tcb;
+} tcbhead_t;
+#endif
+
+
+#ifdef HAVE_TLS_SUPPORT
+
+/* Signal that TLS support is available.  */
+# define USE_TLS	1
+
+# ifndef __ASSEMBLER__
+/* Get system call information.  */
+#  include <sysdep.h>
+
+/* Get the thread descriptor definition.  */
+#  include <linuxthreads/descr.h>
+
+/* This is the size of the initial TCB.  */
+#  define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
+
+/* Alignment requirements for the initial TCB.  */
+#  define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+/* This is the size of the TCB.  */
+#  define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
+
+/* Alignment requirements for the TCB.  */
+#  define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+/* The DTV is allocated at the TP; the TCB is placed elsewhere.  */
+#  define TLS_DTV_AT_TP 1
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+#  define INSTALL_DTV(descr, dtvp) \
+  ((tcbhead_t *) (descr))->dtv = (dtvp) + 1
+
+/* Install new dtv for current thread.  */
+#  define INSTALL_NEW_DTV(DTV) \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv = (DTV))
+
+/* Return dtv of given thread descriptor.  */
+#  define GET_DTV(descr) \
+  (((tcbhead_t *) (descr))->dtv)
+
+/* 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(descr, secondcall)				\
+  ({								\
+    register tcbhead_t *__self = (void *)(descr);		\
+    __self->tcb = __self;					\
+    __builtin_set_thread_pointer(__self);			\
+  })
+
+/* Return the address of the dtv for the current thread.  */
+#  define THREAD_DTV() \
+  (((tcbhead_t *)__builtin_thread_pointer ())->dtv)
+
+/* Return the thread descriptor for the current thread.  */
+#undef THREAD_SELF
+#define THREAD_SELF \
+  ((pthread_descr)(((tcbhead_t *)__builtin_thread_pointer ())->tcb))
+
+#undef INIT_THREAD_SELF
+
+# endif	/* HAVE_TLS_SUPPORT */
+#endif /* __ASSEMBLER__ */
+
+#endif	/* tls.h */
diff --git a/sysdeps/alpha/dl-machine.h b/sysdeps/alpha/dl-machine.h
index 05d988274b..711bf10fdd 100644
--- a/sysdeps/alpha/dl-machine.h
+++ b/sysdeps/alpha/dl-machine.h
@@ -228,7 +228,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
 	mov	$26, $18					\n\
 	addq	$17, $17, $17					\n\
 	/* Do the fixup */					\n\
-	bsr	$26, " ASM_ALPHA_NG_SYMBOL_PREFIX #fixup_name "..ng\n\
+	bsr	$26, " #fixup_name "	!samegp			\n\
 	/* Move the destination address into position.  */	\n\
 	mov	$0, $27						\n\
 	/* Restore program registers.  */			\n\
@@ -308,7 +308,7 @@ _start:								\n\
 	.prologue 0						\n\
 	/* Pass pointer to argument block to _dl_start.  */	\n\
 	mov	$sp, $16					\n\
-	bsr	$26, "ASM_ALPHA_NG_SYMBOL_PREFIX"_dl_start..ng	\n\
+	bsr	$26, _dl_start		!samegp			\n\
 	.end _start						\n\
 	/* FALLTHRU */						\n\
 	.globl _dl_start_user					\n\
@@ -322,7 +322,7 @@ _dl_start_user:							\n\
 	stq	$30, __libc_stack_end				\n\
 	/* See if we were run as a command with the executable	\n\
 	   file name as an extra leading argument.  */		\n\
-	ldl	$1, _dl_skip_args				\n\
+	ldl	$1, _dl_skip_args($gp)	!gprel			\n\
 	bne	$1, $fixup_stack				\n\
 $fixup_stack_ret:						\n\
 	/* The special initializer gets called with the stack	\n\
@@ -332,14 +332,16 @@ $fixup_stack_ret:						\n\
 " RTLD_START_SPECIAL_INIT "					\n\
 	/* Call _dl_init(_dl_loaded, argc, argv, envp) to run	\n\
 	   initializers.  */					\n\
-	ldq	$16, _rtld_local				\n\
+	ldah	$16, _rtld_local($gp)	!gprelhigh		\n\
+	ldq	$16, _rtld_local($16)	!gprellow		\n\
 	ldq	$17, 0($sp)					\n\
 	lda	$18, 8($sp)					\n\
 	s8addq	$17, 8, $19					\n\
 	addq	$19, $18, $19					\n\
-	jsr	$26, _dl_init_internal				\n\
+	bsr	$26, _dl_init_internal	!samegp			\n\
 	/* Pass our finalizer function to the user in $0. */	\n\
-	lda	$0, _dl_fini					\n\
+	ldah	$0, _dl_fini($gp)	!gprelhigh		\n\
+	lda	$0, _dl_fini($0)	!gprellow		\n\
 	/* Jump to the user's entry point.  */			\n\
 	mov	$9, $27						\n\
 	jmp	($9)						\n\
@@ -541,10 +543,15 @@ elf_machine_rela (struct link_map *map,
       return;
   else
     {
-      Elf64_Addr loadbase, sym_value;
+      Elf64_Addr sym_value;
 
-      loadbase = RESOLVE (&sym, version, r_type);
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+      struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+      sym_value = sym ? sym_map->l_addr + sym->st_value : 0;
+#else
+      Elf64_Addr loadbase = RESOLVE (&sym, version, r_type);
       sym_value = sym ? loadbase + sym->st_value : 0;
+#endif
       sym_value += reloc->r_addend;
 
       if (r_type == R_ALPHA_GLOB_DAT)
@@ -575,6 +582,40 @@ elf_machine_rela (struct link_map *map,
 	  memcpy (reloc_addr_1, &sym_value, 8);
 	}
 #endif
+#if defined USE_TLS && (!defined RTLD_BOOTSTRAP || USE___THREAD)
+      else if (r_type == R_ALPHA_DTPMOD64)
+	{
+#ifdef RTLD_BOOTSTRAP
+	  /* During startup the dynamic linker is always index 1.  */
+	  *reloc_addr = 1;
+#else
+	  /* Get the information from the link map returned by the
+	     resolv function.  */
+	  if (sym_map != NULL)
+	    *reloc_addr = sym_map->l_tls_modid;
+#endif
+	}
+      else if (r_type == R_ALPHA_DTPREL64)
+	{
+#ifndef RTLD_BOOTSTRAP
+	  /* During relocation all TLS symbols are defined and used.
+	     Therefore the offset is already correct.  */
+	  *reloc_addr = sym_value;
+#endif
+	}
+      else if (r_type == R_ALPHA_TPREL64)
+	{
+#ifdef RTLD_BOOTSTRAP
+	  *reloc_addr = sym_value - map->l_tls_offset;
+#else
+	  if (sym_map)
+	    {
+	      *reloc_addr = sym_value - sym_map->l_tls_offset;
+	      CHECK_STATIC_TLS (map, sym_map);
+	    }
+#endif
+	}
+#endif /* USE_TLS */
       else
 	_dl_reloc_bad_type (map, r_type, 0);
     }
diff --git a/sysdeps/alpha/dl-tls.h b/sysdeps/alpha/dl-tls.h
new file mode 100644
index 0000000000..f81f95d75e
--- /dev/null
+++ b/sysdeps/alpha/dl-tls.h
@@ -0,0 +1,29 @@
+/* Thread-local storage handling in the ELF dynamic linker.  Alpha 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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+
+extern void *__tls_get_addr (tls_index *ti);
diff --git a/sysdeps/alpha/fpu/e_sqrt.c b/sysdeps/alpha/fpu/e_sqrt.c
index c6262c8f69..a371896765 100644
--- a/sysdeps/alpha/fpu/e_sqrt.c
+++ b/sysdeps/alpha/fpu/e_sqrt.c
@@ -153,7 +153,7 @@ __ieee754_sqrt:								\n\
 	.align 4							\n\
 $fixup:									\n\
 	addq	$sp, 16, $sp						\n\
-	br	"ASM_ALPHA_NG_SYMBOL_PREFIX"__full_ieee754_sqrt..ng	\n\
+	br	__full_ieee754_sqrt	!samegp				\n\
 									\n\
 	.end	__ieee754_sqrt");
 
diff --git a/sysdeps/unix/alpha/sysdep.S b/sysdeps/unix/alpha/sysdep.S
index 05c00918e6..50c84c1166 100644
--- a/sysdeps/unix/alpha/sysdep.S
+++ b/sysdeps/unix/alpha/sysdep.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1993, 1996, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1993, 1996, 1998, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Brendan Kehoe (brendan@zen.org).
 
@@ -20,24 +20,59 @@
 #include <sysdep.h>
 #include <features.h>
 
+#if defined(__ELF__) && defined(PIC)
+	/* Put this at the end of libc's text segment so that all of
+	   the direct branches from the syscalls are forward, and 
+	   thus predicted not taken.  */
+	.section .text.last, "ax", @progbits
+#else
 	.text
-	.align 2
+#endif
 
-#ifdef	_LIBC_REENTRANT
+#ifdef PIC
+	/* When building a shared library, we branch here without
+	   having loaded the GP.  Nor, since it was a direct branch,
+	   have we loaded PV with our address.  Do both.  */
+# define LOADGP		br pv, 1f; 1: ldgp gp, 0(pv)
+# define PROLOGUE	.prologue 0
+#else
+# define LOADGP		ldgp gp, 0(pv)
+# define PROLOGUE	.prologue 1
+#endif
 
+	.align 4
 	.globl __syscall_error
 	.ent __syscall_error
 __syscall_error:
-	ldgp	gp, 0(pv)
+
+#if defined(_LIBC_REENTRANT) && defined(USE___THREAD)
+
+	LOADGP
+	PROLOGUE
+	mov	v0, t0
+	call_pal PAL_rduniq
+	ldq	t1, __libc_errno(gp) !gottprel
+	addq	v0, t1, v0
+	stl	t0, 0(v0)
+	lda	v0, -1
+	ret
+
+#elif defined(_LIBC_REENTRANT)
+
+	LOADGP
 	lda	sp, -16(sp)
 	.frame	sp, 16, ra, 0
 	stq	ra, 0(sp)
 	stq	v0, 8(sp)
 	.mask	0x4000001, -16
-	.prologue 1
+	PROLOGUE
 
 	/* Find our per-thread errno address  */
+#ifdef PIC
+	bsr	ra, __errno_location	!samegp
+#else
 	jsr	ra, __errno_location
+#endif
 
 	/* Store the error value.  */
 	ldq	t0, 8(sp)
@@ -49,16 +84,15 @@ __syscall_error:
 	ldq	ra, 0(sp)
 	lda	sp, 16(sp)
 	ret
-	.end __syscall_error
-#else
 
-ENTRY(__syscall_error)
-	ldgp	gp, 0(t12)
-	.prologue 1
+#else
 
+	LOADGP
+	PROLOGUE
 	stl	v0, errno
 	lda	v0, -1
 	ret
-	END(__syscall_error)
 
-#endif /* _LIBC_REENTRANT */
+#endif
+
+	.end __syscall_error
diff --git a/sysdeps/unix/alpha/sysdep.h b/sysdeps/unix/alpha/sysdep.h
index 46b5214987..f9aba3ffa2 100644
--- a/sysdeps/unix/alpha/sysdep.h
+++ b/sysdeps/unix/alpha/sysdep.h
@@ -27,6 +27,13 @@
 # include <regdef.h>
 #endif
 
+#include <tls.h>		/* Defines USE___THREAD.  */
+
+#ifdef IS_IN_rtld
+# include <dl-sysdep.h>         /* Defines RTLD_PRIVATE_ERRNO.  */
+#endif
+
+
 #ifdef __STDC__
 #define __LABEL(x)	x##:
 #else
@@ -55,54 +62,65 @@
    label of that number between those two macros!  */
 
 #ifdef PROF
-#define PSEUDO(name, syscall_name, args)	\
-    .globl name;				\
-    .align 3;					\
-    .ent name,0;				\
+# define PSEUDO_PROLOGUE			\
+	.frame sp, 0, ra;			\
+	ldgp	gp,0(pv);			\
+	.set noat;				\
+	lda	AT,_mcount;			\
+	jsr	AT,(AT),_mcount;		\
+	.set at;				\
+	.prologue 1
+# define PSEUDO_LOADGP
+#else
+# define PSEUDO_PROLOGUE			\
+	.frame sp, 0, ra;			\
+	.prologue 0
+# define PSEUDO_LOADGP				\
+	br	gp, 2f;				\
+2:	ldgp	gp, 0(gp)
+#endif /* PROF */
+
+#if RTLD_PRIVATE_ERRNO
+# define SYSCALL_ERROR_HANDLER			\
+	stl	v0, errno(gp)	!gprel;		\
+	lda	v0, -1;				\
+	ret
+#else
+# define SYSCALL_ERROR_HANDLER \
+	jmp	$31, __syscall_error
+#endif /* RTLD_PRIVATE_ERRNO */
+
+#if defined(PIC) && !RTLD_PRIVATE_ERRNO
+# define PSEUDO(name, syscall_name, args)	\
+	.globl name;				\
+	.align 4;				\
+	.ent name,0;				\
 __LABEL(name)					\
-    .frame sp, 0, ra;				\
-    ldgp gp,0(pv);				\
-    .set noat;					\
-    lda AT,_mcount;				\
-    jsr AT,(AT),_mcount;			\
-    .set at;					\
-    .prologue 1;				\
-    ldiq	v0, SYS_ify(syscall_name);	\
-    .set noat;					\
-    call_pal	PAL_callsys;			\
-    .set at;					\
-    bne		a3, 1996f;			\
+	PSEUDO_PROLOGUE;			\
+	lda	v0, SYS_ify(syscall_name);	\
+	call_pal PAL_callsys;			\
+	bne	a3, __syscall_error !samegp;	\
 3:
+# undef PSEUDO_END
+# define PSEUDO_END(sym)  END(sym)
 #else
-#define PSEUDO(name, syscall_name, args)	\
-    .globl name;				\
-    .align 3;					\
-    .ent name,0;				\
+# define PSEUDO(name, syscall_name, args)	\
+	.globl name;				\
+	.align 4;				\
+	.ent name,0;				\
 __LABEL(name)					\
-    .frame sp, 0, ra				\
-    .prologue 0;				\
-    ldiq	v0, SYS_ify(syscall_name);	\
-    .set noat;					\
-    call_pal	PAL_callsys;			\
-    .set at;					\
-    bne		a3, 1996f;			\
+	lda	v0, SYS_ify(syscall_name);	\
+	call_pal PAL_callsys;			\
+	bne	a3, 1996f;			\
 3:
-#endif
 
-#undef PSEUDO_END
-#ifdef PROF
-#define PSEUDO_END(sym)				\
+# undef PSEUDO_END
+# define PSEUDO_END(sym)			\
 1996:						\
-    jmp		zero, __syscall_error;		\
-    END(sym)
-#else
-#define PSEUDO_END(sym)				\
-1996:						\
-    br		gp, 2f;				\
-2:  ldgp	gp, 0(gp);			\
-    jmp		zero, __syscall_error;		\
-    END(sym)
-#endif
+	PSEUDO_LOADGP;				\
+	SYSCALL_ERROR_HANDLER;			\
+	END(sym)
+#endif /* PIC && !RTLD_PRIVATE_ERRNO */
 
 #define r0	v0
 #define r1	a4
diff --git a/sysdeps/unix/sysv/linux/alpha/brk.S b/sysdeps/unix/sysv/linux/alpha/brk.S
index 3cd1ae0fbd..e01abebe0e 100644
--- a/sysdeps/unix/sysv/linux/alpha/brk.S
+++ b/sysdeps/unix/sysv/linux/alpha/brk.S
@@ -74,7 +74,7 @@ $ok:	stq	a0, __curbrk
 	/* What a horrible way to die.  */
 $err0:	ldi	v0, ENOMEM
 $err1:	addq	sp, 8, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 	END(__brk)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/clone.S b/sysdeps/unix/sysv/linux/alpha/clone.S
index f1f62146ac..42df98a9b4 100644
--- a/sysdeps/unix/sysv/linux/alpha/clone.S
+++ b/sysdeps/unix/sysv/linux/alpha/clone.S
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Richard Henderson <rth@tamu.edu>, 1996.
 
@@ -24,7 +24,9 @@
 #define _ERRNO_H	1
 #include <bits/errno.h>
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg) */
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+		       pid_t *tid, void *tls);
+ */
 
         .text
 ENTRY(__clone)
@@ -49,24 +51,29 @@ ENTRY(__clone)
 	stq	a0,0(a1)
 	stq	a3,8(a1)
 
-	/* Do the system call */
+	/* Shift the flags, tid and tls arguments into place; the
+	   child_stack argument is already correct.  */
 	mov	a2,a0
+	mov	a4,a2
+	mov	a5,a3
+
+	/* Do the system call.  */
 	ldiq	v0,__NR_clone
 	call_pal PAL_callsys
 
 	bne	a3,$error
 	beq	v0,thread_start
 
-	/* Successful return from the parent */
+	/* Successful return from the parent.  */
 	ret
 
-	/* Something bad happened -- no child created */
+	/* Something bad happened -- no child created.  */
 $error:
 #ifndef PROF
 	br	gp,1f
 1:	ldgp	gp,0(gp)
 #endif
-	jmp	zero,__syscall_error
+	SYSCALL_ERROR_HANDLER
 
 	END(__clone)
 
@@ -85,11 +92,11 @@ thread_start:
 	ldq	a0,8(sp)
 	addq	sp,16,sp
 
-	/* Call the user's function */
+	/* Call the user's function.  */
 	jsr	ra,(pv)
 	ldgp	gp,0(ra)
 
-	/* Call _exit rather than doing it inline for breakpoint purposes */
+	/* Call _exit rather than doing it inline for breakpoint purposes.  */
 	mov	v0,a0
 	jsr	ra,_exit
 
diff --git a/sysdeps/unix/sysv/linux/alpha/getitimer.S b/sysdeps/unix/sysv/linux/alpha/getitimer.S
index 03ceea10f0..543256272c 100644
--- a/sysdeps/unix/sysv/linux/alpha/getitimer.S
+++ b/sysdeps/unix/sysv/linux/alpha/getitimer.S
@@ -97,7 +97,7 @@ $do32:	ldi	v0, SYS_ify(osf_getitimer)
 	.align 3
 $error:
 	addq	sp, 16, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(GETITIMER)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/getrusage.S b/sysdeps/unix/sysv/linux/alpha/getrusage.S
index 13762a87b1..dd3eced775 100644
--- a/sysdeps/unix/sysv/linux/alpha/getrusage.S
+++ b/sysdeps/unix/sysv/linux/alpha/getrusage.S
@@ -129,7 +129,7 @@ $do32:	ldi	v0, SYS_ify(osf_getrusage)
 	.align 3
 $error:
 	addq	sp, 16, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(GETRUSAGE)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/gettimeofday.S b/sysdeps/unix/sysv/linux/alpha/gettimeofday.S
index 60d642a125..71b8c134dc 100644
--- a/sysdeps/unix/sysv/linux/alpha/gettimeofday.S
+++ b/sysdeps/unix/sysv/linux/alpha/gettimeofday.S
@@ -94,7 +94,7 @@ $do32:	ldi	v0, SYS_ify(osf_gettimeofday)
 	.align 3
 $error:
 	addq	sp, 16, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(GETTIMEOFDAY)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S b/sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S
index 650f7c0715..89e08b3dc9 100644
--- a/sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S
+++ b/sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S
@@ -53,7 +53,7 @@ $error:
 1:	ldgp	gp, 0(gp)
 #endif
 	lda	sp, 16(sp)
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 	END(__ieee_get_fp_control)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S b/sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S
index 53838fe84e..dc1bbbb962 100644
--- a/sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S
+++ b/sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S
@@ -52,7 +52,7 @@ $error:
 1:	ldgp	gp, 0(gp)
 #endif
 	lda	sp, 16(sp)
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 	END(__ieee_set_fp_control)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/rt_sigaction.S b/sysdeps/unix/sysv/linux/alpha/rt_sigaction.S
index e3d01af928..5f166a7094 100644
--- a/sysdeps/unix/sysv/linux/alpha/rt_sigaction.S
+++ b/sysdeps/unix/sysv/linux/alpha/rt_sigaction.S
@@ -56,7 +56,7 @@ ENTRY(__syscall_rt_sigaction)
 	br	gp,2f
 2:	ldgp	gp,0(gp)
 #endif
-	jmp	__syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(__syscall_rt_sigaction)
 
@@ -82,6 +82,6 @@ ENTRY(__syscall_rt_sigaction)
 	ldgp $29,0($27)
 	.prologue 1
 	ldi $0,ENOSYS
-	jmp __syscall_error
+	SYSCALL_ERROR_HANDLER
 END(__syscall_rt_sigaction)
 #endif
diff --git a/sysdeps/unix/sysv/linux/alpha/select.S b/sysdeps/unix/sysv/linux/alpha/select.S
index 57030aaa4e..d3b206df6e 100644
--- a/sysdeps/unix/sysv/linux/alpha/select.S
+++ b/sysdeps/unix/sysv/linux/alpha/select.S
@@ -112,7 +112,7 @@ $do32:
 	.align 3
 $error:
 	addq	sp, 64, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(SELECT)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/setitimer.S b/sysdeps/unix/sysv/linux/alpha/setitimer.S
index 2cc126337d..fdc3d27a8c 100644
--- a/sysdeps/unix/sysv/linux/alpha/setitimer.S
+++ b/sysdeps/unix/sysv/linux/alpha/setitimer.S
@@ -113,7 +113,7 @@ $do32:
 	.align 3
 $error:
 	addq	sp, 48, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(SETITIMER)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/settimeofday.S b/sysdeps/unix/sysv/linux/alpha/settimeofday.S
index 03e9206d48..339913ff51 100644
--- a/sysdeps/unix/sysv/linux/alpha/settimeofday.S
+++ b/sysdeps/unix/sysv/linux/alpha/settimeofday.S
@@ -94,7 +94,7 @@ $do32:
 	.align 3
 $error:
 	addq	sp, 16, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(SETTIMEOFDAY)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/sigsuspend.S b/sysdeps/unix/sysv/linux/alpha/sigsuspend.S
index d6a17851ca..955d82ecc8 100644
--- a/sysdeps/unix/sysv/linux/alpha/sigsuspend.S
+++ b/sysdeps/unix/sysv/linux/alpha/sigsuspend.S
@@ -47,7 +47,7 @@ error:
 	br	gp, 1f
 1:	ldgp	gp, 0(gp)
 #endif
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 	END(__sigsuspend)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/syscall.S b/sysdeps/unix/sysv/linux/alpha/syscall.S
index c354bb6161..10a32d5dc8 100644
--- a/sysdeps/unix/sysv/linux/alpha/syscall.S
+++ b/sysdeps/unix/sysv/linux/alpha/syscall.S
@@ -70,7 +70,7 @@ $error:
 	br	gp, 2f
 2:	ldgp	gp, 0(gp)
 #endif
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(__syscall)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/sysdep.h b/sysdeps/unix/sysv/linux/alpha/sysdep.h
index e56adca8ed..3bf25e6fd2 100644
--- a/sysdeps/unix/sysv/linux/alpha/sysdep.h
+++ b/sysdeps/unix/sysv/linux/alpha/sysdep.h
@@ -17,6 +17,9 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#ifndef _LINUX_ALPHA_SYSDEP_H
+#define _LINUX_ALPHA_SYSDEP_H 1
+
 #ifdef __ASSEMBLER__
 
 #include <asm/pal.h>
@@ -88,118 +91,114 @@
    of the hard-register variables as much as possible.  Thus we copy
    in/out as close to the asm as possible.  */
 
-#define inline_syscall0(name)			\
-{						\
-	register long _sc_0 __asm__("$0");	\
-	register long _sc_19 __asm__("$19");	\
-						\
-	_sc_0 = __NR_##name;			\
-	__asm__("callsys # %0 %1 <= %2"		\
-		: "=r"(_sc_0), "=r"(_sc_19)	\
-		: "0"(_sc_0)			\
-		: inline_syscall_clobbers);	\
-	_sc_ret = _sc_0, _sc_err = _sc_19;	\
-}
-
-#define inline_syscall1(name,arg1)		\
-{						\
-	register long _sc_0 __asm__("$0");	\
-	register long _sc_16 __asm__("$16");	\
-	register long _sc_19 __asm__("$19");	\
-						\
-	_sc_0 = __NR_##name;			\
-	_sc_16 = (long) (arg1);			\
-	__asm__("callsys # %0 %1 <= %2 %3"	\
-		: "=r"(_sc_0), "=r"(_sc_19)	\
-		: "0"(_sc_0), "r"(_sc_16)	\
-		: inline_syscall_clobbers);	\
-	_sc_ret = _sc_0, _sc_err = _sc_19;	\
-}
-
-#define inline_syscall2(name,arg1,arg2)			\
+#define inline_syscall0(name)				\
 {							\
-	register long _sc_0 __asm__("$0");		\
-	register long _sc_16 __asm__("$16");		\
-	register long _sc_17 __asm__("$17");		\
 	register long _sc_19 __asm__("$19");		\
 							\
-	_sc_0 = __NR_##name;				\
-	_sc_16 = (long) (arg1);				\
-	_sc_17 = (long) (arg2);				\
-	__asm__("callsys # %0 %1 <= %2 %3 %4"		\
-		: "=r"(_sc_0), "=r"(_sc_19)		\
-		: "0"(_sc_0), "r"(_sc_16), "r"(_sc_17)	\
-		: inline_syscall_clobbers);		\
-	_sc_ret = _sc_0, _sc_err = _sc_19;		\
+	__asm__("callsys # %0 %1 <= %2"			\
+		: "=v"(_sc_ret), "=r"(_sc_19)		\
+		: "0"(__NR_##name)			\
+		: inline_syscall_clobbers,		\
+		  "$16", "$17", "$18", "$20", "$21");	\
+	_sc_err = _sc_19;				\
 }
 
-#define inline_syscall3(name,arg1,arg2,arg3)		\
+#define inline_syscall1(name,arg1)			\
 {							\
-	register long _sc_0 __asm__("$0");		\
 	register long _sc_16 __asm__("$16");		\
-	register long _sc_17 __asm__("$17");		\
-	register long _sc_18 __asm__("$18");		\
 	register long _sc_19 __asm__("$19");		\
 							\
-	_sc_0 = __NR_##name;				\
 	_sc_16 = (long) (arg1);				\
-	_sc_17 = (long) (arg2);				\
-	_sc_18 = (long) (arg3);				\
-	__asm__("callsys # %0 %1 <= %2 %3 %4 %5"	\
-		: "=r"(_sc_0), "=r"(_sc_19)		\
-		: "0"(_sc_0), "r"(_sc_16), "r"(_sc_17),	\
-		  "r"(_sc_18)				\
-		: inline_syscall_clobbers);		\
-	_sc_ret = _sc_0, _sc_err = _sc_19;		\
+	__asm__("callsys # %0 %1 <= %2 %3"		\
+		: "=v"(_sc_ret), "=r"(_sc_19),		\
+		  "=r"(_sc_16)				\
+		: "0"(__NR_##name), "2"(_sc_16)		\
+		: inline_syscall_clobbers,		\
+		  "$17", "$18", "$20", "$21");		\
+	_sc_err = _sc_19;				\
 }
 
-#define inline_syscall4(name,arg1,arg2,arg3,arg4)	\
-{							\
-	register long _sc_0 __asm__("$0");		\
-	register long _sc_16 __asm__("$16");		\
-	register long _sc_17 __asm__("$17");		\
-	register long _sc_18 __asm__("$18");		\
-	register long _sc_19 __asm__("$19");		\
-							\
-	_sc_0 = __NR_##name;				\
-	_sc_16 = (long) (arg1);				\
-	_sc_17 = (long) (arg2);				\
-	_sc_18 = (long) (arg3);				\
-	_sc_19 = (long) (arg4);				\
-	__asm__("callsys # %0 %1 <= %2 %3 %4 %5 %6"	\
-		: "=r"(_sc_0), "=r"(_sc_19)		\
-		: "0"(_sc_0), "r"(_sc_16), "r"(_sc_17),	\
-		  "r"(_sc_18), "1"(_sc_19)		\
-		: inline_syscall_clobbers);		\
-	_sc_ret = _sc_0, _sc_err = _sc_19;		\
+#define inline_syscall2(name,arg1,arg2)				\
+{								\
+	register long _sc_16 __asm__("$16");			\
+	register long _sc_17 __asm__("$17");			\
+	register long _sc_19 __asm__("$19");			\
+								\
+	_sc_16 = (long) (arg1);					\
+	_sc_17 = (long) (arg2);					\
+	__asm__("callsys # %0 %1 <= %2 %3 %4"			\
+		: "=v"(_sc_ret), "=r"(_sc_19),			\
+		  "=r"(_sc_16), "=r"(_sc_17)			\
+		: "0"(__NR_##name), "2"(_sc_16), "3"(_sc_17)	\
+		: inline_syscall_clobbers,			\
+		  "$18", "$20", "$21");				\
+	_sc_err = _sc_19;					\
 }
 
-#define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)	\
-{							\
-	register long _sc_0 __asm__("$0");		\
-	register long _sc_16 __asm__("$16");		\
-	register long _sc_17 __asm__("$17");		\
-	register long _sc_18 __asm__("$18");		\
-	register long _sc_19 __asm__("$19");		\
-	register long _sc_20 __asm__("$20");		\
-							\
-	_sc_0 = __NR_##name;				\
-	_sc_16 = (long) (arg1);				\
-	_sc_17 = (long) (arg2);				\
-	_sc_18 = (long) (arg3);				\
-	_sc_19 = (long) (arg4);				\
-	_sc_20 = (long) (arg5);				\
-	__asm__("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7"	\
-		: "=r"(_sc_0), "=r"(_sc_19)		\
-		: "0"(_sc_0), "r"(_sc_16), "r"(_sc_17),	\
-		  "r"(_sc_18), "1"(_sc_19), "r"(_sc_20)	\
-		: inline_syscall_clobbers);		\
-	_sc_ret = _sc_0, _sc_err = _sc_19;		\
+#define inline_syscall3(name,arg1,arg2,arg3)			\
+{								\
+	register long _sc_16 __asm__("$16");			\
+	register long _sc_17 __asm__("$17");			\
+	register long _sc_18 __asm__("$18");			\
+	register long _sc_19 __asm__("$19");			\
+								\
+	_sc_16 = (long) (arg1);					\
+	_sc_17 = (long) (arg2);					\
+	_sc_18 = (long) (arg3);					\
+	__asm__("callsys # %0 %1 <= %2 %3 %4 %5"		\
+		: "=v"(_sc_ret), "=r"(_sc_19),			\
+		  "=r"(_sc_16), "=r"(_sc_17), "=r"(_sc_18)	\
+		: "0"(__NR_##name), "2"(_sc_16), "3"(_sc_17),	\
+		  "4"(_sc_18)					\
+		: inline_syscall_clobbers, "$20", "$21");	\
+	_sc_err = _sc_19;					\
+}
+
+#define inline_syscall4(name,arg1,arg2,arg3,arg4)		\
+{								\
+	register long _sc_16 __asm__("$16");			\
+	register long _sc_17 __asm__("$17");			\
+	register long _sc_18 __asm__("$18");			\
+	register long _sc_19 __asm__("$19");			\
+								\
+	_sc_16 = (long) (arg1);					\
+	_sc_17 = (long) (arg2);					\
+	_sc_18 = (long) (arg3);					\
+	_sc_19 = (long) (arg4);					\
+	__asm__("callsys # %0 %1 <= %2 %3 %4 %5 %6"		\
+		: "=v"(_sc_ret), "=r"(_sc_19),			\
+		  "=r"(_sc_16), "=r"(_sc_17), "=r"(_sc_18)	\
+		: "0"(__NR_##name), "2"(_sc_16), "3"(_sc_17),	\
+		  "4"(_sc_18), "1"(_sc_19)			\
+		: inline_syscall_clobbers, "$20", "$21");	\
+	_sc_err = _sc_19;					\
+}
+
+#define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5)		\
+{								\
+	register long _sc_16 __asm__("$16");			\
+	register long _sc_17 __asm__("$17");			\
+	register long _sc_18 __asm__("$18");			\
+	register long _sc_19 __asm__("$19");			\
+	register long _sc_20 __asm__("$20");			\
+								\
+	_sc_16 = (long) (arg1);					\
+	_sc_17 = (long) (arg2);					\
+	_sc_18 = (long) (arg3);					\
+	_sc_19 = (long) (arg4);					\
+	_sc_20 = (long) (arg5);					\
+	__asm__("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7"		\
+		: "=v"(_sc_ret), "=r"(_sc_19), 			\
+		  "=r"(_sc_16), "=r"(_sc_17), "=r"(_sc_18),	\
+		  "=r"(_sc_20)					\
+		: "0"(__NR_##name), "2"(_sc_16), "3"(_sc_17),	\
+		  "4"(_sc_18), "1"(_sc_19), "5"(_sc_20)		\
+		: inline_syscall_clobbers, "$21");		\
+	_sc_ret = _sc_0, _sc_err = _sc_19;			\
 }
 
 #define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6)	\
 {								\
-	register long _sc_0 __asm__("$0");			\
 	register long _sc_16 __asm__("$16");			\
 	register long _sc_17 __asm__("$17");			\
 	register long _sc_18 __asm__("$18");			\
@@ -207,7 +206,6 @@
 	register long _sc_20 __asm__("$20");			\
 	register long _sc_21 __asm__("$21");			\
 								\
-	_sc_0 = __NR_##name;					\
 	_sc_16 = (long) (arg1);					\
 	_sc_17 = (long) (arg2);					\
 	_sc_18 = (long) (arg3);					\
@@ -215,10 +213,14 @@
 	_sc_20 = (long) (arg5);					\
 	_sc_21 = (long) (arg6);					\
 	__asm__("callsys # %0 %1 <= %2 %3 %4 %5 %6 %7 %8"	\
-		: "=r"(_sc_0), "=r"(_sc_19)			\
-		: "0"(_sc_0), "r"(_sc_16), "r"(_sc_17),		\
-		  "r"(_sc_18), "1"(_sc_19), "r"(_sc_20),	\
-		  "r"(_sc_21)					\
+		: "=v"(_sc_ret), "=r"(_sc_19)			\
+		  "=r"(_sc_16), "=r"(_sc_17), "=r"(_sc_18),	\
+		  "=r"(_sc_20), "=r"(_sc_21)			\
+		: "0"(__NR_##name), "2"(_sc_16), "3"(_sc_17),	\
+		  "4"(_sc_18), "1"(_sc_19), "5"(_sc_20),	\
+		  "6"(_sc_21)					\
 		: inline_syscall_clobbers);			\
-	_sc_ret = _sc_0, _sc_err = _sc_19;			\
+	_sc_err = _sc_19;					\
 }
+
+#endif /* _LINUX_ALPHA_SYSDEP_H */
diff --git a/sysdeps/unix/sysv/linux/alpha/utimes.S b/sysdeps/unix/sysv/linux/alpha/utimes.S
index e9c16db39d..a939255d27 100644
--- a/sysdeps/unix/sysv/linux/alpha/utimes.S
+++ b/sysdeps/unix/sysv/linux/alpha/utimes.S
@@ -99,7 +99,7 @@ $do32:
 	.align 3
 $error:
 	addq	sp, 16, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(UTIMES)
 
diff --git a/sysdeps/unix/sysv/linux/alpha/wait4.S b/sysdeps/unix/sysv/linux/alpha/wait4.S
index b695047890..17c5a97952 100644
--- a/sysdeps/unix/sysv/linux/alpha/wait4.S
+++ b/sysdeps/unix/sysv/linux/alpha/wait4.S
@@ -132,7 +132,7 @@ $do32:	ldi	v0, SYS_ify(osf_wait4)
 	.align 3
 $error:
 	addq	sp, 32, sp
-	jmp	zero, __syscall_error
+	SYSCALL_ERROR_HANDLER
 
 END(WAIT4)