使用环境
系统架构 | 语言版本 | |
---|---|---|
Amd64 | Go 1.8 |
示例代码
package main
func main() {
var a, b int
a, b = 1, 2
swap(a, b)
}
func swap(a, b int) {
a, b = b, a
}
go tool compile -S -N -l main.go | grep -v PCDATA |grep -v FUNCDATA >main.s
汇编代码
"".main STEXT size=88 args=0x0 locals=0x28 funcid=0x0 align=0x0
0x0000 00000 (main.go:3) TEXT "".main(SB), ABIInternal, $40-0
0x0000 00000 (main.go:3) CMPQ SP, 16(R14)
0x0004 00004 (main.go:3) JLS 81
// 阶段1
0x0006 00006 (main.go:3) SUBQ $40, SP
0x000a 00010 (main.go:3) MOVQ BP, 32(SP)
0x000f 00015 (main.go:3) LEAQ 32(SP), BP
0x0014 00020 (main.go:4) MOVQ $0, "".a+24(SP)
0x001d 00029 (main.go:4) MOVQ $0, "".b+16(SP)
0x0026 00038 (main.go:5) MOVQ $1, "".a+24(SP)
0x002f 00047 (main.go:5) MOVQ $2, "".b+16(SP)
0x0038 00056 (main.go:6) MOVQ "".a+24(SP), AX
0x003d 00061 (main.go:6) MOVL $2, BX
// 阶段2
0x0042 00066 (main.go:6) CALL "".swap(SB)
// 阶段3
0x0047 00071 (main.go:7) MOVQ 32(SP), BP
0x004c 00076 (main.go:7) ADDQ $40, SP
0x0050 00080 (main.go:7) RET
0x0051 00081 (main.go:7) NOP
0x0051 00081 (main.go:3) CALL runtime.morestack_noctxt(SB)
0x0056 00086 (main.go:3) JMP 0
0x0000 49 3b 66 10 76 4b 48 83 ec 28 48 89 6c 24 20 48 I;f.vKH..(H.l$ H
0x0010 8d 6c 24 20 48 c7 44 24 18 00 00 00 00 48 c7 44 .l$ H.D$.....H.D
0x0020 24 10 00 00 00 00 48 c7 44 24 18 01 00 00 00 48 $.....H.D$.....H
0x0030 c7 44 24 10 02 00 00 00 48 8b 44 24 18 bb 02 00 .D$.....H.D$....
0x0040 00 00 e8 00 00 00 00 48 8b 6c 24 20 48 83 c4 28 .......H.l$ H..(
0x0050 c3 e8 00 00 00 00 eb a8 ........
rel 67+4 t=7 "".swap+0
rel 82+4 t=7 runtime.morestack_noctxt+0
"".swap STEXT nosplit size=57 args=0x10 locals=0x10 funcid=0x0 align=0x0
0x0000 00000 (main.go:10) TEXT "".swap(SB), NOSPLIT|ABIInternal, $16-16
0x0000 00000 (main.go:10) SUBQ $16, SP
0x0004 00004 (main.go:10) MOVQ BP, 8(SP)
0x0009 00009 (main.go:10) LEAQ 8(SP), BP
0x000e 00014 (main.go:10) MOVQ AX, "".a+24(SP)
0x0013 00019 (main.go:10) MOVQ BX, "".b+32(SP)
0x0018 00024 (main.go:11) MOVQ AX, ""..autotmp_2(SP)
0x001c 00028 (main.go:11) MOVQ "".b+32(SP), AX
0x0021 00033 (main.go:11) MOVQ AX, "".a+24(SP)
0x0026 00038 (main.go:11) MOVQ ""..autotmp_2(SP), AX
0x002a 00042 (main.go:11) MOVQ AX, "".b+32(SP)
0x002f 00047 (main.go:12) MOVQ 8(SP), BP
0x0034 00052 (main.go:12) ADDQ $16, SP
0x0038 00056 (main.go:12) RET
0x0000 48 83 ec 10 48 89 6c 24 08 48 8d 6c 24 08 48 89 H...H.l$.H.l$.H.
0x0010 44 24 18 48 89 5c 24 20 48 89 04 24 48 8b 44 24 D$.H.\$ H..$H.D$
0x0020 20 48 89 44 24 18 48 8b 04 24 48 89 44 24 20 48 H.D$.H..$H.D$ H
0x0030 8b 6c 24 08 48 83 c4 10 c3 .l$.H....
go.cuinfo.packagename. SDWARFCUINFO dupok size=0
0x0000 63 6f 6d 6d comm
gclocals?33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00 ........
"".swap.arginfo1 SRODATA static dupok size=5
0x0000 00 08 08 08 ff .....
调用过程
这段代码是汇编代码,是 Go 语言的编译输出。Go 语言编译器使用 SSA (Static Single Assignment) 形式的中间表示来优化和生成机器代码。
让我们分阶段逐步解析这段代码:
-
函数定义:
"".main(SB)
: 这是一个名为main
的函数。(SB)
表示该函数在文本段中。"".swap(SB)
: 这是一个名为swap
的函数。
-
函数体:
TEXT "".main(SB), ABIInternal, $40-0
: 这是main
函数的开始,40是声明这个函数需要的栈空间的大小,一般来说就是局部变量需要的空间,单位是位。 0是声明函数传入参数和返回值需要的栈空间的大小,单位也是位。TEXT "".swap(SB), NOSPLIT|ABIInternal, $16-16
:这是swap
函数的开始,16是声明这个函数需要的栈空间的大小,一般来说就是局部变量需要的空间,单位是位。16是声明函数传入参数和返回值需要的栈空间的大小,单位也是位。`
阶段1:
汇编指令 代码说明 用途说明 SUBQ $40, SP
SP=SP-40 从栈指针 SP
减去 40,为局部变量分配空间MOVQ BP, 32(SP)
BP=SP+32 将基指针 BP
的值移动到SP+32的位置LEAQ 32(SP), BP
将SP+32的地址传输给 BP
MOVQ $0, "".a+24(SP)
将立即数 0 存储到局部变量 a(SP+24)
,初始化a=0MOVQ $0, "".b+16(SP)
将立即数 0 存储到局部变量 b(SP+16)
,初始化b=0MOVQ $1, "".a+24(SP)
将立即数 1 存储到局部变量 a(SP+24)
,赋值a=1MOVQ $2, "".b+16(SP)
将立即数 2 存储到局部变量 b(SP+16)
,赋值b=2MOVQ "".a+24(SP), AX
将局部变量 a
的值加载到寄存器AX
MOVL $2, BX
将立即数 2 加载到寄存器 BX
阶段2:
汇编指令 代码说明 用途说明 SUBQ $16, SP
SP=SP-16 从栈指针 SP
减去16,为局部变量分配空间MOVQ BP, 8(SP)
BP=SP+8 将基指针 BP
的值移动到SP+8的位置LEAQ 8(SP), BP
将SP+8的地址传输给 BP
MOVQ AX, "".a+24(SP)
将AX寄存器的值存储到局部变量 a(SP+24)
,a=AXMOVQ BX, "".b+32(SP)
将BX寄存器的值存储到局部变量 b(SP+32)
,b=BXMOVQ AX, ""..autotmp_2(SP)
将AX寄存器的值存储到一个临时变量 autotmp_2
MOVQ "".b+32(SP), AX
将 b(SP+32)
的值赋值给AXMOVQ AX, "".a+24(SP)
将AX的值赋值给 a(SP+24)
MOVQ ""..autotmp_2(SP), AX
将临时变量 autotmp_2
的值赋值给AXMOVQ AX, "".b+32(SP)
将AX的值赋值给 b(SP+32)
MOVQ 8(SP), BP
将 (SP+8)
的值存储在BP寄存器ADDQ $16, SP
SP=SP+16 SP
增加 16阶段3:
汇编指令 代码说明 用途说明 MOVQ 32(SP), BP
将 (SP+32)
的值存储在BP寄存器ADDQ $40, SP
SP=SP+40 SP
增加40,以释放栈帧空间RET
函数返回 NOP
无操作