Xtensa support for uClibc [8/9]

Chris Zankel chris at zankel.net
Thu Dec 6 20:50:07 UTC 2007


Add support for Xtensa to uClibc [8/9]: Syscalls and startup file part 2.

---

diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/pread_write.c uClibc-0.9.29/libc/sysdeps/linux/xtensa/pread_write.c
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/pread_write.c	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/pread_write.c	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,193 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen at uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+/*
+ * Based in part on the files
+ *		./sysdeps/unix/sysv/linux/pwrite.c,
+ *		./sysdeps/unix/sysv/linux/pread.c,
+ *		sysdeps/posix/pread.c
+ *		sysdeps/posix/pwrite.c
+ * from GNU libc 2.2.5, but reworked considerably...
+ */
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <endian.h>
+
+extern __typeof(pread) __libc_pread;
+extern __typeof(pwrite) __libc_pwrite;
+#ifdef __UCLIBC_HAS_LFS__
+extern __typeof(pread64) __libc_pread64;
+extern __typeof(pwrite64) __libc_pwrite64;
+#endif
+
+#include <bits/kernel_types.h>
+
+#ifdef __NR_pread
+
+# define __NR___syscall_pread __NR_pread
+/* On Xtensa, 64-bit values are aligned in even/odd register pairs.  */
+static inline _syscall6(ssize_t, __syscall_pread, int, fd, void *, buf,
+		size_t, count, int, pad, off_t, offset_hi, off_t, offset_lo);
+
+ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
+{
+	return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR(offset >> 31, offset));
+}
+weak_alias(__libc_pread,pread)
+
+# ifdef __UCLIBC_HAS_LFS__
+ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)
+{
+    uint32_t low = offset & 0xffffffff;
+    uint32_t high = offset >> 32;
+	return __syscall_pread(fd, buf, count, 0, __LONG_LONG_PAIR(high, low));
+}
+weak_alias(__libc_pread64,pread64)
+# endif /* __UCLIBC_HAS_LFS__  */
+
+#endif /* __NR_pread */
+
+#ifdef __NR_pwrite
+
+# define __NR___syscall_pwrite __NR_pwrite
+/* On Xtensa, 64-bit values are aligned in even/odd register pairs.  */
+static inline _syscall6(ssize_t, __syscall_pwrite, int, fd, const void *, buf,
+		size_t, count, int, pad, off_t, offset_hi, off_t, offset_lo);
+
+ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+	return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR(offset >> 31, offset));
+}
+weak_alias(__libc_pwrite,pwrite)
+
+# ifdef __UCLIBC_HAS_LFS__
+ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)
+{
+    uint32_t low = offset & 0xffffffff;
+    uint32_t high = offset >> 32;
+	return __syscall_pwrite(fd, buf, count, 0, __LONG_LONG_PAIR(high, low));
+}
+weak_alias(__libc_pwrite64,pwrite64)
+# endif /* __UCLIBC_HAS_LFS__  */
+#endif /* __NR_pwrite */
+
+#if ! defined __NR_pread || ! defined __NR_pwrite
+libc_hidden_proto(read)
+libc_hidden_proto(write)
+libc_hidden_proto(lseek)
+
+static ssize_t __fake_pread_write(int fd, void *buf,
+		size_t count, off_t offset, int do_pwrite)
+{
+	int save_errno;
+	ssize_t result;
+	off_t old_offset;
+
+	/* Since we must not change the file pointer preserve the
+	 * value so that we can restore it later.  */
+	if ((old_offset=lseek(fd, 0, SEEK_CUR)) == (off_t) -1)
+		return -1;
+
+	/* Set to wanted position.  */
+	if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
+		return -1;
+
+	if (do_pwrite == 1) {
+		/* Write the data.  */
+		result = write(fd, buf, count);
+	} else {
+		/* Read the data.  */
+		result = read(fd, buf, count);
+	}
+
+	/* Now we have to restore the position.  If this fails we
+	 * have to return this as an error.  */
+	save_errno = errno;
+	if (lseek(fd, old_offset, SEEK_SET) == (off_t) -1)
+	{
+		if (result == -1)
+			__set_errno(save_errno);
+		return -1;
+	}
+	__set_errno(save_errno);
+	return(result);
+}
+
+# ifdef __UCLIBC_HAS_LFS__
+libc_hidden_proto(lseek64)
+
+static ssize_t __fake_pread_write64(int fd, void *buf,
+		size_t count, off64_t offset, int do_pwrite)
+{
+	int save_errno;
+	ssize_t result;
+	off64_t old_offset;
+
+	/* Since we must not change the file pointer preserve the
+	 * value so that we can restore it later.  */
+	if ((old_offset=lseek64(fd, 0, SEEK_CUR)) == (off64_t) -1)
+		return -1;
+
+	/* Set to wanted position.  */
+	if (lseek64(fd, offset, SEEK_SET) == (off64_t) -1)
+		return -1;
+
+	if (do_pwrite == 1) {
+		/* Write the data.  */
+		result = write(fd, buf, count);
+	} else {
+		/* Read the data.  */
+		result = read(fd, buf, count);
+	}
+
+	/* Now we have to restore the position. */
+	save_errno = errno;
+	if (lseek64(fd, old_offset, SEEK_SET) == (off64_t) -1) {
+		if (result == -1)
+			__set_errno (save_errno);
+		return -1;
+	}
+	__set_errno (save_errno);
+	return result;
+}
+# endif /* __UCLIBC_HAS_LFS__  */
+#endif /*  ! defined __NR_pread || ! defined __NR_pwrite */
+
+#ifndef __NR_pread
+ssize_t __libc_pread(int fd, void *buf, size_t count, off_t offset)
+{
+	return __fake_pread_write(fd, buf, count, offset, 0);
+}
+weak_alias(__libc_pread,pread)
+
+# ifdef __UCLIBC_HAS_LFS__
+ssize_t __libc_pread64(int fd, void *buf, size_t count, off64_t offset)
+{
+	return __fake_pread_write64(fd, buf, count, offset, 0);
+}
+weak_alias(__libc_pread64,pread64)
+# endif /* __UCLIBC_HAS_LFS__  */
+#endif /* ! __NR_pread */
+
+#ifndef __NR_pwrite
+ssize_t __libc_pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+	/* we won't actually be modifying the buffer,
+	 *just cast it to get rid of warnings */
+	return __fake_pread_write(fd, (void*)buf, count, offset, 1);
+}
+weak_alias(__libc_pwrite,pwrite)
+
+# ifdef __UCLIBC_HAS_LFS__
+ssize_t __libc_pwrite64(int fd, const void *buf, size_t count, off64_t offset)
+{
+	return __fake_pread_write64(fd, (void*)buf, count, offset, 1);
+}
+weak_alias(__libc_pwrite64,pwrite64)
+# endif /* __UCLIBC_HAS_LFS__  */
+#endif /* ! __NR_pwrite */
diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/setjmp.S uClibc-0.9.29/libc/sysdeps/linux/xtensa/setjmp.S
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/setjmp.S	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/setjmp.S	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,131 @@
+/* setjmp for Xtensa Processors.
+   Copyright (C) 2001, 2007 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., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* This implementation relies heavily on the Xtensa register window
+   mechanism.  Setjmp flushes all the windows except its own to the
+   stack and then copies registers from the save areas on the stack
+   into the jmp_buf structure, along with the return address of the call
+   to setjmp.  Longjmp invalidates all the windows except its own, and
+   then sets things up so that it will return to the right place,
+   using a window underflow to automatically restore the registers.
+
+   Note that it would probably be sufficient to only copy the
+   registers from setjmp's caller into jmp_buf.  However, we also copy
+   the save area located at the stack pointer of setjmp's caller.
+   This save area will typically remain intact until the longjmp call.
+   The one exception is when there is an intervening alloca in
+   setjmp's caller.  This is certainly an unusual situation and is
+   likely to cause problems in any case (the storage allocated on the
+   stack cannot be safely accessed following the longjmp).  As bad as
+   it is, on most systems this situation would not necessarily lead to
+   a catastrophic failure.  If we did not preserve the extra save area
+   on Xtensa, however, it would.  When setjmp's caller returns after a
+   longjmp, there will be a window underflow; an invalid return
+   address or stack pointer in the save area will almost certainly
+   lead to a crash.  Keeping a copy of the extra save area in the
+   jmp_buf avoids this with only a small additional cost.  If setjmp
+   and longjmp are ever time-critical, this could be removed.  */
+
+#include "sysdep.h"
+
+/* int setjmp (a2 = jmp_buf env) */
+
+ENTRY (_setjmp)
+	movi	a3, 0
+	j	1f
+END (_setjmp)
+libc_hidden_def (_setjmp)
+
+ENTRY (setjmp)
+	movi	a3, 1
+	j	1f
+END (setjmp)
+
+/* int __sigsetjmp (a2 = jmp_buf env,
+		    a3 = int savemask)  */
+
+ENTRY (__sigsetjmp)
+1:	
+	/* Flush registers.  */
+	movi	a4, __window_spill
+	callx4	a4
+
+	/* Preserve the second argument (savemask) in a15.  The selection
+ 	   of a15 is arbitrary, except it's otherwise unused.  There is no
+	   risk of triggering a window overflow since we just returned
+	   from __window_spill().  */
+	mov	a15, a3
+
+	/* Copy the register save area at (sp - 16).  */
+	addi	a5, a1, -16
+	l32i	a3, a5, 0
+	l32i	a4, a5, 4
+	s32i	a3, a2, 0
+	s32i	a4, a2, 4
+	l32i	a3, a5, 8
+	l32i	a4, a5, 12
+	s32i	a3, a2, 8
+	s32i	a4, a2, 12
+
+	/* Copy 0-8 words from the register overflow area.  */
+	extui	a3, a0, 30, 2
+	blti	a3, 2, .Lendsj
+	l32i	a7, a1, 4
+	slli	a4, a3, 4
+	sub	a5, a7, a4
+	addi	a6, a2, 16
+	addi	a7, a7, -16		// a7 = end of register overflow area
+.Lsjloop:
+	l32i	a3, a5, 0
+	l32i	a4, a5, 4
+	s32i	a3, a6, 0
+	s32i	a4, a6, 4
+	l32i	a3, a5, 8
+	l32i	a4, a5, 12
+	s32i	a3, a6, 8
+	s32i	a4, a6, 12
+	addi	a5, a5, 16
+	addi	a6, a6, 16
+	blt	a5, a7, .Lsjloop
+.Lendsj:
+
+	/* Copy the register save area at sp.  */
+	l32i	a3, a1, 0
+	l32i	a4, a1, 4
+	s32i	a3, a2, 48
+	s32i	a4, a2, 52
+	l32i	a3, a1, 8
+	l32i	a4, a1, 12
+	s32i	a3, a2, 56
+	s32i	a4, a2, 60
+
+	/* Save the return address, including the window size bits.  */
+	s32i	a0, a2, 64
+
+	/* a2 still addresses jmp_buf.  a15 contains savemask.  */
+	mov	a6, a2
+	mov	a7, a15
+	movi	a3, __sigjmp_save
+	callx4	a3
+	mov	a2, a6
+	retw
+END(__sigsetjmp)
+
+weak_extern(_setjmp)
+weak_extern(setjmp)
diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/syscall.S uClibc-0.9.29/libc/sysdeps/linux/xtensa/syscall.S
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/syscall.S	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/syscall.S	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,42 @@
+/* Copyright (C) 2005, 2007 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., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+
+/* The register layout upon entering the function is:
+
+   arguments	syscall number	arg0, arg1, arg2, arg3, arg4, arg5
+   ---------	--------------	----------------------------------
+   function	a2		a3,   a4,   a5,   a6,   a7,   (sp)
+   syscall	a2		a6,   a3,   a4,   a5,   a8,   a9
+ */
+
+ENTRY (syscall)
+	l32i	a9, a1, 16	/* load extra argument from stack */
+	mov	a8, a7
+	mov	a7, a3		/* preserve a3 in a7 */
+	mov	a3, a4
+	mov	a4, a5
+	mov	a5, a6
+	mov	a6, a7
+	syscall
+	movi    a4, -4095
+	bgeu    a2, a4, SYSCALL_ERROR_LABEL
+.Lpseudo_end:
+	retw
+PSEUDO_END (syscall)
diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/sysdep.h uClibc-0.9.29/libc/sysdeps/linux/xtensa/sysdep.h
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/sysdep.h	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/sysdep.h	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,160 @@
+/* Assembler macros for Xtensa processors.
+   Copyright (C) 2001, 2007 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., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifdef __ASSEMBLER__
+
+#define ALIGNARG(log2) 1 << log2
+#define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg
+#define ASM_SIZE_DIRECTIVE(name) .size name, . - name
+
+#ifdef __STDC__
+#define C_LABEL(name)	name :
+#else
+#define C_LABEL(name)	name/**/:
+#endif
+
+#define	ENTRY(name)							\
+  ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name);				\
+  ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function);			\
+  .align ALIGNARG(2);							\
+  LITERAL_POSITION;							\
+  C_LABEL(name)								\
+  entry sp, FRAMESIZE;							\
+  CALL_MCOUNT
+
+#undef END
+#define END(name) ASM_SIZE_DIRECTIVE(name)
+
+/* Define a macro for this directive so it can be removed in a few places.  */
+#define LITERAL_POSITION .literal_position
+
+#undef JUMPTARGET
+#ifdef PIC
+/* The "@PLT" suffix is currently a no-op for non-shared linking, but
+   it doesn't hurt to use it conditionally for PIC code in case that
+   changes someday.  */
+#define JUMPTARGET(name) name##@PLT
+#else
+#define JUMPTARGET(name) name
+#endif
+
+#define FRAMESIZE 16
+#define CALL_MCOUNT		/* Do nothing.  */
+
+
+/* Linux uses a negative return value to indicate syscall errors,
+   unlike most Unices, which use the condition codes' carry flag.
+
+   Since version 2.1 the return value of a system call might be
+   negative even if the call succeeded.  E.g., the `lseek' system call
+   might return a large offset.  Therefore we must not anymore test
+   for < 0, but test for a real error by making sure the value in a2
+   is a real error number.  Linus said he will make sure the no syscall
+   returns a value in -1 .. -4095 as a valid result so we can safely
+   test with -4095.  */
+
+/* We don't want the label for the error handler to be global when we define
+   it here.  */
+#define SYSCALL_ERROR_LABEL 0f
+
+#undef  PSEUDO
+#define	PSEUDO(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+	DO_CALL	(syscall_name, args);					      \
+	movi	a4, -4095;						      \
+	bgeu	a2, a4, SYSCALL_ERROR_LABEL;				      \
+  .Lpseudo_end:
+
+#undef	PSEUDO_END
+#define	PSEUDO_END(name)						      \
+  SYSCALL_ERROR_HANDLER							      \
+  END (name)
+
+#undef	PSEUDO_NOERRNO
+#define	PSEUDO_NOERRNO(name, syscall_name, args)			      \
+  .text;								      \
+  ENTRY (name)								      \
+	DO_CALL	(syscall_name, args)
+
+#undef	PSEUDO_END_NOERRNO
+#define	PSEUDO_END_NOERRNO(name)					      \
+  END (name)
+
+#undef	ret_NOERRNO
+#define ret_NOERRNO retw
+
+/* The function has to return the error code.  */
+#undef	PSEUDO_ERRVAL
+#define	PSEUDO_ERRVAL(name, syscall_name, args)				      \
+  .text;								      \
+  ENTRY (name)								      \
+	DO_CALL	(syscall_name, args);					      \
+	neg	a2, a2
+
+#undef	PSEUDO_END_ERRVAL
+#define	PSEUDO_END_ERRVAL(name)						      \
+  END (name)
+
+#define ret_ERRVAL retw
+
+#if RTLD_PRIVATE_ERRNO
+# define SYSCALL_ERROR_HANDLER						      \
+0:	movi	a4, rtld_errno;						      \
+	neg	a2, a2;							      \
+	s32i	a2, a4, 0;						      \
+	movi	a2, -1;							      \
+	j	.Lpseudo_end;
+
+#elif defined _LIBC_REENTRANT
+
+# if USE___THREAD
+#  ifndef NOT_IN_libc
+#   define SYSCALL_ERROR_ERRNO __libc_errno
+#  else
+#   define SYSCALL_ERROR_ERRNO errno
+#  endif
+#  define SYSCALL_ERROR_HANDLER						      \
+0:	rur	a4, THREADPTR;						      \
+	movi	a3, SYSCALL_ERROR_ERRNO at TPOFF;				      \
+	neg	a2, a2;							      \
+	add	a4, a4, a3;						      \
+	s32i	a2, a4, 0;						      \
+	movi	a2, -1;							      \
+	j	.Lpseudo_end;
+# else /* !USE___THREAD */
+#  define SYSCALL_ERROR_HANDLER						      \
+0:	neg	a2, a2;							      \
+	mov	a6, a2;							      \
+	movi	a4, __errno_location at PLT;				      \
+	callx4	a4;						              \
+	s32i	a2, a6, 0;						      \
+	movi	a2, -1;							      \
+	j	.Lpseudo_end;
+# endif /* !USE___THREAD */
+#else /* !_LIBC_REENTRANT */
+#define SYSCALL_ERROR_HANDLER						      \
+0:	movi	a4, errno;						      \
+	neg	a2, a2;							      \
+	s32i	a2, a4, 0;						      \
+	movi	a2, -1;							      \
+	j	.Lpseudo_end;
+#endif /* _LIBC_REENTRANT */
+
+#endif	/* __ASSEMBLER__ */
diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/vfork.S uClibc-0.9.29/libc/sysdeps/linux/xtensa/vfork.S
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/vfork.S	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/vfork.S	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,170 @@
+/* Copyright (C) 2005, 2007 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., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include <sys/syscall.h>
+#define _SIGNAL_H
+#include <bits/signum.h>
+
+
+/* Clone the calling process, but without copying the whole address space.
+   The calling process is suspended until the new process exits or is
+   replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
+   and the process ID of the new process to the old process.
+
+   Note that it is important that we don't create a new stack frame for the
+   caller.  */
+
+
+/* The following are defined in linux/sched.h, which unfortunately
+   is not safe for inclusion in an assembly file.  */
+#define CLONE_VM        0x00000100     /* set if VM shared between processes */
+#define CLONE_VFORK     0x00004000     /* set if the parent wants the child to
+					  wake it up on mm_release */
+
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
+
+/* pid_t vfork(void);
+   Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */
+
+ENTRY (__vfork)
+
+	movi	a6, .Ljumptable
+	extui	a2, a0, 30, 2		// call-size: call4/8/12 = 1/2/3
+	addx4	a4, a2, a6		// find return address in jumptable
+	l32i	a4, a4, 0
+	add	a4, a4, a6
+
+	slli	a2, a2, 30
+	xor	a3, a0, a2		// remove call-size from return address
+	extui	a5, a4, 30, 2		// get high bits of jump target
+	slli	a5, a5, 30
+	or	a3, a3, a5		// stuff them into the return address
+	xor	a4, a4, a5		// clear high bits of jump target
+	or	a0, a4, a2		// create temporary return address
+	retw				// "return" to .L4, .L8, or .L12
+
+	.align	4
+.Ljumptable:
+	.word	0
+	.word	.L4 - .Ljumptable
+	.word	.L8 - .Ljumptable
+	.word	.L12 - .Ljumptable
+
+	/* a7: return address */
+.L4:	mov	a12, a2
+	mov	a13, a3
+
+	SAVE_PID
+
+	/* Use syscall 'clone'.  Set new stack pointer to the same address.  */
+	movi	a2, SYS_ify (clone)
+ 	movi	a3, 0
+	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+        syscall
+
+	RESTORE_PID
+
+	movi	a5, -4096
+
+	mov	a6, a2
+	mov	a2, a12
+	mov	a3, a13
+
+	bgeu	a6, a5, 1f
+	jx	a7
+1:	call4	.Lerr			// returns to original caller
+
+
+	/* a11: return address */
+.L8:	mov	a12, a2
+	mov	a13, a3
+	mov	a14, a6
+
+	SAVE_PID
+
+	movi	a2, SYS_ify (clone)
+	movi	a3, 0
+	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+	syscall
+
+	RESTORE_PID
+
+	movi	a9, -4096
+
+	mov	a10, a2
+	mov	a2, a12
+	mov	a3, a13
+	mov	a6, a14
+
+	bgeu	a10, a9, 1f
+	jx	a11
+1:	call8	.Lerr			// returns to original caller
+
+
+	/* a15: return address */
+.L12:	mov	a12, a2
+	mov	a13, a3
+	mov	a14, a6
+
+	SAVE_PID
+
+	movi	a2, SYS_ify (clone)
+	movi	a3, 0
+	movi	a6, CLONE_VM | CLONE_VFORK | SIGCHLD
+	syscall
+
+	RESTORE_PID
+
+	mov	a3, a13
+	movi	a13, -4096
+
+	mov	a6, a14
+	mov	a14, a2
+
+	mov	a2, a12
+
+	bgeu	a14, a13, 1f
+	jx	a15
+1:	call12	.Lerr			// returns to original caller
+
+
+	.align 4
+.Lerr:	entry	a1, 16
+
+	/* Restore the return address.  */
+	extui	a4, a0, 30, 2		// get the call-size bits
+	slli	a4, a4, 30
+	slli	a3, a3, 2		// clear high bits of target address
+	srli	a3, a3, 2
+	or	a0, a3, a4		// combine them
+
+	PSEUDO_END (__vfork)
+.Lpseudo_end:
+	retw
+
+libc_hidden_def (__vfork)
+
+weak_alias (__vfork, vfork)
diff -Nurd uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/windowspill.S uClibc-0.9.29/libc/sysdeps/linux/xtensa/windowspill.S
--- uClibc-0.9.29.orig/libc/sysdeps/linux/xtensa/windowspill.S	1969-12-31 16:00:00.000000000 -0800
+++ uClibc-0.9.29/libc/sysdeps/linux/xtensa/windowspill.S	2007-12-04 11:38:00.000000000 -0800
@@ -0,0 +1,95 @@
+/* Function to force register windows to the stack.
+   Copyright (C) 2005, 2007 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., 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include <bits/xtensa-config.h>
+
+	.text
+	.align  4
+	.literal_position
+	.global __window_spill
+	.type   __window_spill, @function
+__window_spill:
+	entry	a1, 48
+        bbci.l  a0, 31, .L4		// branch if called with call4
+        bbsi.l  a0, 30, .L12		// branch if called with call12
+
+	/* Called with call8: touch register NUM_REGS-12 (4/20/52) */
+.L8:
+#if XCHAL_NUM_AREGS > 16
+	call12	1f
+	retw
+
+	.align	4
+1:	_entry	a1, 48			// touch NUM_REGS-24 (x/8/40)
+
+#if XCHAL_NUM_AREGS == 32
+	mov	a8, a0
+	retw
+#else
+	_entry	a1, 48			// touch NUM_REGS-36 (x/x/28)
+	mov	a12, a0
+	_entry	a1, 48			// touch NUM_REGS-48 (x/x/16)
+	mov	a12, a0
+	_entry	a1, 16			// touch NUM_REGS-60 (x/x/4)
+#endif
+#endif
+	mov	a4, a0
+	retw
+
+	/* Called with call4: touch register NUM_REGS-8 (8/24/56) */
+.L4:
+#if XCHAL_NUM_AREGS == 16
+	mov	a8, a0
+#else
+	call12	1f
+	retw
+
+	.align	4
+1:	_entry	a1, 48			// touch NUM_REGS-20 (x/12/44)
+	mov	a12, a0
+#if XCHAL_NUM_AREGS > 32
+	_entry	a1, 48			// touch NUM_REGS-32 (x/x/32)
+	mov	a12, a0
+	_entry	a1, 48			// touch NUM_REGS-44 (x/x/20)
+	mov	a12, a0
+	_entry	a1, 48			// touch NUM_REGS-56 (x/x/8)
+	mov	a8, a0
+#endif
+#endif
+	retw
+
+	/* Called with call12: touch register NUM_REGS-16 (x/16/48) */
+.L12:
+#if XCHAL_NUM_AREGS > 16
+	call12	1f
+	retw
+
+	.align	4
+1:	_entry	a1, 48			// touch NUM_REGS-28 (x/4/36)
+#if XCHAL_NUM_AREGS == 32
+	mov	a4, a0
+#else
+	mov	a12, a0
+	_entry	a1, 48			// touch NUM_REGS-40 (x/x/24)
+	mov	a12, a0
+	_entry	a1, 48			// touch NUM_REGS-52 (x/x/12)
+	mov	a12, a0
+#endif
+#endif
+	retw



More information about the uClibc mailing list