我有兴趣检查标准Go编译器的x86汇编输出,看看我的代码是否真的被转换为合理有效的汇编代码;希望通过分析和检查程序集输出,我可以得到一个线索,我应该在哪里/如何重写我的Go代码以获得最佳性能。但是当我使用-S标志检查代码时,Go吐出一团糟!我想要两件事:
有没有办法让Go编译器将汇编输出转储到文件中,而不只是在终端上打印出来?
另外,有没有办法让Go编译器将汇编代码分离成单独的函数,带有标签?我知道有些函数可能内联,因此不会出现在汇编代码中。我所看到的只是一个几乎不可能理解的同质组装。
答案 0 :(得分:22)
您可以将输出重定向到这样的文件:
go tool 6g -S file.go > file.s
您可以使用-N:
禁用优化go tool 6g -S -N file.go
或者,您可以使用gccgo:
gccgo -S -O0 -masm=intel test.go
将生成test.s.您可以使用-O0 / 1/2/3来查看不同的优化。
答案 1 :(得分:15)
我不建议使用-S
的输出,因为Go链接器可以更改写入目标代码的内容。它确实可以让您了解发生了什么。
go汇编程序输出也非标准。
当我想这样做时,我总是使用objdump,这将为您提供一个很好的标准汇编程序输出。
例如x86 / amd64
objdump -d executable > disassembly
对于ARM(要使寄存器名称与Go使用相同)
objdump -M reg-names-raw -d executable > disassembly
答案 2 :(得分:9)
在生成的可执行文件上运行go tool objdump
。
要将输出限制为有趣的函数,请使用其-s
选项。
答案 3 :(得分:3)
将输出转储到文件:
go tool objdump EXECUTABLE_FILE > ASSEMBLY_FILE
如果你想包含源Go代码(假设你有一个有效的golang设置,并且你自己构建了可执行文件):
go tool objdump -S EXECUTABLE_FILE
为了使输出更容易看,我使用产生以下内容的small hacky wrapper(简而言之,它着色改变控制流的指令 - 蓝色用于跳转,绿色用于调用/返回,红色用于陷阱,紫色用于填充 - 并在无条件控制流跳转后添加新行):
如果你使用上面的包装器,你可能希望在管道到-R
时使用less
开关(或者通过将其添加到环境中,例如在.bashrc
中{{1} }}):
export LESS="$LESS -R"
或者,godbolt.org可能具有最易读的输出,并允许您在编译器(gc,gccgo)和版本之间轻松切换。
答案 4 :(得分:1)
我对其他答案有疑问,因为汇编产生的信息比我想要的要多得多,但仍然没有足够的细节。让我解释一下:它为内部导入的所有库提供了程序集,并没有提供我的代码所在的行(我的代码全部位于文件的底部)
以下是我从官方文档中找到的内容:
$ GOOS=linux GOARCH=amd64 go tool compile -S x.go # or: go build -gcflags -S x.go
文件:
package main
func main() {
println(3)
}
产地:
--- prog list "main" ---
0000 (x.go:3) TEXT main+0(SB),$8-0
0001 (x.go:3) FUNCDATA $0,gcargs·0+0(SB)
0002 (x.go:3) FUNCDATA $1,gclocals·0+0(SB)
0003 (x.go:4) MOVQ $3,(SP)
0004 (x.go:4) PCDATA $0,$8
0005 (x.go:4) CALL ,runtime.printint+0(SB)
0006 (x.go:4) PCDATA $0,$-1
0007 (x.go:4) PCDATA $0,$0
0008 (x.go:4) CALL ,runtime.printnl+0(SB)
0009 (x.go:4) PCDATA $0,$-1
0010 (x.go:5) RET ,
所以我所做的基本上是:
go tool compile -S hello.go > hello.s
它得到了我想要的结果!
答案 5 :(得分:0)