4.5.1 类型检查逻辑 - 包加载器
go 编译器一次编译的最大单元是一个包,输出的结果叫着对象文件(Object File),go 定义了自己的对象文件格式,并以.a
或者.o
为后缀存在于文件系统中。在$GOROOT/pkg/$OS_$ARCH/
目录下就包含了所有标准库的对象文件,例如 linux 系统该目录为:$GOROOT/pkg/linux_amd64
.
加载器在编译阶段解决包依赖问题,其任务就是通过包名找到对应的对象文件,然后将其解析成为上文提到的Package对象。加载器可以有各种实现,其接口定义在文件$GCROOT/compile/internal/types2/api.go
中:
两个接口的区别是方法ImporterFrom
通过指定目标目录的方式来支持vendor 机制, 而Importer
无法支持,保留Importer
接口是为了兼容性考虑,ImportMode 当前没有用途。加载器的实现在$GCROOT/compile/internal/noder/import.go
中,抛开具体细节,其代码框架为:
可见Import
只是简单地调用ImportFrom
方法,而后者负责整个加载解析逻辑。加载器配置在Config中,并在类型检查的入口函数check2()
中进行初始化,该函数在文件$GCROOT/compile/internal/noder/irgen.go
中。
go 编译过程的最后一件事情就是将编译结果导出成对象文件,所以包加载器只是该过程的一个逆操作,当前加载器的实现也是 Go 编译器团队在重写类型检查器的过程中临时的一个实现,后续可能会修改。
对于对象文件的详细格式、导出逻辑与加载逻辑我们没有必要深挖细刨,只需要掌握如下要点即可:
对象文件是二进制格式文件,是编译器的输出,链接器的输入
对象文件分为不同的块(Section)来组织数据,例如数据块,代码块,调试信息块等
对象文件内包含重定位(Relocation)信息,链接器在将多个对象链接在一起时,主要工作就是为需要重定位的数据或者指令规划内存地址
go 是静态链接语言,在生成可执行文件时,链接器会将所有依赖的包链接在一起,形成一个独立的可执行文件
可以通过工具
go tool objdump
来查看对象文件或者可执行文件的内容
最后更新于