goc 专栏

goc 专栏

goc 是一个用 Go 写的 C 编译器,也带一个自研汇编器 goa。它做的事有点极端:

编译 C 代码,产物既不依赖 gcc,也不依赖 libc。

Windows 上产物是 PE32+,只导入 kernel32 / user32 / gdi32 这类系统 DLL;Linux 上产物是静态 ELF64,一条动态链接都没有,只走 syscall。两头都没有 msvcrt,也没有 glibc。

  foo.c ──[goc]──> foo.asm ──[goa]──> foo.exe    Windows PE32+,只导入 kernel32
              └─[goc -target linux]─[goa -f elf]─> foo    Linux ELF64,只用 syscall

源码在 GitHub:yafengabc/goc(MIT 许可,公开仓库,已发布 v0.1.1)。

这个专栏写什么

这个专栏分四块:

篇章内容
项目介绍goc 是什么、为什么这么做、架构怎么分的、和gcc 差在哪
上手教程从装工具链到写出第一个程序,含Windows GUI 和 Linux 双目标
体积实测同一份源码,goc / goc+LLVM 后端 / gcc 三方对比,全部自己跑出来的数字
项目状态已经能做什么、还不能做什么、正在进行什么,附一份测试失败怎么读的经验

另有一份开发笔记(content/goc/devnotes/),记录 bug 排查与修复的完整过程——不走弯路的那部分不进教程。

为什么值得写

goc 最有意思的地方不是"又写了个编译器"——那没什么新鲜的。而是它把取舍做得非常明白:

  • 不要 gcc:既然是 Go 写的编译器,那就纯到底,产物里不会出现任何 C 工具链的痕迹。
  • 不要 libc:那printf 怎么办?答案是把它当成一个真正的库函数写在 C 里,按需发射——只调用 putchar 的程序不会背上 printf的 512字节输出缓冲。
  • 不要假设 CPU 会变好:验证环节直接上QEMU(Unicorn),因为手写解释器只能证明"代码生成器和我的理解一致",证明不了程序真的对。

这三条决定了 goc 的整个形态。后面几篇会逐一展开。

现状速览

写这个专栏时的实测状态(2026-10-06):

  • 仓库 176 次提交,最新 tag v0.1.1(提交数会随迭代变化,以仓库为准)
  • run_tests.sh 在 Windows 11 + MSYS2 下跑出 pass=253 fail=0
  • 85 个C 示例,81 份 golden
  • 默认后端回归基线 gocregress pass=490 fail=0(82 example × 6 腿,2026-10-07 实测)
  • C99主体 + C11 类型系统 + C23 实用子集全部落地
  • _BitInt(N) 已实现,10 万位π 二分算法 100,011 位对拍 Python 大整数通过
  • 编译器本身便携:goc.exe 4.65 MB 单文件(只导入 kernel32);gocl.exe + libLLVM.dll 两个文件,拷到空目录、清空 PATH 也能编 C

阅读顺序

  1. 第0 章:为什么再写一个 C 编译器 —— 项目介绍与设计取舍(含"交付物只有一个文件"的便携性实测)
  2. 第 1 章:5 分钟跑起来 —— 装工具链,编译第一个程序
  3. 第 2 章:写第一个 Windows GUI 程序 —— 用 MessageBox 弹个框
  4. 第 3 章:体积实测 —— goc / LLVM 后端 / gcc 对比
  5. 第 4 章:项目状态与 roadmap —— 能做什么,不能做什么

开发笔记

笔记内容
变参窄整型丢符号性gocl 把经变参传的 32 位整型符号性丢掉:从误诊为"有符号除法"到定位为"8 字节参数槽没填满"的完整排查过程
把 gocld 变成真正的链接器让 goc -c 产出可重定位目标文件,gocld 成为可独立运行的链接器:字符串表 NUL、Elf64_Sym 漏 st_other、section 索引 1-based 等字节级坑
让 gocld 链接 .rsrc 资源节让 gocld 读入/合并/写出 PE 的 .rsrc:OffsetToData 文件偏移陷阱、ENTRY 高位标志、rd32 符号扩展等
gocl(LLVM 后端)踩过的坑libLLVM 的 FFI 约定、LLVM IR 畸形输出、COFF 重定位丢 addend 导致控制台全哑、printf 特化的架构缺口、PE 段级文件对齐、TLS 访问被当成 extern 全局、AT&T 前端操作数方向——共 64 条,每条含源码位置与实测
gocl 通用化与 Linux ELF 填坑从「连 goclib 都编不过」到「ls 在 Windows PE 与 Linux ELF 逐字节一致」的 13 个坑:goc 宏、syscall 桩第 4 参、brk identity 宏段错误、整数提升、跨平台一致性

⚠️ 说明:本专栏所有体积、测试数字均为在作者机器(Windows 11 + MSYS2)实测所得,标注了日期。goc 迭代很快,数字会变——但结论和方法相对稳定。