标签: CSAPP
从某种意义上来说,本书的目的就是为了帮助你了解当你在系统上执行 hello 程序时,系统发生了什么以及为什么会这样。
为了理解 hello 程序运行时发生什么,需要先对一个典型系统的硬件组织有一个大致的了解。如下图所示:
系统的硬件组成包括:
总线 贯穿整个系统的一组电子管道,负责在各个部件之间传递信息。总线通常被设计成传送定长的字节块,也就是 字(word)。I/O 设备 I/O 设备是系统与外部世界的联系通道。 每个 I/O 设备都通过一个 控制器 或 适配器 与 I/O总线相连。控制器与适配器之间的区别主要在于它们的封装方式。控制器是 I/O设备本身或者系统的主板上的芯片组,而适配器是一块插在主板插槽上的卡。
主存 主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据。 物理上,存储器是由一组 DRAM 芯片 组成。逻辑上,存储器是一个线性的字节数组,每个字节有唯一的地址。 处理器(CPU) 是执行存储在主存中指令的引擎,核心是 程序计数器(PC),在任何时刻,PC 都指向主存中的某条机器指令。此例子中的源代码如下:
#include<stdio.h> int main() { printf("hello world\n"); return 0; }每个程序都是由源代码开始的,源代码即文本文件。
只由 ASCII 字符构成的文件称为 文本文件,所有其他文件称为 二进制文件。
为了在系统上运行 hello.c 程序,每条 C 语句都必须被其他程序转化为一系列的 低级 机器语言 指令,然后按照一种称为 可执行目标程序 的格式打包起来,并以二进制磁盘文件的形式存放起来。 在 Unix 系统上,从源文件到目标程序的转化是由 编译器驱动程序 完成的。
编译过程如下:
Created with Raphaël 2.1.0 源代码(文本) 预处理(ccp) 编译器(ccl) 汇编器(as) 链接器(ld) 可执行目标文件(二进制)编译过程由四个阶段组成:
预处理阶段 预处理器(cpp)根据以字符 # 开头的命令(头文件、宏定义等),修改原始的 C 程序。比如 hello.c 中第一行的 #include<stdio.h> 命令告诉预处理器读取系统头文件 stdio.h 的内容,并把它直接 插入 程序文本中。结果就得到了另一个 C 程序 hello.i。编译阶段 编译器(ccl)将文本文件 hello.i 翻译成文本文件 hello.s,它包含一个 汇编语言程序。如下:
main: subq $8, %rsp movl $.LCO,