阅读 bufio 源码的时候,对内置函数 len 产生了很大兴趣,想知道 len 函数的性能如果。
翻阅了 buildin.go,发现对内置函数的处理只有声明,没有定义部分。所以编译内置函数时编译器自动为其添加实现。
翻看了 go build -gcflags 的命令,找到以下比较有意思的参数:
-E debug symbol export
-N disable optimizations
-l disable inlining
-race enable race detector
把 -E -N -l参数加上后,能方便地通过汇编找到对应的 Go 语言代码。
编写一个简单的 go 程序:
package main
import "fmt"
func main() {
arr := [4]int{1, 2, 3, 4}
i := len(arr)
fmt.Println(i)
}
编译: go build -gcflags "-N -l -E" main.go
得到 main 文件,挂上 GDB,list 一下,能看到 go 源码:
(gdb) l
3 import "fmt"
4
5 func main() {
6 arr := [4]int{1, 2, 3, 4}
7 i := len(arr)
8 fmt.Println(i)
9 }
(gdb)
对 len 函数下断点,执行到相应位置。
之后执行 disasse(mble)就能看到相应汇编代码。
就当前的 len 函数,其实我们并没有看到相应的 call 命令,只能看到一系列的内存访问。
将 main 拖入到 IDA 中分析,可以看到如下内容:
mov rbx, [rsp+88h+a.len]
由此可以得出 len 函数直接实现为对结构体内部字段的访问,速度很快。
关于 GDB 调试汇编的其余内容,可以查看各类帮助文档和博客。