go语言 liunx编译 go语言的编译器_二进制文件


本文基于Go 1.13。

Go编译器是Go生态系统中的一个重要工具,因为它是将程序构建为可执行二进制文件的基本步骤之一。编译器的历程是漫长的,它已经用C语言编写,转移到Go,许多优化和清理将在未来继续发生。让我们发现它的高水平运作。

Phases

Go编译器由四个阶段组成,可分为两类:

  • 前端。此阶段从源代码运行分析,并生成源代码的抽象语法结构,称为AST。
  • 后端。第二阶段将把源代码的表示转换为机器代码,以及几个优化。


go语言 liunx编译 go语言的编译器_编译器_02


为了更好地理解每个阶段,让我们使用一个简单的程序:

package mainfunc main() { a := 1 b := 2 if true { add(a, b) }}func add(a, b int) { println(a + b)}

解析

第一阶段非常简单,并在文档中做了很好的解释:

在编译的第一阶段,源代码被标记化(词法分析),解析(语法分析),并且为每个源文件构造语法树。

词法分析器将是第一个为了标记源代码而运行的包。这是前一个示例标记化的输出:


go语言 liunx编译 go语言的编译器_编译器_03


去源代码标记化

一旦被标记化,将被解析并用于构建语法树。

AST转换

由于带有标志的命令,可以显示对抽象语法树的转换:go tool compile``-W


go语言 liunx编译 go语言的编译器_Go_04


生成AST的样本

此阶段还将包括内联等优化。在我们的示例中,该方法add可以已经内联,因为我们没有看到CALLFUNC该方法的任何指令add。让我们使用禁用内联的标志-l运行again命令:


go语言 liunx编译 go语言的编译器_编译器_05


AST生成后,它允许编译器使用SSA表示转到较低级别的中间表示。

SSA

在静态单赋值形式是阶段,其中优化会发生:死代码消除,删除不使用的分支,具有恒定值等替换一些表达式

由于GOSSAFUNC=main go tool compile main.go && open ssa.html生成HTML文档的命令将在SSA包中完成所有不同的传递,因此可以转储SSA代码:


go语言 liunx编译 go语言的编译器_二进制文件_06


生成的SSA位于“开始”选项卡中:


go语言 liunx编译 go语言的编译器_编译器_07


SSA代码

这里的变量a和b突出显示以及if条件将允许我们稍后查看这些行是如何更改的。该代码也向我们展示了编译器如何管理println是在4个步骤分解函数:printlock,printint,printnl,printunlock。编译器会自动为我们添加一个锁,并根据参数的类型调用相关方法来正确打印它。

在我们的示例中,由于编译时已知a并且b已知,编译器可以计算最终结果并将变量标记为不再需要。通行证opt将优化此部分:


go语言 liunx编译 go语言的编译器_二进制文件_08


v11这里已经被添加的结果替换,v4并且v5已被标记为死代码。该传递opt deadcode将删除该代码:


go语言 liunx编译 go语言的编译器_二进制文件_09


关于if条件,opt阶段将常量标记true为死代码,然后将被删除:


go语言 liunx编译 go语言的编译器_go语言 liunx编译_10


常量布尔值被删除

然后,另一个过程将通过将不必要的块和条件标记为无效来简化控制流程。这些块稍后将被另一个专用于死代码的传递删除:


go语言 liunx编译 go语言的编译器_Go_11


不必要的控制流程被删除

完成所有传递后,Go编译器现在将生成一个中间汇编代码:


go语言 liunx编译 go语言的编译器_编译器_12


go asm代码

下一阶段将生成机器代码到二进制文件中。

机器代码生成

main.o在我们的示例中,编译器的最后一步是生成目标文件。从该文件中,现在可以使用objdump执行相反过程的工具对其进行反汇编。这是Grant Seltzer Richman创建的一个很好的图表:


go语言 liunx编译 go语言的编译器_go语言 liunx编译_13


go 工具编译


go语言 liunx编译 go语言的编译器_go语言 liunx编译_14


go 工具objdump

您可以在“ Dissecting Go Binaries ”中找到有关目标文件和二进制文件的更多信息。

生成目标文件后,现在可以使用该命令go tool link将其直接传递给链接器,您的二进制文件最终将准备就绪。

翻译自:https://medium.com/a-journey-with-go/go-overview-of-the-compiler-4e5a153ca889