【程序员的自我修养】系列总览:一份跨越 12 年的工程师内功心法

程序员的自我修养 · 系列总览

为什么你写的 printf("Hello World\n") 能跑到屏幕上?

这 15 篇文章,会沿着这条问号,把答案从 CPU 寄存器、一路挖到内核的 sys_write

0. 为什么要写这个系列

2009 年,俞甲子、石凡、潘爱民三位作者把”链接、装载与库”这四个字写成了一本薄书。12 年过去了,C++ 多了 std::move、Rust 已经登堂入室、Web 后端换了一茬又一茬——但程序从 .c 到屏幕的这条链路,没有变过

计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。“ —— Butler Lampson

这个系列就是要把这十几个中间层一层一层剥开:从 cpp → cc1 → as → ld → execve → ld.so → syscall 直到 tty_write 把字符送到显示器。

读完这 15 篇,你会获得三种工程师内功

能力对应文章直接收益
看懂 linker error 报的”undefined reference to…”是哪一层在作怪02、04、05、07调试编译问题不再靠 Google 盲搜
解释 ldd 输出的 .so 关系,理解”动态链接”为何要 -fPIC05、07、08、15排查 ABI 兼容性问题不再玄学
理解 malloc 返回的指针为什么有时要 mmap、有时要 brk09、10调优内存占用、性能瓶颈分析
明白 pthread_create 背后内核做了什么、用户态做了什么12多线程 bug 排查有据可循
看懂 gdb 输出的栈帧、寄存器,理解 core 文件的每一个字节13、14生产环境 crash 定位速度 10x

1. 全书脉络

graph TB
    A["第1章<br/>温故而知新"] --> B["第2章<br/>编译和链接"]
    B --> C["第3章<br/>目标文件"]
    C --> D["第4章<br/>静态链接"]
    D --> E["第5章<br/>Windows PE/COFF"]
    E --> F["第6章<br/>装载与进程"]
    F --> G["第7章<br/>动态链接"]
    G --> H["第8章<br/>Linux 共享库"]
    H --> I["第9章<br/>Windows 动态链接"]
    I --> J["第10章<br/>内存"]
    J --> K["第11章<br/>运行库"]
    K --> L["第12章<br/>系统调用"]
    L --> M["第13章<br/>运行库实现 MiniCRT"]

    style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
    style B fill:#E8D5F5,stroke:#CE93D8,color:#333
    style C fill:#FFDAB9,stroke:#FFAB76,color:#333
    style D fill:#B5EAD7,stroke:#80CBC4,color:#333
    style E fill:#FFF9C4,stroke:#F9A825,color:#333
    style F fill:#FFB3C6,stroke:#F48FB1,color:#333
    style G fill:#C7CEEA,stroke:#9FA8DA,color:#333
    style H fill:#E8D5F5,stroke:#CE93D8,color:#333
    style I fill:#FFDAB9,stroke:#FFAB76,color:#333
    style J fill:#B5EAD7,stroke:#80CBC4,color:#333
    style K fill:#FFF9C4,stroke:#F9A825,color:#333
    style L fill:#FFB3C6,stroke:#F48FB1,color:#333
    style M fill:#C7CEEA,stroke:#9FA8DA,color:#333

2. 系列目录(15 篇)

#文章对应书中章节核心问题状态
01温故而知新Ch1Hello World 怎么从源码变成屏幕上的字符?
02编译和链接Ch2gcc 背后到底跑了哪 4 个工具?
03目标文件里有什么Ch3.o 文件为什么不是乱码?它分几段?
04静态链接Ch4两个 .o 文件是怎么拼成一个 a.out 的?
05Windows PE/COFFCh5Windows 的 .exe 跟 Linux 的 ELF 有什么本质区别?🆕
06可执行文件的装载与进程Ch6execve 之后,内核做了什么?
07动态链接Ch7为什么要动态链接?.so 何时被加载?
08动态链接的实现Ch7 实现GOT/PLT/延迟绑定的代码长什么样?
09Linux 共享库的组织Ch8ldconfig 做了什么?SONAME 是什么?
10内存管理Ch10malloc 背后是 brk 还是 mmap
11运行库Ch11C++ 全局对象构造函数什么时候被调?
12系统调用Ch12int 0x80syscall 有什么区别?
13线程库补充NPTL 线程的栈、TCB、TLS 在哪?
14调试补充gdb 怎么在另一个进程里改我的内存?
15Windows 下的动态链接Ch9DLL 加载、IAT 表、DLL 注入是怎么回事?🆕

✅ = 已发布(已增强) 🆕 = 本次新增

3. 阅读建议

你是谁推荐路径预计耗时
计算机系大二/大三学生01 → 02 → 03 → 04 → 06 → 07 → 10 → 128-10 小时
C/C++ 后端工程师03 → 04 → 07 → 08 → 10 → 11 → 12 → 136-8 小时
面试突击(系统底层)03 → 04 → 07 → 09 → 10 → 124-5 小时
嵌入式 / OS 开发01 → 02 → 06 → 10 → 12 → 136-8 小时
想完整读一遍01 → 02 → … → 1520-25 小时

4. 配套实验环境

本系列所有代码均在以下环境验证:

1
2
3
4
5
6
7
8
9
10
$ uname -a
Linux x86_64 #1 SMP Debian 6.1.0
$ gcc --version
gcc (Debian 12.2.0) 12.2.0
$ ld --version
GNU ld 2.40
$ readelf --version
GNU readelf 2.40
$ gdb --version
GNU gdb 13.2

Windows 章节(05、15)使用:

1
2
3
4
Windows 10 22H2 x64
Visual Studio 2022 17.5
cl.exe 19.35
dumpbin.exe (VS 自带)

5. 一句话总结

一个程序,从 .c 到屏幕,走了 12 层间接。这 15 篇文章就是那 12 层的解剖图。


下一篇 → 第一章:温故而知新

📖 完整 15 篇目录(点击展开)
  1. 第一章:温故而知新 ← 系列起点
  2. 第二章:编译和链接
  3. 第三章:目标文件里有什么
  4. 第四章:静态链接
  5. 第五章:Windows PE/COFF 🆕
  6. 第六章:可执行文件的装载与进程
  7. 第七章:动态链接
  8. 第八章:动态链接的实现
  9. 第九章:Linux 共享库的组织
  10. 第十章:内存管理
  11. 第十一章:运行库
  12. 第十二章:系统调用
  13. 第十三章:线程库
  14. 第十四章:调试
  15. 第十五章:Windows 下的动态链接 🆕