Merge with master.kernel.org:/pub/scm/linux/kernel/git/herbert/klibc.git
diff --git a/klibc/Makefile b/klibc/Makefile
index dff813f..bf32f7c 100644
--- a/klibc/Makefile
+++ b/klibc/Makefile
@@ -18,7 +18,7 @@
 	  atoi.o atol.o atoll.o \
 	  strtol.o strtoll.o strtoul.o strtoull.o \
 	  strtoimax.o strtoumax.o \
-	  globals.o exitc.o atexit.o onexit.o \
+	  globals.o exit.o atexit.o onexit.o \
 	  execl.o execle.o execv.o execvpe.o execvp.o execlp.o execlpe.o \
 	  fork.o wait.o wait3.o waitpid.o system.o setpgrp.o getpgrp.o \
 	  daemon.o \
diff --git a/klibc/SYSCALLS.def b/klibc/SYSCALLS.def
index b78919b..08e4477 100644
--- a/klibc/SYSCALLS.def
+++ b/klibc/SYSCALLS.def
@@ -16,7 +16,7 @@
 ;
 ; Process-related syscalls
 ;
-<!i386,x86_64> void _exit,exit::_exit(int)
+void _exit,exit::_exit(int)
 <?!ia64> pid_t clone::__clone(unsigned long, void *)
 <?ia64> pid_t clone::__clone2(unsigned long, void *, void *)
 <?!sparc> pid_t fork()
diff --git a/klibc/arch/i386/Makefile.inc b/klibc/arch/i386/Makefile.inc
index 80344bd..aa0aa37 100644
--- a/klibc/arch/i386/Makefile.inc
+++ b/klibc/arch/i386/Makefile.inc
@@ -8,7 +8,6 @@
 #
 
 ARCHOBJS = \
-	arch/$(ARCH)/exits.o \
 	arch/$(ARCH)/socketcall.o \
 	arch/$(ARCH)/setjmp.o \
 	arch/$(ARCH)/syscall.o \
diff --git a/klibc/arch/i386/exits.S b/klibc/arch/i386/exits.S
deleted file mode 100644
index ed23d98..0000000
--- a/klibc/arch/i386/exits.S
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# exit and _exit get included in *every* program, and gcc generates
-# horrible code for them.  Yes, this only saves a few bytes, but
-# it does it in every program.
-#
-
-#include <asm/unistd.h>
-
-	.data
-	.align 4
-	.globl __exit_handler
-	.type __exit_handler,@object
-__exit_handler:
-	.long _exit
-	.size __exit_handler,4
-
-	.text
-	.align 4
-	.globl exit
-	.type exit,@function
-exit:
-	jmp *(__exit_handler)
-	.size exit,.-exit
-
-	/* No need to save any registers... we're exiting! */
-	.text
-	.align 4
-	.globl _exit
-	.type _exit,@function
-_exit:
-#ifdef _REGPARM
-	movl %eax,%ebx
-#else
-	popl %ebx
-	popl %ebx
-#endif
-#if __NR_exit == 1
-	xorl %eax,%eax
-	incl %eax
-#else
-	movl $__NR_exit,%eax
-#endif
-	int $0x80
-	hlt
-	.size _exit,.-exit
diff --git a/klibc/arch/parisc/Makefile.inc b/klibc/arch/parisc/Makefile.inc
index 980a543..4fddf5f 100644
--- a/klibc/arch/parisc/Makefile.inc
+++ b/klibc/arch/parisc/Makefile.inc
@@ -14,6 +14,3 @@
 ARCHOOBJS = $(patsubst %o,%.lo,%(ARCHOBJS))
 
 archclean:
-
-arch/$(ARCH)/syscall.o: arch/$(ARCH)/syscall.c
-	$(CC) $(CFLAGS) -ffixed-r20 -c -o $@ $<
diff --git a/klibc/arch/parisc/crt0.S b/klibc/arch/parisc/crt0.S
index fb0bd37..7adc6c4 100644
--- a/klibc/arch/parisc/crt0.S
+++ b/klibc/arch/parisc/crt0.S
@@ -29,6 +29,6 @@
         bl	__libc_init,%r2
         nop
 /* break miserably if we ever return */
