读懂go汇编

发布于 2018-04-25 作者 超级苦工 342次 浏览 版块 分享

go的汇编感觉比较抽象,和之前接触的masm或者nasm,亦或是arm下的汇编指令都有一些不同,而且和语言本身的一些数据结构,如string或者slice相关联,要读懂这些指令之前,需要先明白这些数据结构的内存布局
今天通过对一小段汇编指令的解析,来进一步学习go的汇编

先上源代码
type Bean struct {
    Name string
}
func main() {
    m := make(map[string]*Bean)
    b := Bean{"Jim"}
    m["Jim"] = &b
    fmt.Println(m["Jim"])
}

简书支持代码高亮了吗?

本次只对最后一条语句的汇编进行分析
使用

$ go tool compile -S main.go >> main.S

生成汇编文件 main.S
打开之后,找到该语句所对应的汇编指令

需要先介绍一下map的取值函数签名
func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer
这个函数,该函数位于runtime包中

    ;获取*maptype
    LEAQ    type.map[string]*"".Bean(SB), AX
    AX, (SP)
    ;获取*hmap,map实际上是一个*hmap类型指针
    LEAQ    ""..autotmp_6+72(SP), AX
    MOVQ    AX, 8(SP)
    ;构造参数key,key是一个string,由字节数组和len字段构成
    ;字符串的字节数组
    LEAQ    go.string."Jim"(SB), AX
    MOVQ    AX, 16(SP)
    ;字符串的字符长度3
    MOVQ    $3, 24(SP)
    PCDATA  $0, $1
   ;通过key获取map中的value
    CALL    runtime.mapaccess1_faststr(SB)
    ;获取mapaccess1_faststr的返回值,是unsafe.Pointer(&value)
    MOVQ    32(SP), AX
    ;获取value的内容,因为value类型是指针,直接保存到AX
    MOVQ    (AX), AX
    ;内存置零
    XORPS   X0, X0
    MOVUPS  X0, ""..autotmp_4+56(SP)
    ;构造*Bean的空接口值
    ;*Bean的type
    LEAQ    type.*"".Bean(SB), CX
    MOVQ    CX, ""..autotmp_4+56(SP)
    ;AX保存的是*Bean的类型
    MOVQ    AX, ""..autotmp_4+64(SP)
    ;保存空接口值的地址到AX
    LEAQ    ""..autotmp_4+56(SP), AX
    ;可变长参数实际上是一个slice,底层数组只有一个元素
    MOVQ    AX, (SP)
    ;len为1
    MOVQ    $1, 8(SP)
    ;cap为1
    MOVQ    $1, 16(SP)
    PCDATA  $0, $3
    ;调用fmt.Println
    CALL    fmt.Println(SB)

汇编高亮?

go的汇编中,调用一个函数时,调用方要先把参数类型的内存布局和函数的参数声明顺序放到SP伪寄存器对应的函数栈中,而被调用函数把返回值写到紧接参数之后的位置,调用方可以直接获取到

收藏
暂无回复