CSAPP 阅读笔记 (1)

CSAPP 阅读笔记 (1)

第 1 章:计算机系统漫游。这一章通过研究 “hello, world” 这个简单程序的生命周期,介绍计算机系统的主要概念和主题。

本章通过讲述如下的一个简单的源代码从编译到运行过程中发生的事情阐述了计算机以及操作系统工作的原理以及其中的一些重要的特性。

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
printf("hello, world\n");
return 0;
}

编译系统

我们通常说的编译(也就是输入 gcc hello.c -o hello 再回车)实际上发生了四件事情:预处理,编译,汇编,链接。相应的编译系统也包括预处理器、编译器、汇编器和链接器。

预处理主要是文本的替换,比如 C 中以 # 开头的宏命令。

编译是从高级语言转换为汇编语言。笔者之前做编译原理的课设在这里花了很大功夫,虽然大部分都是机械性的工作。

汇编总是让人忽略,以至于我总是习惯性地说预处理、编译、链接。实际上汇编这一步才是真正完成了从文本文件到二进制文件的跨越。这个阶段的产物可重定位目标程序 (relocatable object program) 算是我经常听说但是没有深究的名词。但实际上,这个概念还是很复杂且重要的。我们将在链接阶段讲述。

链接阶段是将多个可重定位目标程序合并的过程。这里的链接本质就是 “重定位”。可重定位目标程序之所以被称为 “可重定位” (Relocatable),是因为它内部的代码和数据没有固定的内存绝对地址,链接器可以根据需要把它们重新放置(Relocate)到内存的任何合法位置。

如果你尝试用 objdump -d hello.o 命令查看,会发现以下内容:

1
2
3
4
5
6
7
0000000000000000 <main>:
0: 48 83 ec 08 sub $0x8,%rsp
4: bf 00 00 00 00 mov $0x0,%edi
9: e8 00 00 00 00 call e <main+0xe>
e: b8 00 00 00 00 mov $0x0,%eax
13: 48 83 c4 08 add $0x8,%rsp
17: c3 ret

这里 e8 00 00 00 00 call e <main+0xe> 实际上是想要调用 puts 库函数,但是此时并不知道 puts 的位置,所以只能用全 0 来占位。

链接器根据可重定位目标程序中的重定位条目表来给这些占位填入真实的地址。但是请注意,这里的虽然称作真实的地址,但是实际上还是虚拟地址,而不是物理地址。

如果你尝试用 objdump -r hello.o 命令,会发现以下内容:

1
2
3
4
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000005 R_X86_64_32 .rodata.str1.1
000000000000000a R_X86_64_PLT32 puts-0x0000000000000004

这里的 000000000000000a 正是上文占位的地址的偏移量,.text 的重定位条目表告诉链接器这里实际要填入 puts 的偏移量减 4(PC 相对寻址)。不过这里是动态链接,并不是真正的地址,这部分我也还没有完全弄懂,后面的章节应该会涉及。

此外还要说的是,我的环境下直接按照书上的命令运行会由于编译器版本以及优化等级的问题导致结果不同,需要使用 gcc -Og -fno-pie -fcf-protection=none 参数。


CSAPP 阅读笔记 (1)
http://yoursite.com/2026/09/03/CSAPP-阅读笔记-1/
作者
99_wood
发布于
2026年9月3日
许可协议