[git commit] libc: fix MIPS N64 fork
Bernhard Reutner-Fischer
rep.dot.nop at gmail.com
Wed Jan 22 20:04:39 UTC 2014
commit: http://git.uclibc.org/uClibc/commit/?id=a7e8c6aa9b192075f17774c0bbdf6829f41ba62f
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master
fork() is broken for MIPS64 N64 ABI. You can check it with a simple
C program statically linked with qemu-mips64 user emulation.
Internally fork() is using the clone system call (at least with NPTL)
with 5 arguments. See ./libpthread/nptl/sysdeps/unix/sysv/linux/i386/fork.c.
The calling conventions for MIPS N32 and N64 allow to use up to 8 registers
for that. See http://en.wikipedia.org/wiki/Calling_convention#MIPS
This is correctly implemented in libc/sysdeps/linux/mips/bits/syscalls.h,
but not in libc/sysdeps/linux/mips/sysdep.h. fork.c uses the later one.
It seems that fork() works fine for MIPS64 N32 with just using the stack like
with the O32 case. There is a user of INLINE_SYSCALL with 7 arguments in
libc/sysdeps/linux/common/sync_file_range.c for MIPS64 N32, so I decided to
only use the macros for the MIPS64 N64 case. With this patch my uClibc based
Linux system boots up fine in qemu-system-mips64.
Signed-off-by: Waldemar Brodkorb <wbx at openadk.org>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
---
libc/sysdeps/linux/mips/sysdep.h | 63 ++++++++++++++++++++++++++++++++++++++
1 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/libc/sysdeps/linux/mips/sysdep.h b/libc/sysdeps/linux/mips/sysdep.h
index 6dba1fb..46b6c53 100644
--- a/libc/sysdeps/linux/mips/sysdep.h
+++ b/libc/sysdeps/linux/mips/sysdep.h
@@ -279,6 +279,8 @@ L(syse1):
_sys_result; \
})
+#if _MIPS_SIM == _ABIO32 || _MIPS_SIM == _ABIN32
+
/* We need to use a frame pointer for the functions in which we
adjust $sp around the syscall, or debug information and unwind
information will be $sp relative and thus wrong during the syscall. As
@@ -382,6 +384,67 @@ L(syse1):
#define __SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", \
"$14", "$15", "$24", "$25", "memory"
+#else /* N64 */
+
+#undef internal_syscall5
+#define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5) \
+({ \
+ long _sys_result; \
+ \
+ { \
+ register long __v0 __asm__("$2") ncs_init; \
+ register long __a0 __asm__("$4") = (long) arg1; \
+ register long __a1 __asm__("$5") = (long) arg2; \
+ register long __a2 __asm__("$6") = (long) arg3; \
+ register long __a3 __asm__("$7") = (long) arg4; \
+ register long __a4 __asm__("$8") = (long) arg5; \
+ __asm__ __volatile__ ( \
+ ".set\tnoreorder\n\t" \
+ cs_init \
+ "syscall\n\t" \
+ ".set\treorder" \
+ : "=r" (__v0), "+r" (__a3) \
+ : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4) \
+ : __SYSCALL_CLOBBERS); \
+ err = __a3; \
+ _sys_result = __v0; \
+ } \
+ _sys_result; \
+})
+
+#undef internal_syscall6
+#define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6) \
+({ \
+ long _sys_result; \
+ \
+ { \
+ register long __v0 __asm__("$2") ncs_init; \
+ register long __a0 __asm__("$4") = (long) arg1; \
+ register long __a1 __asm__("$5") = (long) arg2; \
+ register long __a2 __asm__("$6") = (long) arg3; \
+ register long __a3 __asm__("$7") = (long) arg4; \
+ register long __a4 __asm__("$8") = (long) arg5; \
+ register long __a5 __asm__("$9") = (long) arg6; \
+ __asm__ __volatile__ ( \
+ ".set\tnoreorder\n\t" \
+ cs_init \
+ "syscall\n\t" \
+ ".set\treorder" \
+ : "=r" (__v0), "+r" (__a3) \
+ : input, "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a4), \
+ "r" (__a5) \
+ : __SYSCALL_CLOBBERS); \
+ err = __a3; \
+ _sys_result = __v0; \
+ } \
+ _sys_result; \
+})
+
+#define __SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", "$13", \
+ "$14", "$15", "$24", "$25", "hi", "lo", "memory"
+
+#endif
+
/* Pointer mangling is not yet supported for MIPS. */
#define PTR_MANGLE(var) (void) (var)
#define PTR_DEMANGLE(var) (void) (var)
More information about the uClibc-cvs
mailing list