casyup.me@outlook.com

0%

other/headFirstGoAssembly

前言

下班忘把没读完的 inside the c++ object model 带回去

还好包里有本备用的 go, 简单看了一下前面基础部分

感觉就是, 很”新颖 + 轻巧”, 有很多新的概念和工具, 抛弃了一些沉重的”包袱”

试了一下用例, 看了一下汇编

1
2
3
4
5
6
7
1 package main
2
3 import "fmt"
4
5 func main() {
6 fmt.Printf("hello, world\n")
7 }

汇编:

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
 1 # command-line-arguments                                                                 
2 "".main STEXT size=88 args=0x0 locals=0x48
3 0x0000 00000 (/test/go/t.go:5) TEXT "".main(SB), $72-0 // 非常友好地给我加上了对应的源码信息
4 0x0000 00000 (/test/go/t.go:5) MOVQ (TLS), CX
5 0x0009 00009 (/test/go/t.go:5) CMPQ SP, 16(CX)
6 0x000d 00013 (/test/go/t.go:5) JLS 81
7 0x000f 00015 (/test/go/t.go:5) SUBQ $72, SP // 这里应该是在开辟栈帧
8 0x0013 00019 (/test/go/t.go:5) MOVQ BP, 64(SP) // 栈顶保存了 bp 指针
9 0x0018 00024 (/test/go/t.go:5) LEAQ 64(SP), BP // 重置 bp
10 0x001d 00029 (/test/go/t.go:5) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) // gc ? garbage collection?
11 0x001d 00029 (/test/go/t.go:5) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
12 0x001d 00029 (/test/go/t.go:5) FUNCDATA $3, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB) // 看不懂 = =
13 0x001d 00029 (/test/go/t.go:6) PCDATA $2, $1
14 0x001d 00029 (/test/go/t.go:6) PCDATA $0, $0 // 还是看不懂 = =
15 0x001d 00029 (/test/go/t.go:6) LEAQ go.string."hello, world\n"(SB), AX // 加载字符串文本, 者很方便, 我直接可以看到字符串
16 0x0024 00036 (/test/go/t.go:6) PCDATA $2, $0
17 0x0024 00036 (/test/go/t.go:6) MOVQ AX, (SP)
18 0x0028 00040 (/test/go/t.go:6) MOVQ $13, 8(SP) // 应该是指字符串长度
19 0x0031 00049 (/test/go/t.go:6) MOVQ $0, 16(SP) // 后续参数数量?
20 0x003a 00058 (/test/go/t.go:6) XORPS X0, X0 // 单精度异或?
21 0x003d 00061 (/test/go/t.go:6) MOVUPS X0, 24(SP) // 代码中没有用到单精度浮点数, 为什么会有这个指令?
22 0x0042 00066 (/test/go/t.go:6) CALL fmt.Printf(SB) // 调用 // 这样的格式很清晰
23 0x0047 00071 (/test/go/t.go:7) MOVQ 64(SP), BP // 返还 bp
24 0x004c 00076 (/test/go/t.go:7) ADDQ $72, SP // 重置栈顶
25 0x0050 00080 (/test/go/t.go:7) RET // 结束
26 0x0051 00081 (/test/go/t.go:7) NOP
27 0x0051 00081 (/test/go/t.go:5) PCDATA $0, $-1
28 0x0051 00081 (/test/go/t.go:5) PCDATA $2, $-1
29 0x0051 00081 (/test/go/t.go:5) CALL runtime.morestack_noctxt(SB) // 运行时的什么?
30 0x0056 00086 (/test/go/t.go:5) JMP 0

FUNCDATA 我怀疑和垃圾回收有关, PCDATA 意义不明 (网上查了一下, 都和垃圾回收有关)

我尝试过添加一个参数, 以用作 fmt.Println(), 但是我并未在代码中找到任何有关参数的信息

仅仅只有一句看起来和那个参数有关

1
2
3
LEAQ    ""..autotmp_0+64(SP), AX	// 就是这句话
PCDATA $2, $0
MOVQ AX, 16(SP)

而且我差点忽略的一点是, 这里参数的传递是用栈

顺便, 我在文件的末尾找到了这些信息, 看起来像是某种标记

1
2
3
4
5
6
7
8
213 gclocals·69c1753bd5f81501d95132d08af04464 SRODATA dupok size=8        
214 0x0000 02 00 00 00 00 00 00 00 ........
215 gclocals·568470801006e5c0dc3947ea998fe279 SRODATA dupok size=10
216 0x0000 02 00 00 00 02 00 00 00 00 02 ..........
217 gclocals·9fb7f0986f647f17cb53dda1484e0f7a SRODATA dupok size=10
218 0x0000 02 00 00 00 01 00 00 00 00 01 ..........
219 gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
220 0x0000 01 00 00 00 00 00 00 00 ........

我再次使用了变量存储值的形式, 然后我的数字能够正常看见了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0x0034 00052 (/test/go/t.go:7)  MOVQ    $100, 8(SP)	// 我的数字在这里
0x003d 00061 (/test/go/t.go:7) CALL runtime.convT2E64(SB)
0x0042 00066 (/test/go/t.go:7) MOVQ 16(SP), AX
0x0047 00071 (/test/go/t.go:7) PCDATA $2, $2
0x0047 00071 (/test/go/t.go:7) MOVQ 24(SP), CX
0x004c 00076 (/test/go/t.go:7) MOVQ AX, ""..autotmp_1+64(SP)
0x0051 00081 (/test/go/t.go:7) PCDATA $2, $0
0x0051 00081 (/test/go/t.go:7) MOVQ CX, ""..autotmp_1+72(SP)
0x0056 00086 (/test/go/t.go:7) PCDATA $2, $1
0x0056 00086 (/test/go/t.go:7) LEAQ go.string."hello, world\n%d"(SB), AX
0x005d 00093 (/test/go/t.go:7) PCDATA $2, $0
0x005d 00093 (/test/go/t.go:7) MOVQ AX, (SP)
0x0061 00097 (/test/go/t.go:7) MOVQ $15, 8(SP)
0x006a 00106 (/test/go/t.go:7) PCDATA $2, $1
0x006a 00106 (/test/go/t.go:7) LEAQ ""..autotmp_1+64(SP), AX
0x006f 00111 (/test/go/t.go:7) PCDATA $2, $0
0x006f 00111 (/test/go/t.go:7) MOVQ AX, 16(SP)
0x0074 00116 (/test/go/t.go:7) MOVQ $1, 24(SP)
0x007d 00125 (/test/go/t.go:7) MOVQ $1, 32(SP)
0x0086 00134 (/test/go/t.go:7) CALL fmt.Printf(SB)
// 但是在调用之前, 我并没看到我的数字被加载了, 为什么?
// 我唯一比较怀疑的是那个 CALL runtime.convT2E64(SB)

好吧, 我的数据再度丢失了, 我甚至不知道它是如何被传过去的…

summary

go的汇编基于 plan 9(一个新的操作系统), 感觉到了新的技术和观点

并且它也更加友好, 我明显觉得看它的汇编会更轻松一些

(除了那个 PCDATA, FUNCDATA, 和那个已经被我跟丢的变量)

emmm… 很不错, 觉得自己听了别人的建议, 去学新的语言

而不学现在看起来很强大, 但是已经很老了的 java 是一个正确的决定