commit 2952c70804b48bb5c87eea21df5e401969dc4ec1 Author: Kevin Cernekee Date: Tue Jun 5 15:05:20 2012 -0700 MIPS: Use $a0 instead of $v0 for __syscall_error() argument $a0 is saved across _dl_runtime_resolve(); $v0 is not. Unfortunately, __syscall_error() uses $v0 for its argument, not $a0 as is the MIPS ABI standard. This means that if lazy binding was used for __syscall_error(), the errno value in $v0 could get corrupted. The problem can be easily seen in testcases where syscalls in librt fail; when librt tries to call __syscall_error() in libc, the argument gets lost and errno gets set to a bogus value: # ./tst-mqueue1 ; echo $? mq_receive on O_WRONLY mqd_t did not fail with EBADF: Unknown error 2004684208 1 # ./tst-mqueue2 ; echo $? mq_timedreceive with too small msg_len did not fail with EMSGSIZE: Unknown error 1997360560 1 # ./tst-mqueue4 ; echo $? mq_timedsend did not fail with ETIMEDOUT: Unknown error 2008747440 1 When _dl_runtime_resolve() was taken out of the equation, the same test cases passed: # LD_BIND_NOW=y ./tst-mqueue1 ; echo $? 0 # LD_BIND_NOW=y ./tst-mqueue2 ; echo $? 0 # LD_BIND_NOW=y ./tst-mqueue4 ; echo $? 0 Changing __syscall_error() to look at $a0 instead of $v0 fixed the problem. (Note that there is also a "__syscall_error.c" file which presumably uses the standard C calling conventions, but I do not think it is used on MIPS.) Signed-off-by: Kevin Cernekee Signed-off-by: Bernhard Reutner-Fischer commit 3c58d95d918c7e2fda374c37a52f81b34b81e4ca Author: Kevin Cernekee Date: Tue Jun 5 15:05:19 2012 -0700 MIPS: Convert __syscall_error() callers to use $a0 for argument Some callers passed the first argument in $v0, while others used $a0. Change the callers to use $a0 consistently. Signed-off-by: Kevin Cernekee Signed-off-by: Bernhard Reutner-Fischer --- a/libc/sysdeps/linux/mips/vfork.S +++ b/libc/sysdeps/linux/mips/vfork.S @@ -84,6 +84,7 @@ NESTED(__vfork,FRAMESZ,sp) /* Something bad happened -- no child created. */ L(error): + move a0, v0 #ifdef __PIC__ PTR_LA t9, __syscall_error RESTORE_GP64 --- a/libpthread/linuxthreads/sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h +++ b/libpthread/linuxthreads/sysdeps/unix/sysv/linux/mips/mips64/sysdep-cancel.h @@ -31,7 +31,7 @@ # undef PSEUDO # define PSEUDO(name, syscall_name, args) \ .align 2; \ - 99: \ + 99: move a0, v0; \ PTR_LA t9,__syscall_error; \ /* manual cpreturn. */ \ REG_L gp, STKOFF_GP(sp); \ --- a/libpthread/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S +++ b/libpthread/linuxthreads/sysdeps/unix/sysv/linux/mips/vfork.S @@ -80,6 +80,7 @@ NESTED(__vfork,FRAMESZ,sp) /* Something bad happened -- no child created. */ L(error): + move a0, v0 #ifdef __PIC__ PTR_LA t9, __syscall_error RESTORE_GP64 --- a/libc/sysdeps/linux/mips/syscall_error.S +++ b/libc/sysdeps/linux/mips/syscall_error.S @@ -43,7 +43,7 @@ ENTRY(__syscall_error) #ifdef __PIC__ SAVE_GP(GPOFF) #endif - REG_S v0, V0OFF(sp) + REG_S a0, V0OFF(sp) REG_S ra, RAOFF(sp) /* Find our per-thread errno address */