Hi Aurelien, Got it, thanks for the explanation.
Just curious, does the same problem exist on X86-64(64bit kernel + 32 bit userland)? If yes, should the caller of syscall() need to split each 64bit argument into two 32bit arguments? 2011/3/26 Aurelien Jarno <aurel...@aurel32.net> > On Wed, Mar 16, 2011 at 12:36:30PM +0000, Chen Jie wrote: > > Package: libc6 > > Version: 2.11.2-10 > > > > syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname), > > failed with 'Invalid argument'. > > strace shows 'syscall' didn't pass the correct parameters: > > syscall(0x10f1, 0x3, 0x11, 0, 0x20, 0, 0xffffff9c, 0x4013e0) > > ( The expected one is: syscall(0x10f1, 0x3, 0x17, 0x20, 0, -100, > 0x4013e0) ) > > So let me summarize the difference between the real and expected values: > - arg1: 0x10f1 in both cases, no problem > - arg2: 0x3 in both cases, no problem > - arg3: 0x11 in the syscall, 0x17 expected. The problem is actually the > test program which uses %d to display an hexadecimal number 0x11 = 17. > No problem on the glibc side here. > - arg4: 0 in the syscall, not expected, will explain below why. > - arg5 (syscall) / arg4 (expected): 0x20 in both cases, no problem > - arg6 (syscall) / arg5 (expected): 0 in both cases, no problem > - arg7 (syscall) / arg6 (expected) 0xffffff9c in the syscall, -100 > expected. This is actually the same value. > - arg8 (syscall) / arg7 (expected): 0x4013e0 in both cases, no problem. > > So the only non-explained problem is the 4th argument as displayed by > strace. The syscall() function takes a variable number of arguments, and > pass them to the __NR_syscall syscall (4000), which is the indirect > syscall, as shown in the code below: > > eecd0: 3c1c0009 lui gp,0x9 > eecd4: 279c5c90 addiu gp,gp,23696 > eecd8: 0399e021 addu gp,gp,t9 > eecdc: 24020fa0 li v0,4000 > eece0: 0000000c syscall > eece4: 14e0fff6 bnez a3,eecc0 <syslog+0x54> > eece8: 00200825 move at,at > eecec: 03e00008 jr ra > eecf0: 00200825 move at,at > > syscall() follows the MIPS ABI, which means a 64-bit argument has to be > 64-bit aligned. That's why the arguments are organized as below: > - a0: 0x000010f1 > - a1: 0x00000003 > - a2: 0x00000011 > - a3: not used (due to 64-bit alignement) > - sp+16: 0x00000020 > - sp+20: 0x00000000 > - sp+24: 0xffffff9c > - sp+28: 0x004013e0 > > On the kernel side, the arguments are simply shifted by one (to remove > the syscall number), without taking into account the ABI and the real > syscall called. That's why there is an additional argument to the > syscall. > > Now I don't think there is any way to fix it on the libc6 side. > syscall() doesn't know what are the type of the passed arguments, and is > following the MIPS ABI. It might be fixed on the kernel side, but it > means having a table with the type of all arguments. It doesn't seems to > be easy to do. > > That said, there is an easy workaround by passing only 32-bit values to > the syscall() function on a 32-bit machine. > > -- > Aurelien Jarno GPG: 1024D/F1BCDB73 > aurel...@aurel32.net http://www.aurel32.net >