dpl3350 2016-08-03 08:38
浏览 144
已采纳

Go的Syscall()中的第二个r2返回值是什么?

Here is Go's undocumented Syscall function:

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

And here is the C definition:

long syscall(long number, ...);

Pretty different. So it's fairly obvious that trap is number, and a1, a2, and a3 allow for three arguments. I also worked out that r1 is the return value, and err is errno. But what is r2? The syscall man page doesn't mention multiple return values.

It does give the actual calling conventions (still only one 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      -

But on x86 this is 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

Now, I don't read assembly too well, but I'm pretty sure it is returning EDX in r2. Why?

  • 写回答

1条回答 默认 最新

  • dongmai6666 2016-08-03 12:10
    关注

    I think they have multiple return values for consistency. As you can see from that table, some architectures return multiple values and if you check a few of the other assembly files from that directory you'll see they move register values to r2.


    But why DX? This part is still puzzling. Scattered across the web are docs mentioning on i386 a function is allowed to use both EAX and EDX for return values. For example System V Application Binary Interface Intel386 Architecture Processor Supplement:

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

    Later it goes on to say:

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

    Let's try this:

    uint64_t some_function() {
      return 18446744073709551614LLU;
    }
    

    Clang ends up producing:

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

    Interestingly, asm_linux_amd64.s seems to do the same thing, giving us a pretext to look at the System V ABI for AMD64. This also doc mentions in passing, about RDX:

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

    But Appendix A deals with Linux Conventions specifically.

    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.

    No mention of RDX for the system call.


    I won't put my hand in the fire for this (or in general) but I suspect taking DX is not necessary for Linux which doesn't make use of such large return values that they spill out of AX.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)