2016-08-03 274 views
3

这里是Go's undocumented Syscall functionGo的Syscall()中的第二个`r2`返回值是什么?

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) 

这里是the C definition

long syscall(long number, ...); 

相当不同。所以很明显trapnumber,a1,a2a3允许三个参数。我还研究出r1是返回值,而errerrno。但是什么是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。为什么?

回答

4

我认为他们有多个返回值的一致性。正如您从该表中可以看到的那样,一些体系结构会返回多个值,如果您检查该目录中的其他一些汇编文件,则会看到它们将寄存器值移至r2。


但为什么DX?这部分仍然令人费解。在网络上散布的文档是在i386上提到的,允许函数使用EAX和EDX作为返回值。例如System V Application Binary Interface Intel386 Architecture Processor Supplement

%EDX暂存寄存器;还用于返回一些 64位的返回类型

的上32位后来又接着说:

最显著32位在%edx中返回。在%eax中返回最小的无符号长度,重要的32位长度为 。

让我们试试这个:

uint64_t some_function() { 
    return 18446744073709551614LLU; 
} 

锵最终产生:

pushl %ebp 
movl %esp, %ebp 
movl $-2, %eax 
movl $-1, %edx 
popl %ebp 
ret 

有趣的是,asm_linux_amd64.s似乎做同样的事情,给我们一个借口来看看System V ABI for AMD64。这也是doc在提及RDX时提到的:

用来传递第三个参数给函数; 第二个返回寄存器

但附录A具体涉及Linux约定。

C库和Linux内核之间的接口是相同的 作为具有下列不同的用户级应用程序:

从系统调用返回,寄存器%RAX包含的结果 系统调用。 -4095到-1之间的值表示错误, 它是-errno。

没有提及系统调用的RDX。


我不会把我的手在火为此(或一般),但我怀疑服用DX没有必要对Linux不使用他们洒出了这样大的返回值斧头。

相关问题