-        iitlbp	%r0,(%r0) /* illegal instruction */
+        iitlbp	%r0,(%sr0,%r0) /* illegal instruction */
         nop
         .procend
diff --git a/klibc/arch/parisc/syscall.S b/klibc/arch/parisc/syscall.S
new file mode 100644
index 0000000..a4f26f5
--- /dev/null
+++ b/klibc/arch/parisc/syscall.S
@@ -0,0 +1,36 @@
+/*
+ * arch/parisc/syscall.S
+ * 
+ * %r20 contains the system call number, %r2 contains whence we came
+ *
+ */
+
+	.text
+	.align 64				; cache-width aligned
+	.globl	__syscall_common
+	.type	__syscall_common,@function
+__syscall_common:
+	ldo 		0x40(%sp),%sp
+	stw 		%rp,-0x54(%sp)		; save return pointer	
+
+	ldw 		-0x74(%sp),%r22		; %arg4
+	ldw 		-0x78(%sp),%r21		; %arg5
+
+	ble		0x100(%sr2, %r0)	; jump to gateway page
+	nop					; can we move a load here?
+
+	ldi		-0x1000,%r19		; %r19 = -4096
+	sub		%r0,%ret0,%r22		; %r22 = -%ret0
+	cmpb,>>=,n	%r19,%ret0,1f		; if %ret0 >= -4096UL
+	ldi		-1,%ret0		; nullified on taken forward
+
+	/* store %r22 to errno... */
+	ldil		L%errno,%r1
+	ldo		R%errno(%r1),%r1
+	stw		%r22,0(%r1)
+1:
+	ldw 		-0x54(%sp),%rp		; restore return pointer
+	bv		%r0(%rp)		; jump back
+	ldo 		-0x40(%sp),%sp
+
+	.size __syscall_common,.-__syscall_common
diff --git a/klibc/arch/parisc/syscall.c b/klibc/arch/parisc/syscall.c
deleted file mode 100644
index 99ef5fe..0000000
--- a/klibc/arch/parisc/syscall.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * arch/parisc/syscall.c
- *
- * This function is called from a stub with %r20 already set up.
- * Compile this function with -ffixed-r20 so that it doesn't clobber
- * this register by mistake.
- */
-
-#include <klibc/compiler.h>
-#include <errno.h>
-
-long __syscall_common(long a0, long a1, long a2, long a3, long a4, long a5)
-{
-  register unsigned long rv asm ("r28");
-
-  asm volatile("\tble 0x100(%%sr2, %%r0)\n"
-	       : "=r" (rv)
-	       : "r" (a0), "r" (a1), "r" (a2), "r" (a3), "r" (a4), "r" (a5)
-	       : "%r1", "%r2", "%r29", "%r31");
-
-  if ( __unlikely(rv >= -4095UL) ) {
-    errno = -rv;
-    return -1L;
-  } else {
-    return (long)rv;
-  }
-}
-
-  
diff --git a/klibc/arch/x86_64/Makefile.inc b/klibc/arch/x86_64/Makefile.inc
index 26d880d..bfa0885 100644
--- a/klibc/arch/x86_64/Makefile.inc
+++ b/klibc/arch/x86_64/Makefile.inc
@@ -8,7 +8,6 @@
 #
 
 ARCHOBJS = \
-	arch/$(ARCH)/exits.o \
 	arch/$(ARCH)/setjmp.o \
 	arch/$(ARCH)/syscall.o \
 	arch/$(ARCH)/sigreturn.o
diff --git a/klibc/arch/x86_64/exits.S b/klibc/arch/x86_64/exits.S
deleted file mode 100644
index 618f4fb..0000000
--- a/klibc/arch/x86_64/exits.S
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# exit and _exit get included in *every* program, and gcc generates
-# horrible code for them.  Yes, this only saves a few bytes, but
-# it does it in every program.
-#
-
-#include <asm/unistd.h>
-
-	.data
-	.align 8
-	.globl __exit_handler
-	.type __exit_handler,@object
-__exit_handler:
-	.quad _exit
-	.size __exit_handler,8
-
-	.text
-	.align 8
-	.globl exit
-	.type exit,@function
-exit:
-	jmp *(__exit_handler)
-	.size exit,.-exit
-
-	/* No need to save any registers... we're exiting! */
-	.text
-	.align 4
-	.globl _exit
-	.type _exit,@function
-_exit:
-	movl $__NR_exit,%eax
-	/* The argument is already in %rdi */
-	syscall
-	.size _exit,.-exit
-
diff --git a/klibc/atexit.h b/klibc/atexit.h
index 792141d..a60d641 100644
--- a/klibc/atexit.h
+++ b/klibc/atexit.h
@@ -13,5 +13,7 @@
   struct atexit *next;
 };
 
