The Little Go Compiler Book
1 · 0. 引言#
在日常写代码时,我们面对的是变量、函数、类型、接口这些适合人理解和维护的抽象;但机器真正能够执行的,只有更低层的指令、寄存器和内存操作。
编译器正是连接这两层世界的桥梁。它把人类可读、可维护的源代码,逐步转换成机器能够理解和执行的低层表示,最终生成可运行的程序。
从这个角度看,编译本质上就是一个逐步降低抽象层次的过程。
这本小册子不打算系统讲编译原理,也不打算从零实现一门语言,而是沿着 Go 官方工具链的真实实现,建立一条从 .go 源码到可执行文件的完整心智模型。
之所以选择 Go 编译器,是因为它足够工程化:语言设计相对克制,编译速度长期被高度重视,代码中也保留了比较清晰的阶段划分。 当然,真实工业编译器并不会像教材里的流水线那样完全线性,很多分析、改写和优化会分散在不同阶段,这恰好也是这本小册子想讲清楚的部分。
2 · 1. go build 如何构建出可执行文件#
go build -o main main.go
./main
-x -n 打印出底层执行的命令;-p 1 限制非并发执行;
引入底层工具compile asm pack link
2.1 · 1.1. compile 做了什么#
引出a归档文件概念
关于go代码到a文件,引入编译的几个阶段:前端(语义分析)-> 中端(优化)-> 后端(生成机器指令)
2.2 · 1.2. asm 做了什么,pack 做了什么#
引出go汇编概念,引出o目标文件概念
pack 对 a/o 文件操作
2.3 · 1.3. link 做了什么#
引入重定位概念,引入可执行文件,
2.4 · 1.4. 最终的可执行文件,ELF格式#
引入OS装载执行
2.5 · 1.5. 整条链路连起来#
3 · 2. compile 编译器整体#
前端:AST,类型检查 中端:IR,优化(逃逸分析、去虚拟化),walk(降级更底层原语) 后端:SSA,优化(死代码),生成机器指令
4 · 3. 前端:token、ast、类型检查#
类型检查做了什么?
5 · 4. IR:编译器内部表示#
为什么需要IR? IR如何表示的?
6 · 5. 高层分析与优化#
内联、逃逸分析、去虚拟化
逃逸分析:确保指向栈内变量的指针,一定在栈内使用; 便于复制栈。
7 · 6. walk:降级与改写#
去语法糖、转化为运行时函数调用
8 · 7. SSA:后端优化的基础设施#
9 · 8. 从 SSA 到机器码#
机器无关、机器有关
指令选择、寄存器分配
10 · 9. 链接:link#
重定位、ELF、入口点、OS加载
11 · 10. 选一个例子,完整走一遍#
make slice 应该这些步骤都能覆盖到