原文章中的6l和6g在go tool里面没有找到,查了网上的相关资料有了以下的补充: 使用的工具是go tool compile 和 go tool objdump

go tool
复制代码

Screen Shot 2021-10-09 at 11.50.51 AM.png

这里我标注出了两个最常用的工具 go tool compile 和 go tool objdump。在我们卷 Go 汇编底层的时候,业内还有这么一句黑话:

几乎没有任何一个 Go 汇编底层问题不是用一条 go tool compile 不能解决的,如果不行的话,就用 go tool objdump,总能知道是怎么回事。

再让我们看看这两句指令在具体场合下都是什么意思:

go tool compile -S main.go  # 反编译代码为汇编代码。

go tool objdump # 可用于查看任意函数的机器码、汇编指令、偏移。(go 源码下面有个 cmd/internal/goobj包,可以读到.o文件的重定向信息,更好)

go tool objdump -S 二进制 # Objdump 打印二进制文件中所有文本符号(代码)的反汇编。如果存在 -S 选项,objdump 只会反汇编名称与正则表达式匹配的符号。

我们来编写一个小案例进行汇编调试实践:

package main

import "fmt"

func main() {
   var a = "hello"
   var b = []byte(a)
   fmt.Println(b)
}
复制代码

通过反汇编工具来查看一下:

go tool compile -S ./hello.go | grep "hello.go:5"
复制代码

这条命令的意思是,产生 .o 目标文件,并且把目标的汇编内容输出出来。后面跟上管道,用 grep 截取出来 hello.go 编译出来第五行的汇编代码。这里大部分汇编代码其实我们不需要看懂,我们只需要它调用了其中某个函数就知道了。

对于初学者来说,学习Go汇编不需要全都懂,只需要一些关键路径在干什么就行。比如这里最关键的是 "runtime.stringtoslicebyte(SB)",即我们要把 string 转换成 byte 数组,底层会调用这个函数。

掌握了这个方法我们就能解决之前文章中提到的第一个问题:

场景1,这两段代码运行速度怎样?第一个比第二个快?

// 代码1
package main

type person struct {
   age int
}

func main() {
   var a = &person{111}
   println(a)
}
复制代码
// 对比代码2
package main

type person struct {
   age int
}

func main() {
   var b = person {111}
   var a = &b
   println(a)
}
复制代码

我们来看看第一个代码第 8 行编译后变成啥了:

再来看看第二个代码第 8 和第 9 行:

由此,我们可以得出结论:一行版本的代码和两行版本的代码最终编译出的结果是完全一致的,没有任何区别。