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