易于阅读Golang装配输出?

时间:2014-05-21 17:20:15

标签: assembly go

我有兴趣检查标准Go编译器的x86汇编输出,看看我的代码是否真的被转换为合理有效的汇编代码;希望通过分析和检查程序集输出,我可以得到一个线索,我应该在哪里/如何重写我的Go代码以获得最佳性能。但是当我使用-S标志检查代码时,Go吐出一团糟!我想要两件事:

  1. 有没有办法让Go编译器将汇编输出转储到文件中,而不只是在终端上打印出来?

  2. 另外,有没有办法让Go编译器将汇编代码分离成单独的函数,带有标签?我知道有些函数可能内联,因此不会出现在汇编代码中。我所看到的只是一个几乎不可能理解的同质组装。

6 个答案:

答案 0 :(得分:22)

  1. 您可以将输出重定向到这样的文件:

    go tool 6g -S file.go > file.s
    
  2. 您可以使用-N:

    禁用优化
    go tool 6g -S -N file.go
    
  3. 或者,您可以使用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(简而言之,它着色改变控制流的指令 - 蓝色用于跳转,绿色用于调用/返回,红色用于陷阱,紫色用于填充 - 并在无条件控制流跳转后添加新行):

example output of go-objdump 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)

我发现 Mac 用户使用 XCode 开发工具的最简单方法是使用 otool

$ otool -tV myGoProgramBinary to disassemble

Source