golang assmebly

golang提供了根据源码生成汇编代码的命令go tool compile -S xxx.go 。通过该命令生成如下的汇编代码,用来了解汇编语法。

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
># cat test.go
package test
func t(cc []byte) int{
return len(cc)
}

># go tool compile -S test.go

"".t t=1 size=11 args=0x20 locals=0x0
0x0000 00000 (test1.go:3) TEXT "".t(SB), $0-32
0x0000 00000 (test1.go:3) FUNCDATA $0, gclocals·42de96b0ee2ecebee32eb4aae6bc10d1(SB)
0x0000 00000 (test1.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (test1.go:4) MOVQ "".cc+16(FP), AX
0x0005 00005 (test1.go:4) MOVQ AX, "".~r1+32(FP)
0x000a 00010 (test1.go:4) RET
0x0000 48 8b 44 24 10 48 89 44 24 20 c3 H.D$.H.D$ .
gclocals·33cdeccccebe80329f1fdbee7f5874cb t=8 dupok size=8
0x0000 01 00 00 00 00 00 00 00 ........
gclocals·42de96b0ee2ecebee32eb4aae6bc10d1 t=8 dupok size=9
0x0000 01 00 00 00 04 00 00 00 01 .........
go.info."".t t=45 size=56
0x0000 02 22 22 2e 74 00 00 00 00 00 00 00 00 00 00 00 ."".t...........
0x0010 00 00 00 00 00 00 01 05 63 63 00 01 9c 00 00 00 ........cc......
0x0020 00 00 00 00 00 05 7e 72 31 00 04 9c 11 18 22 00 ......~r1.....".
0x0030 00 00 00 00 00 00 00 00 ........
rel 6+8 t=1 "".t+0
rel 14+8 t=1 "".t+11
rel 29+8 t=28 go.info.[]uint8+0
rel 47+8 t=28 go.info.int+0
runtime.gcbits.01 t=8 dupok size=1
0x0000 01 .
type..namedata.*[]uint8. t=8 dupok size=11
0x0000 00 00 08 2a 5b 5d 75 69 6e 74 38 ...*[]uint8
type.*[]uint8 t=8 dupok size=56
0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 a5 8e d0 69 00 08 08 36 00 00 00 00 00 00 00 00 ...i...6........
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.algarray+80
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*[]uint8.+0
rel 48+8 t=1 type.[]uint8+0
type.[]uint8 t=8 dupok size=56
0x0000 18 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
0x0010 df 7e 2e 38 02 08 08 17 00 00 00 00 00 00 00 00 .~.8............
0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.algarray+0
rel 32+8 t=1 runtime.gcbits.01+0
rel 40+4 t=5 type..namedata.*[]uint8.+0
rel 44+4 t=6 type.*[]uint8+0
rel 48+8 t=1 type.uint8+0

以上汇编内容采用的类似于AT&T的语言规则,使用的是plan9的汇编语法。
TEXT . SB共同作用声明了一个函数main,不能对SB进行解引用。
\$X-X 其中第一个X表示该函数的栈大小,第二个X表示参数返回值共需要多少字节。上面\$0-32,其中32表示函数有32字节的栈帧并且需要一个0字节的参数。
如果没有为TEXT指定NOSPLIT标志,必须提供参数大小,NOSPLIT定义在src/runtime/textflag.h中,指定NOSPLIT说明不允许调度器调整stack frame的大小。

关于slice占24字节 byte,int占8字节

1
2
3
4
5
type slice struct {
array unsafe.Pointer
len int
lcap int
}

unsafe.Pointer在amd64上是uintptr即uint64。int在amd64上是int64.因此一个slice占用了3个qword(word=2byte qual=4, 2x4=8byte 8x8=64bit)即3x8=24bytes。
FP(stack frame pointer)stack帧低位指针,指向参数和局部变量,offset为正数。主要用于取参数以及返回值。
SP(virtual stack pointer) stack帧高位指针(栈顶),offset应为负数。
PC(program counter) 程序计数器,负责跳转和分支。
SB(static base pointer) 静态全局符号(symbol)。

栈存储分布图如下:

1
2
3
4
5
6
7
8
9
High +---------------+
| |
| stack frame 0 |
| |
+---------------+
| | ---+ SP
| stack frame 1 |
| | ---+ FP
Low +---------------+


常用操作指令说明:

  • AMD64/386寄存器
    amd64里寄存器 [A-D]X通用64位寄存器 R8-15 SI DI X0-15 Y0-15
  • ARM/s390寄存器register
    数据寄存器R0~R7 地址寄存器A0~A7 浮点寄存器F0~F7
  • 伪寄存器pseudo-register
    FP frame pointer 0(FP)指向第一个参数,4(FP)指向第二个。 p+0(FP)为0(FP)指定了一个名称p。
    SP local stack pointer 0(SP)指第一个自动变量
    TOS top-of-stack 保存临时值

编写汇编文件规则:

  1. 汇编文件编码格式utf8,要求最后一行是空白行
  2. 文件名要按照平台xxx_amd64.s或者xxx_arm.s命令,平台包含386,amd64,arm,arm64,mipsx,mipsx64,ppc64x等等
  3. 常用引入头文件src/runtime/textflag.h
  4. 创建xxx_amd64.s的同时要创建xxx.go,并在go文件中声明其函数。编译时通过+build tag就可以编译指定的平台汇编代码了。
    示例如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     # filename: add_amd64.s

    #include "textflag.h"

    // func Add(a int, b int) (z int)
    TEXT ·Add(SB), NOSPLIT, $0-24
    MOVQ a+0(FP), AX
    MOVQ b+8(FP), BX
    ADDQ AX, BX
    MOVQ BX, z+16(FP)
    RET

要了解更过的汇编语法参考如下链接:
arm汇编指令文档:https://developer.arm.com

坚持原创技术分享,如果觉得文章对你有帮助,给点鼓励更好!