1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
"".addInt STEXT size=177 args=0x18 locals=0x20 funcid=0x0
;; 0x0000 00000 均为当前指令相对于当前函数的偏移量,第一个是 16 进制,第二个是 10 进制
;; TEXT 函数申明
;; TEXT 位于内存的 .text 段
;; "".addInt(SB) ""为包名,链接时会填充;函数名 addInt;SB (static base)虚拟寄存器,基于静态地址,可认为是程序内存起始位置,所有用户定义的符号(如 main.addInt) 都作为偏移量写入伪寄存器 FP 和 SB
;; ??? addInt 之所以使用 SB 是否是相对于 so 的函数而言,因为对于动态链接库的函数,函数的地址 = so 文件在进程内存空间的映射地址 + 函数偏移量,而静态链接的函数在编译器就可以确定地址
;; ABIInternal 编译器 flag,含义 application binary interface
;; 其他常见的编译器 flag 有 NOSPLIT
;; NOSPLIT 使编译器不要进行内联优化
;; $32-24 函数栈帧大小为 32 字节,其中参数+返回值占用 24 字节
0x0000 00000 (./compile.go:11) TEXT "".addInt(SB), ABIInternal, $32-24
;; MOV 数据搬运
;; MOVB // 1 byte B(Byte)
;; MOVW // 2 bytes W(Word)
;; MOVL // 4 bytes L(Long)
;; MOVQ // 8 bytes Q(Quadword)
;; MOVSD //
;; MOVUPS // 16 bytes 4个不对准的单精度值
;; MOVAPS // 16 bytes 4个对准的单精度值
;; TLS 是一个由 runtime 维护的虚拟寄存器,保存了指向当前 g 的指针
;; g 前 24 位数据结构如下:
;; 0(TLS) uintptr g.stack.lo;
;; 8(TLS) uintptr g.stack.hi; stack describes the actual stack memory: [stack.lo,stack.hi)
;; 16(TLS) uintptr g.stackguard0; stackguard0 is the stack pointer compared in the Go stack growth prologue.
0x0000 00000 (./compile.go:11) MOVQ (TLS), CX
;; CMP 比较大小
;; 与 MOV 类似,CMPL,CMPQ ... 中的 L,Q 为 size 大小
;; CMPQ SP,16(CX) 表示将以 8bytes 的大小比较 SP,*(CX + 16) 即 g.stackguard0 的大小
0x0009 00009 (./compile.go:11) CMPQ SP, 16(CX)
;; PCDATA GC 相关
;; PC表格: 针对每个函数和函数的每个指令生成一个地址表格,记录代码所在的文件路径、行号和函数的信息
;; PCDATA tableid,tableoffset 第一个参数为表格的类型,第二个是表格的地址
0x000d 00013 (./compile.go:11) PCDATA $0, $-2
;; JLS jump less 小于时跳转
;; CMPQ SP,16(CX); JLS 167 表示若 SP < *(CX + 16) 跳转到 00167
;; 当 g 的 satck 不足时, 跳转到 00167 执行扩容函数
0x000d 00013 (./compile.go:11) JLS 167
0x0013 00019 (./compile.go:11) PCDATA $0, $-1
;; 栈调整
;; SUBQ $32,SP 对 SP 做减法,为函数分配函数栈帧
0x0013 00019 (./compile.go:11) SUBQ $32, SP
;; MOV 数据搬运
;; 使用 MOV,CMP 的时候会有看到带括号和不带括号的区别
;; MOVQ 16(AX),BX // => BX = *(AX + 16)
;; MOVQ AX,BX // => BX = AX 将AX中存储的内容赋值给BX,注意区别
;; CMPB (AX),$48 // 以 byte 的 size 比较 *(AX) 48
;; MOVQ BP,24(SP) 表示将 BP 赋值给 *(SP + 24),作用为保存调用者的 BP
0x0017 00023 (./compile.go:11) MOVQ BP, 24(SP)
;; LEA Load Effective Address 地址运算,类似 &
;; LEAQ 24(SP),BP 表示将 (SP + 24) 赋值给 BP,作用为设置新的 BP
0x001c 00028 (./compile.go:11) LEAQ 24(SP), BP
;; FUNCDATA GC相关
;; FUNC 表格用于记录函数的参数、局部变量的指针信息
0x0021 00033 (./compile.go:11) FUNCDATA $0, gclocals·54241e171da8af6ae173d69da0236748(SB)
0x0021 00033 (./compile.go:11) FUNCDATA $1, gclocals·2a5305abe05176240e61b8620e19a815(SB)
;; MOVQ $0,"".~r2+56(SP)表示将 0 赋值给 *(56 + SP)
;; .r2 是分配给引用地址的任意别名;尽管没有任何语义上的含义,但在使用虚拟寄存器和相对地址时,这种别名是需要强制使用的。
;; "".~r2+56(SP) 格式 $pkg_name.~$var_name+size(reg)
0x0021 00033 (./compile.go:11) MOVQ $0, "".~r2+56(SP)
0x002a 00042 (./compile.go:12) LEAQ type."".Data(SB), AX
0x0031 00049 (./compile.go:12) MOVQ AX, (SP)
0x0035 00053 (./compile.go:12) PCDATA $1, $0
;; CALL 调用函数
;; 调用函数 runtime.newobject,依据上下文(SP)为参数,8(SP)为返回值
;; 内存逃逸:runtime.newobject 会导致对象分配到堆上
0x0035 00053 (./compile.go:12) CALL runtime.newobject(SB)
0x003a 00058 (./compile.go:12) MOVQ 8(SP), AX
0x003f 00063 (./compile.go:12) MOVQ AX, ""..autotmp_3+16(SP)
0x0044 00068 (./compile.go:12) MOVQ $0, (AX)
0x004b 00075 (./compile.go:12) MOVQ $0, 16(AX)
;; XORPS 源操作数(第二个操作数)与目标操作数(第一个操作数)进行异或。结果保存到目标操作数
;; XORPS X0,X0 初始化寄存器 X0
0x0053 00083 (./compile.go:12) XORPS X0, X0
0x0056 00086 (./compile.go:12) MOVSD X0, 24(AX)
0x005b 00091 (./compile.go:12) LEAQ 8(AX), DI
0x005f 00095 (./compile.go:12) PCDATA $0, $-2
;; GC相关,是否需要写屏障
0x005f 00095 (./compile.go:12) CMPL runtime.writeBarrier(SB), $0
;; JEQ jump equal 等于时跳转
0x0066 00102 (./compile.go:12) JEQ 106
;; JMP 无条件跳转
;; JMP addr // 跳转到地址,地址可为代码中的地址
;; JMP label // 跳转到标签,可以跳转到同一函数内的标签位置
;; JMP 2(PC) // 以当前指令为基础,向后跳转 2 行
0x0068 00104 (./compile.go:12) JMP 156
0x006a 00106 (./compile.go:12) MOVQ $0, 8(AX)
0x0072 00114 (./compile.go:12) JMP 116
0x0074 00116 (./compile.go:12) PCDATA $0, $-1
0x0074 00116 (./compile.go:12) MOVQ ""..autotmp_3+16(SP), AX
0x0079 00121 (./compile.go:12) TESTB AL, (AX)
0x007b 00123 (./compile.go:12) MOVQ "".a+40(SP), CX
0x0080 00128 (./compile.go:12) ADDQ "".b+48(SP), CX
0x0085 00133 (./compile.go:12) MOVQ CX, (AX)
0x0088 00136 (./compile.go:12) MOVQ ""..autotmp_3+16(SP), AX
0x008d 00141 (./compile.go:12) MOVQ AX, "".~r2+56(SP)
;; 栈调整
;; ADDQ $32,SP 对 SP 做加法,清除函数栈帧
0x0092 00146 (./compile.go:12) MOVQ 24(SP), BP
0x0097 00151 (./compile.go:12) ADDQ $32, SP
;; RET 返回
0x009b 00155 (./compile.go:12) RET
0x009c 00156 (./compile.go:12) PCDATA $0, $-2
0x009c 00156 (./compile.go:12) XORL AX, AX
0x009e 00158 (./compile.go:12) NOP
0x00a0 00160 (./compile.go:12) CALL runtime.gcWriteBarrier(SB)
0x00a5 00165 (./compile.go:12) JMP 116
;; NOP 空操作,占用一个时钟周期,用于延时或者程序指令的对齐
0x00a7 00167 (./compile.go:12) NOP
0x00a7 00167 (./compile.go:11) PCDATA $1, $-1
0x00a7 00167 (./compile.go:11) PCDATA $0, $-2
;; CALL runtime.morestack satck 扩容
0x00a7 00167 (./compile.go:11) CALL runtime.morestack_noctxt(SB)
0x00ac 00172 (./compile.go:11) PCDATA $0, $-1
0x00ac 00172 (./compile.go:11) JMP 0
;; ... 省略部分内容 .
rel 5+4 t=17 TLS+0
rel 45+4 t=16 type."".Data+0
rel 54+4 t=8 runtime.newobject+0
rel 97+4 t=16 runtime.writeBarrier+-1
rel 161+4 t=8 runtime.gcWriteBarrier+0
rel 168+4 t=8 runtime.morestack_noctxt+0
"".main STEXT size=186 args=0x0 locals=0x78 funcid=0x0
0x0000 00000 (./compile.go:15) TEXT "".main(SB), ABIInternal, $120-0
0x0000 00000 (./compile.go:15) MOVQ (TLS), CX
0x0009 00009 (./compile.go:15) CMPQ SP, 16(CX)
0x000d 00013 (./compile.go:15) PCDATA $0, $-2
0x000d 00013 (./compile.go:15) JLS 176
0x0013 00019 (./compile.go:15) PCDATA $0, $-1
0x0013 00019 (./compile.go:15) SUBQ $120, SP
0x0017 00023 (./compile.go:15) MOVQ BP, 112(SP)
0x001c 00028 (./compile.go:15) LEAQ 112(SP), BP
0x0021 00033 (./compile.go:15) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0021 00033 (./compile.go:15) FUNCDATA $1, gclocals·1d0ed49f611d7e40a62328b5976a2ede(SB)
0x0021 00033 (./compile.go:15) FUNCDATA $2, "".main.stkobj(SB)
;; CALL 参数:(SP),8(SP)
0x0021 00033 (./compile.go:16) MOVQ $1, (SP)
0x0029 00041 (./compile.go:16) MOVQ $2, 8(SP)
0x0032 00050 (./compile.go:16) PCDATA $1, $0
;; CALL
0x0032 00050 (./compile.go:16) CALL "".addInt(SB)
;; CALL 返回值 16(SP)
0x0037 00055 (./compile.go:16) MOVQ 16(SP), AX
0x003c 00060 (./compile.go:16) MOVQ AX, "".data+48(SP)
0x0041 00065 (./compile.go:17) MOVQ AX, ""..autotmp_1+64(SP)
0x0046 00070 (./compile.go:17) XORPS X0, X0
0x0049 00073 (./compile.go:17) MOVUPS X0, ""..autotmp_2+72(SP)
0x004e 00078 (./compile.go:17) LEAQ ""..autotmp_2+72(SP), AX
0x0053 00083 (./compile.go:17) MOVQ AX, ""..autotmp_4+56(SP)
0x0058 00088 (./compile.go:17) TESTB AL, (AX)
0x005a 00090 (./compile.go:17) MOVQ ""..autotmp_1+64(SP), CX
0x005f 00095 (./compile.go:17) LEAQ type.*"".Data(SB), DX
0x0066 00102 (./compile.go:17) MOVQ DX, ""..autotmp_2+72(SP)
0x006b 00107 (./compile.go:17) MOVQ CX, ""..autotmp_2+80(SP)
0x0070 00112 (./compile.go:17) TESTB AL, (AX)
0x0072 00114 (./compile.go:17) JMP 116
0x0074 00116 (./compile.go:17) MOVQ AX, ""..autotmp_3+88(SP)
0x0079 00121 (./compile.go:17) MOVQ $1, ""..autotmp_3+96(SP)
0x0082 00130 (./compile.go:17) MOVQ $1, ""..autotmp_3+104(SP)
0x008b 00139 (./compile.go:17) MOVQ AX, (SP)
0x008f 00143 (./compile.go:17) MOVQ $1, 8(SP)
0x0098 00152 (./compile.go:17) MOVQ $1, 16(SP)
0x00a1 00161 (./compile.go:17) CALL fmt.Println(SB)
0x00a6 00166 (./compile.go:64) MOVQ 112(SP), BP
0x00ab 00171 (./compile.go:64) ADDQ $120, SP
0x00af 00175 (./compile.go:64) RET
0x00b0 00176 (./compile.go:64) NOP
0x00b0 00176 (./compile.go:15) PCDATA $1, $-1
0x00b0 00176 (./compile.go:15) PCDATA $0, $-2
0x00b0 00176 (./compile.go:15) CALL runtime.morestack_noctxt(SB)
0x00b5 00181 (./compile.go:15) PCDATA $0, $-1
0x00b5 00181 (./compile.go:15) JMP 0
;; ... 省略部分内容
type..importpath.fmt. SRODATA dupok size=6
0x0000 00 00 03 66 6d 74 ...fmt
gclocals·54241e171da8af6ae173d69da0236748 SRODATA dupok size=9
0x0000 01 00 00 00 03 00 00 00 00 .........
gclocals·2a5305abe05176240e61b8620e19a815 SRODATA dupok size=9
0x0000 01 00 00 00 01 00 00 00 00 .........
gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
0x0000 01 00 00 00 00 00 00 00 ........
gclocals·1d0ed49f611d7e40a62328b5976a2ede SRODATA dupok size=9
0x0000 01 00 00 00 08 00 00 00 00 .........
"".main.stkobj SRODATA static size=24
0x0000 01 00 00 00 00 00 00 00 d8 ff ff ff ff ff ff ff ................
0x0010 00 00 00 00 00 00 00 00 ........
rel 16+8 t=1 type.[1]interface {}+0
gclocals·dc9b0298814590ca3ffc3a889546fc8b SRODATA dupok size=10
0x0000 02 00 00 00 02 00 00 00 03 00 ..........
gclocals·2589ca35330fc0fce83503f4569854a0 SRODATA dupok size=10
0x0000 02 00 00 00 02 00 00 00 00 00 ..........
|