go - Go 的 Syscall() 中的第二个 `r2` 返回值是做什么用的?

标签 go system-calls

这里是 Go's undocumented Syscall function :

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

这里是 the C definition :

long syscall(long number, ...);

完全不同。所以很明显 trapnumbera1a2a3 允许三个参数。我还算出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。为什么?

最佳答案

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


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

%edx scratch register; also used to return the upper 32bits of some 64bit return types

后来它继续说:

The most significant 32 bits are returned in %edx. The least unsigned long long significant 32 bits are returned in %eax.

让我们试试这个:

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:

used to pass 3rd argument to functions; 2nd return register

但附录 A 专门处理 Linux 约定。

The interface between the C library and the Linux kernel is the same as for the user-level applications with the following differences:

Returning from the syscall, register %rax contains the result of the system-call. A value in the range between -4095 and -1 indicates an error, it is -errno.

没有提及系统调用的 RDX。


我不会为此(或一般情况下)插手,但我怀疑 Linux 没有必要使用 DX,因为 Linux 不使用从 AX 溢出的如此大的返回值。

关于go - Go 的 Syscall() 中的第二个 `r2` 返回值是做什么用的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38738534/

相关文章:

c - Linux select() 不阻塞

克隆系统调用和互斥

memory-management - Go(lang) 内存使用 : RSIZE growing and VSIZE of 139GB?

postgresql - 如何在 Postgres 表上存储 Go 的当前时间(小时-分钟-秒)?

CSS 文件以 Content-Type : text/plain 发送

c - 编写新的系统调用

c - 搞笑写SysCall错误: Prints chinese characters in . txt

google-app-engine - 超过 Golang AppEngine 内存缓存截止日期

google-app-engine - Golang Cloud SDK - gcloud app deploy 找不到导入包

c++ - C/C++ 中的 CPU 使用事件通知?