GO语言汇编:plan9(贝尔操作系统)
go开发者与plan 9开发者同一人,Rob Pike
寄存器:
数据寄存器:R0-R7,地址寄存器:A0-A7,浮点寄存器:F0-F7。
伪栈寄存器:FP, SP, TOS
数据:
PC用来控制程序执行,SB用来引用全局变量。
Go语言汇编
FUNCDATA和PCDATA是编译器产生的,用于保存一些给垃圾收集的信息。
NOPTR和RODATA的数据不需要被垃圾收集。比指针还要小的数据也被当做NOPTR。不要在go汇编里写非只读数据。
plan9函数调用协议中采用的是caller-save的模式,也就是由调用者负责保存寄存器。
TEXT !$Add(SB),$0
MOVQ x+0(FP), BX
MOVQ y+8(FP), BP
ADDQ BP, BX
MOVQ BX, ret+16(FP)
RET
TEXT "".main(SB), $56-0
56 代表local 大小
0 代表args大小
movl 四字节mov intel指令集
movq 八字节
例子中的TEXT指令就定义了一个叫bytes·Equal的符号(注意是中点号·),接下来就是对应的指令(可以理解成函数体),而最后RET则是返回指令(退出当前stack)。通常情况下,参数大小后跟随着stack frame的大小,使用减号(-)分割。$0-49意味着这是一个0-byte的栈,并且有49-byte长的参数。NOSPLIT说明,不允许调度器调整stack frame的大小,这就意味着必须人工指定stack frame大小。
字符串 函数都放在SB stack basic register
问题:
go是如何实现多值返回的?
go结构体是如何排布的?
go 数组入参的长度是多少?
如何查看go开辟空间位置 堆栈?
数组汇编是怎么玩的?
用例1:
代码:
func fuck(a int){
time.Sleep(time.Duration((a)))
}
func add(a,b int) int{
//a = (b*2)
fuck(a)
return (a+b)
}
func main() {
haha:=add(3,2)
add(haha,4)
}
asm:
"".fuck t=1 size=65 args=0x4 locals=0x10
0x0000 00000 (myLove.go:10) TEXT "".fuck(SB), $16-4
0x0000 00000 (myLove.go:10) MOVL TLS, CX
0x0007 00007 (myLove.go:10) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:10) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:10) JLS 58
0x0012 00018 (myLove.go:10) SUBL $16, SP
0x0015 00021 (myLove.go:10) FUNCDATA $0, gclocals·5184031d3a32a42d85027f073f873668(SB)
0x0015 00021 (myLove.go:10) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:11) MOVL "".a+20(FP), AX
0x0019 00025 (myLove.go:11) CDQ
0x001a 00026 (myLove.go:11) MOVL AX, "".autotmp_0+8(SP)
0x001e 00030 (myLove.go:11) MOVL DX, "".autotmp_0+12(SP)
0x0022 00034 (myLove.go:11) MOVL "".autotmp_0+8(SP), AX
0x0026 00038 (myLove.go:11) MOVL AX, (SP)
0x0029 00041 (myLove.go:11) MOVL "".autotmp_0+12(SP), AX
0x002d 00045 (myLove.go:11) MOVL AX, 4(SP)
0x0031 00049 (myLove.go:11) PCDATA $0, $0
0x0031 00049 (myLove.go:11) CALL time.Sleep(SB)
0x0036 00054 (myLove.go:12) ADDL $16, SP
0x0039 00057 (myLove.go:12) RET
0x003a 00058 (myLove.go:12) NOP
0x003a 00058 (myLove.go:10) CALL runtime.morestack_noctxt(SB)
0x003f 00063 (myLove.go:10) JMP 0
0x0000 64 8b 0d 14 00 00 00 8b 89 00 00 00 00 3b 61 08 d............;a.
0x0010 76 28 83 ec 10 8b 44 24 14 99 89 44 24 08 89 54 v(....D$...D$..T
0x0020 24 0c 8b 44 24 08 89 04 24 8b 44 24 0c 89 44 24 $..D$...$.D$..D$
0x0030 04 e8 00 00 00 00 83 c4 10 c3 e8 00 00 00 00 eb ................
0x0040 bf .
rel 9+4 t=15 TLS+0
rel 50+4 t=7 time.Sleep+0
rel 59+4 t=7 runtime.morestack_noctxt+0
"".add t=1 size=72 args=0xc locals=0x8
0x0000 00000 (myLove.go:13) TEXT "".add(SB), $8-12
0x0000 00000 (myLove.go:13) MOVL TLS, CX
0x0007 00007 (myLove.go:13) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:13) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:13) JLS 65
0x0012 00018 (myLove.go:13) SUBL $8, SP
0x0015 00021 (myLove.go:13) FUNCDATA $0, gclocals·790e5cc5051fc0affc980ade09e929ec(SB)
0x0015 00021 (myLove.go:13) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:13) MOVL $0, "".~r2+20(FP)
0x001d 00029 (myLove.go:15) MOVL "".a+12(FP), BX
0x0021 00033 (myLove.go:15) MOVL BX, (SP)
0x0024 00036 (myLove.go:15) PCDATA $0, $0
0x0024 00036 (myLove.go:15) CALL "".fuck(SB)
0x0029 00041 (myLove.go:16) MOVL "".a+12(FP), BX
0x002d 00045 (myLove.go:16) MOVL BX, "".autotmp_1+4(SP)
0x0031 00049 (myLove.go:16) MOVL "".autotmp_1+4(SP), BX
0x0035 00053 (myLove.go:16) ADDL "".b+16(FP), BX
0x0039 00057 (myLove.go:16) MOVL BX, "".~r2+20(FP)
0x003d 00061 (myLove.go:16) ADDL $8, SP
0x0040 00064 (myLove.go:16) RET
0x0041 00065 (myLove.go:16) NOP
0x0041 00065 (myLove.go:13) CALL runtime.morestack_noctxt(SB)
0x0046 00070 (myLove.go:13) JMP 0
0x0000 64 8b 0d 14 00 00 00 8b 89 00 00 00 00 3b 61 08 d............;a.
0x0010 76 2f 83 ec 08 c7 44 24 14 00 00 00 00 8b 5c 24 v/....D$......\$
0x0020 0c 89 1c 24 e8 00 00 00 00 8b 5c 24 0c 89 5c 24 ...$......\$..\$
0x0030 04 8b 5c 24 04 03 5c 24 10 89 5c 24 14 83 c4 08 ..\$..\$..\$....
0x0040 c3 e8 00 00 00 00 eb b8 ........
rel 9+4 t=15 TLS+0
rel 37+4 t=7 "".fuck+0
rel 66+4 t=7 runtime.morestack_noctxt+0
"".main t=1 size=80 args=0x0 locals=0x10
0x0000 00000 (myLove.go:18) TEXT "".main(SB), $16-0
0x0000 00000 (myLove.go:18) MOVL TLS, CX
0x0007 00007 (myLove.go:18) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:18) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:18) JLS 73
0x0012 00018 (myLove.go:18) SUBL $16, SP
0x0015 00021 (myLove.go:18) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:18) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:19) MOVL $3, (SP)
0x001c 00028 (myLove.go:19) MOVL $2, 4(SP)
0x0024 00036 (myLove.go:19) PCDATA $0, $0
0x0024 00036 (myLove.go:19) CALL "".add(SB)
0x0029 00041 (myLove.go:19) MOVL 8(SP), BX
0x002d 00045 (myLove.go:19) MOVL BX, "".haha+12(SP)
0x0031 00049 (myLove.go:20) MOVL "".haha+12(SP), BX
0x0035 00053 (myLove.go:20) MOVL BX, (SP)
0x0038 00056 (myLove.go:20) MOVL $4, 4(SP)
0x0040 00064 (myLove.go:20) PCDATA $0, $0
0x0040 00064 (myLove.go:20) CALL "".add(SB)
0x0045 00069 (myLove.go:21) ADDL $16, SP
0x0048 00072 (myLove.go:21) RET
0x0049 00073 (myLove.go:21) NOP
0x0049 00073 (myLove.go:18) CALL runtime.morestack_noctxt(SB)
0x004e 00078 (myLove.go:18) JMP 0
0x0000 64 8b 0d 14 00 00 00 8b 89 00 00 00 00 3b 61 08 d............;a.
0x0010 76 37 83 ec 10 c7 04 24 03 00 00 00 c7 44 24 04 v7.....$.....D$.
0x0020 02 00 00 00 e8 00 00 00 00 8b 5c 24 08 89 5c 24 ..........\$..\$
0x0030 0c 8b 5c 24 0c 89 1c 24 c7 44 24 04 04 00 00 00 ..\$...$.D$.....
0x0040 e8 00 00 00 00 83 c4 10 c3 e8 00 00 00 00 eb b0 ................
rel 9+4 t=15 TLS+0
rel 37+4 t=7 "".add+0
rel 65+4 t=7 "".add+0
rel 74+4 t=7 runtime.morestack_noctxt+0
用例二:
多值返回
代码:
func add(a,b int) (int,int){
//a = (b*2)
fuck(a)
return (a+b),(a-b)
}
func main() {
haha,lala:=add(3,2)
add(haha,lala)
}
asm:
"".main t=1 size=88 args=0x0 locals=0x18
0x0000 00000 (myLove.go:18) TEXT "".main(SB), $24-0
0x0000 00000 (myLove.go:18) MOVL TLS, CX
0x0007 00007 (myLove.go:18) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:18) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:18) JLS 81
0x0012 00018 (myLove.go:18) SUBL $24, SP
0x0015 00021 (myLove.go:18) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:18) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:19) MOVL $3, (SP)
0x001c 00028 (myLove.go:19) MOVL $2, 4(SP)
0x0024 00036 (myLove.go:19) PCDATA $0, $0
0x0024 00036 (myLove.go:19) CALL "".add(SB)
0x0029 00041 (myLove.go:19) MOVL 8(SP), BX
0x002d 00045 (myLove.go:19) MOVL BX, "".haha+20(SP)
0x0031 00049 (myLove.go:19) MOVL 12(SP), BX
0x0035 00053 (myLove.go:19) MOVL BX, "".lala+16(SP)
0x0039 00057 (myLove.go:20) MOVL "".haha+20(SP), BX
0x003d 00061 (myLove.go:20) MOVL BX, (SP)
0x0040 00064 (myLove.go:20) MOVL "".lala+16(SP), BX
0x0044 00068 (myLove.go:20) MOVL BX, 4(SP)
0x0048 00072 (myLove.go:20) PCDATA $0, $0
0x0048 00072 (myLove.go:20) CALL "".add(SB)
0x004d 00077 (myLove.go:21) ADDL $24, SP
"".add t=1 size=100 args=0x10 locals=0xc
0x0000 00000 (myLove.go:13) TEXT "".add(SB), $12-16
0x0000 00000 (myLove.go:13) MOVL TLS, CX
0x0007 00007 (myLove.go:13) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:13) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:13) JLS 93
0x0012 00018 (myLove.go:13) SUBL $12, SP
对比用例一与用例二的locals,发现add方法的locals扩大,其把入参与出参都当做返回值,处理。
用例三:研究一下结构体特点
代码:
type test1 struct {
a int
b int
}
func f1(t1 test1){
t1.a = 5
fmt.Println(t1.a)
}
func main() {
aa := test1{1,2}
f1(aa)
}
ASM:
"".main t=1 size=94 args=0x0 locals=0x18
0x0000 00000 (myLove.go:14) TEXT "".main(SB), $24-0
0x0000 00000 (myLove.go:14) MOVL TLS, CX
0x0007 00007 (myLove.go:14) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:14) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:14) JLS 87
0x0012 00018 (myLove.go:14) SUBL $24, SP
0x0015 00021 (myLove.go:14) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:14) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0015 00021 (myLove.go:15) MOVL $0, BX
0x0017 00023 (myLove.go:15) MOVL BX, "".aa+16(SP)
0x001b 00027 (myLove.go:15) MOVL BX, "".aa+20(SP)
0x001f 00031 (myLove.go:15) MOVL $1, "".autotmp_6+12(SP)
0x0027 00039 (myLove.go:15) MOVL "".autotmp_6+12(SP), BX
0x002b 00043 (myLove.go:15) MOVL BX, "".aa+16(SP)
0x002f 00047 (myLove.go:15) MOVL $2, "".autotmp_7+8(SP)
0x0037 00055 (myLove.go:15) MOVL "".autotmp_7+8(SP), BX
0x003b 00059 (myLove.go:15) MOVL BX, "".aa+20(SP)
0x003f 00063 (myLove.go:16) MOVL "".aa+16(SP), BX
0x0043 00067 (myLove.go:16) MOVL BX, (SP)
0x0046 00070 (myLove.go:16) MOVL "".aa+20(SP), BX
0x004a 00074 (myLove.go:16) MOVL BX, 4(SP)
0x004e 00078 (myLove.go:16) PCDATA $0, $0
0x004e 00078 (myLove.go:16) CALL "".f1(SB)
0x0053 00083 (myLove.go:18) ADDL $24, SP
"".f1 t=1 size=200 args=0x8 locals=0x3c
0x0000 00000 (myLove.go:10) TEXT "".f1(SB), $60-8
0x0000 00000 (myLove.go:10) MOVL TLS, CX
0x0007 00007 (myLove.go:10) MOVL (CX)(TLS*2), CX
0x000d 00013 (myLove.go:10) CMPL SP, 8(CX)
0x0010 00016 (myLove.go:10) JLS 190
0x0016 00022 (myLove.go:10) SUBL $60, SP
0x0019 00025 (myLove.go:10) FUNCDATA $0, gclocals·8edb5632446ada37b0a930d010725cc5(SB)
0x0019 00025 (myLove.go:10) FUNCDATA $1, gclocals·ff5e069297bc4e135ac51ef96d4582a2(SB)
0x0019 00025 (myLove.go:11) MOVL $5, "".autotmp_5+24(SP)
0x0021 00033 (myLove.go:11) MOVL "".autotmp_5+24(SP), BX
0x0025 00037 (myLove.go:11) MOVL BX, "".t1+64(FP)
0x0029 00041 (myLove.go:12) MOVL $0, BX
0x002b 00043 (myLove.go:12) MOVL BX, "".autotmp_3+40(SP)
0x002f 00047 (myLove.go:12) MOVL BX, "".autotmp_3+44(SP)
0x0033 00051 (myLove.go:12) LEAL "".autotmp_3+40(SP), BX
0x0037 00055 (myLove.go:12) MOVL BX, "".autotmp_1+28(SP)
0x003b 00059 (myLove.go:12) MOVL $type.int(SB), (SP)
0x0042 00066 (myLove.go:12) LEAL "".t1+64(FP), BX
0x0046 00070 (myLove.go:12) MOVL BX, 4(SP)
main函数堆栈,将数值拷贝到偏移为0 和 4的位置,而f1函数直接从FP+64也就是SP+0的位置修改数据,所以数据修改无效
SP
0---
4---
16---
20---
FP