以下是Go's undocumented Syscall function:
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
long syscall(long number, ...);
非常不同。因此trap
number
a1
,a2
和a3
允许三个参数是相当明显的。我还得出结论:r1
是返回值,err
是errno
。但是什么是r2
?系统调用手册页未提及多个返回值。
它确实给出了实际的调用约定(仍然只有一个retval):
arch/ABI instruction syscall # retval error Notes
────────────────────────────────────────────────────────────────────
alpha callsys v0 a0 a3 [1]
arc trap0 r8 r0 -
arm/OABI swi NR - a1 - [2]
arm/EABI swi 0x0 r7 r0 -
arm64 svc #0 x8 x0 -
blackfin excpt 0x0 P0 R0 -
i386 int $0x80 eax eax -
ia64 break 0x100000 r15 r8 r10 [1]
m68k trap #0 d0 d0 -
microblaze brki r14,8 r12 r3 -
mips syscall v0 v0 a3 [1]
nios2 trap r2 r2 r7
parisc ble 0x100(%sr2, %r0) r20 r28 -
powerpc sc r0 r3 r0 [1]
s390 svc 0 r1 r2 - [3]
s390x svc 0 r1 r2 - [3]
superh trap #0x17 r3 r0 - [4]
sparc/32 t 0x10 g1 o0 psr/csr [1]
sparc/64 t 0x6d g1 o0 psr/csr [1]
tile swint1 R10 R00 R01 [1]
x86_64 syscall rax rax - [5]
x32 syscall rax rax - [5]
xtensa syscall a2 a2 -
但是在x86上,这是the implementation
#define INVOKE_SYSCALL INT $0x80
TEXT ·Syscall(SB),NOSPLIT,$0-28
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
CMPL AX, $0xfffff001
JLS ok
MOVL $-1, r1+16(FP)
MOVL $0, r2+20(FP)
NEGL AX
MOVL AX, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
ok:
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
MOVL $0, err+24(FP)
CALL runtime·exitsyscall(SB)
RET
现在,我没有很好地阅读汇编,但我很确定它会在r2中返回EDX。为什么呢?
答案 0 :(得分:5)
我认为它们具有多个返回值以保持一致性。从该表中可以看出,某些体系结构返回多个值,如果从该目录中检查一些其他程序集文件,您将看到它们将寄存器值移动到r2。
但为什么是DX?这部分仍然令人费解。分散在网络上的是i386上提到的文档,允许函数使用EAX和EDX作为返回值。例如System V Application Binary Interface Intel386 Architecture Processor Supplement:
%edx 暂记寄存器;还用来返回一些上面的32位 64位返回类型
后来继续说:
%edx中返回最重要的32位。最没有签名的 在%eax中返回长long有效32位。
我们试试这个:
uint64_t some_function() {
return 18446744073709551614LLU;
}
Clang最终制作:
pushl %ebp
movl %esp, %ebp
movl $-2, %eax
movl $-1, %edx
popl %ebp
ret
有趣的是,asm_linux_amd64.s似乎做同样的事情,给我们一个借口来看System V ABI for AMD64。这也是文件中提到的关于RDX:
用于将第三个参数传递给函数; 第二次返回登记
但附录A具体涉及Linux公约。
C库和Linux内核之间的接口是相同的 对于具有以下差异的用户级应用程序:
从系统调用返回,寄存器%rax包含结果 system-call。介于-4095和-1之间的值表示错误, 它是-errno。
系统调用没有提及RDX。
我不会为了这个(或者一般情况下)把我的手放在火中但是我怀疑对于Linux来说没有必要使用DX,因为Linux没有使用它们从AX溢出的如此大的返回值。