通过汇编看golang函数的多返回值问题

2020-06-22 12:27:20于海丽

使用 go tool compile -N -l -S main.go 得到汇编代码

"".main STEXT nosplit size=2 args=0x0 locals=0x0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:3)  TEXT "".main(SB), NOSPLIT|ABIInternal, $0-0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:3)  FUNCDATA  $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:3)  FUNCDATA  $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:3)  FUNCDATA  $3, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:4)  PCDATA $2, $0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:4)  PCDATA $0, $0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:4)  XCHGL AX, AX
  0x0001 00001 (<unknown line number>) RET
  0x0000 90 c3           ..
"".one STEXT nosplit size=20 args=0x18 locals=0x0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:7)  TEXT "".one(SB), NOSPLIT|ABIInternal, $0-24
  0x0000 00000 (C:UsersbruceDesktopgomain.go:7)  FUNCDATA  $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:7)  FUNCDATA  $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:7)  FUNCDATA  $3, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
  0x0000 00000 (C:UsersbruceDesktopgomain.go:8)  PCDATA $2, $0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:8)  PCDATA $0, $0
  0x0000 00000 (C:UsersbruceDesktopgomain.go:8)  MOVQ "".a+8(SP), AX
  0x0005 00005 (C:UsersbruceDesktopgomain.go:8)  MOVQ AX, "".~r1+16(SP)
  0x000a 00010 (C:UsersbruceDesktopgomain.go:8)  ADDQ $5, AX
  0x000e 00014 (C:UsersbruceDesktopgomain.go:8)  MOVQ AX, "".~r2+24(SP)
  0x0013 00019 (C:UsersbruceDesktopgomain.go:8)  RET
  0x0000 48 8b 44 24 08 48 89 44 24 10 48 83 c0 05 48 89 H.D$.H.D$.H...H.
  0x0010 44 24 18 c3          D$..

我只截取了和main,one函数相关的部分

TEXT "".one(SB), NOSPLIT|ABIInternal, $0-24 这行最后, $0-24 的含义,0代表one函数的栈帧大小(局部变量+可能需要的额外调用函数的参数空间的总大小),因为one函数中没有额外开销,所有大小是0,24是传入参数和返回值的大小,单位是字节。传入的参数和返回值都是 int ,在64位机器上,大小是8个字节,64位。

简单画一下栈的示意图

看一下这句 0x0000 00000 (C:UsersbruceDesktopgomain.go:8) MOVQ "".a+8(SP), AX

SP寄存器指向的是栈顶的位置, AX 是一个通用寄存器

MOVQ指令 把 参数a 也就是(SP+8)的值搬到AX中

0x0005 00005 (C:UsersbruceDesktopgomain.go:8) MOVQ AX, "".~r1+16(SP)
同样,把AX中的值搬到r1(返回值b)

0x000a 00010 (C:UsersbruceDesktopgomain.go:8) ADDQ $5, AX
ADDQ 指令把AX值+5