Message ID | 20131221121829.GA14600@waldemar-brodkorb.de |
---|---|
State | Accepted |
Commit | a7e8c6aa9b192075f17774c0bbdf6829f41ba62f |
Headers | show |
Hi, any news/comment about this? thx Waldemar Waldemar Brodkorb wrote, > 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@openadk.org> > --- > libc/sysdeps/linux/mips/sysdep.h | 63 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 63 insertions(+) > > 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) > -- > 1.7.10.4 > > _______________________________________________ > uClibc mailing list > uClibc@uclibc.org > http://lists.busybox.net/mailman/listinfo/uclibc >
On 20 January 2014 09:37, Waldemar Brodkorb <wbx@openadk.org> wrote: > Hi, > > any news/comment about this? > > thx > Waldemar > > Waldemar Brodkorb wrote, > >> 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. The mips sysdeps looks highly repetitive, it would be nice to massage it to use something like the i386 variant. Maybe you want to do that? I am applying the below for now though, thanks! cheers, >> >> Signed-off-by: Waldemar Brodkorb <wbx@openadk.org> >> --- >> libc/sysdeps/linux/mips/sysdep.h | 63 ++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 63 insertions(+) >> >> 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) >> -- >> 1.7.10.4 >> >> _______________________________________________ >> uClibc mailing list >> uClibc@uclibc.org >> http://lists.busybox.net/mailman/listinfo/uclibc >> > _______________________________________________ > uClibc mailing list > uClibc@uclibc.org > http://lists.busybox.net/mailman/listinfo/uclibc
On Sat, Dec 21, 2013 at 01:18:29PM +0100, Waldemar Brodkorb wrote: > +#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" \ I seem to recall MIPS assembler having push/pop directives for settings like this. Wouldn't it be better to use them to restore the old setting of reorder rather than forcing it on after asm, so as not to assume the compiler had, and wants, reorder on? Rich
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)
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@openadk.org> --- libc/sysdeps/linux/mips/sysdep.h | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)