+extern struct atexit *__atexit_list;
+
 #endif /* ATEXIT_H */
 
diff --git a/klibc/exit.c b/klibc/exit.c
new file mode 100644
index 0000000..083c736
--- /dev/null
+++ b/klibc/exit.c
@@ -0,0 +1,29 @@
+/*
+ * exit.c
+ *
+ * exit(), including the handling of the atexit chain.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include "atexit.h"
+
+/* Link chain for atexit/on_exit */
+struct atexit *__atexit_list;
+
+__noreturn exit(int rv)
+{
+  struct atexit *ap;
+
+  for ( ap = __atexit_list ; ap ; ap = ap->next ) {
+    /* This assumes extra args are harmless.  They should be in all
+       normal C ABIs, but if an architecture has some particularly
+       bizarre ABI this might be worth watching out for. */
+    ap->fctn(rv, ap->arg);
+  }
+
+  /* Handle any library destructors */
+
+  _exit(rv);
+}
diff --git a/klibc/exitc.c b/klibc/exitc.c
deleted file mode 100644
index 8819737..0000000
--- a/klibc/exitc.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * exit.c
- *
- * Implement exit()
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-/* We have an assembly version for i386 and x86-64 */
-
-#if !defined(__i386__) && !defined(__x86_64__)
-
-/* This allows atexit/on_exit to install a hook */
-__noreturn (*__exit_handler)(int) = _exit;
-
-__noreturn exit(int rv)
-{
-  __exit_handler(rv);
-}
-
-#endif
diff --git a/klibc/libc_init.c b/klibc/libc_init.c
index e91edc4..081eb44 100644
--- a/klibc/libc_init.c
+++ b/klibc/libc_init.c
@@ -17,6 +17,7 @@
 #include <stdint.h>
 #include <klibc/compiler.h>
 #include <elf.h>
+#include "atexit.h"
 
 /* This file is included from __static_init.c or __shared_init.c */
 #ifndef SHARED
@@ -31,6 +32,8 @@
   uintptr_t v;
 };
 
+static struct atexit at_exit;
+
 __noreturn __libc_init(uintptr_t *elfdata, void (*onexit)(void))
 {
   int argc;
@@ -45,6 +48,12 @@
 #endif
   unsigned int page_size = 0, page_shift = 0;
 
+  if ( onexit ) {
+    at_exit.fctn = (void(*)(int, void *))onexit;
+    /* at_exit.next = NULL already */
+    __atexit_list = &at_exit;
+  }
+
   (void)onexit;			/* For now, we ignore this... */
 
   argc = (int)*elfdata++;
diff --git a/klibc/onexit.c b/klibc/onexit.c
index 70a9c01..c6e0257 100644
--- a/klibc/onexit.c
+++ b/klibc/onexit.c
@@ -6,20 +6,6 @@
 #include <unistd.h>
 #include "atexit.h"
 
-extern __noreturn (*__exit_handler)(int);
-static struct atexit *__atexit_list;
-
-static __noreturn on_exit_exit(int rv)
-{
-  struct atexit *ap;
-  
-  for ( ap = __atexit_list ; ap ; ap = ap->next ) {
-    ap->fctn(rv, ap->arg);	/* This assumes extra args are harmless */
-  }
-  
-  _exit(rv);
-}
-
 int on_exit(void (*fctn)(int, void *), void *arg)
 {
   struct atexit *as = malloc(sizeof(struct atexit));
@@ -33,7 +19,5 @@
   as->next = __atexit_list;
   __atexit_list = as;
 
-  __exit_handler = on_exit_exit;
-
   return 0;
 }