编译的过程可以分解为四个步骤,分别是预编译、编译、汇编和链接。
预编译是将源代码文件如拓展名为.c、.cpp或.cxx预编译成一个.i或.ii的文件。预编译过程主要处理那些源代码中的“#”开始的预编译指令。比如“#include”、“#define”等,主要的处理规则如下:
(1)删除#define并进行文本替换
(2)处理#if、#endif、#elif
(3)递归展开#include
(4)删除注释
(5)添加行号和文件标识
(6)保留#program
经过预编译后的.i文件不包含任何宏定义,因为所有的宏已经被展开,并且包含的文件也已经被插入到.i文件中。所以当我们无法判断宏定义是否正确时,可以查看预编译后的文件来确定问题。
编译过程就是把预编译处理完的文件进行一系列词法分析、语法分析、语义分析和优化代码,最后生成汇编指令的过程,将预编译的.i文件编译成.s文件。
汇编是将代码转变成机器可以执行的指令,每一条汇编语句几乎都对应一条机器指令。汇编过程需要处理强符号、符号表和指令段(虚假的地址和偏移)。汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译就可以了。汇编后产生.o文件。
链接的主要内容就是把各个模块之间相互引用的部分处理好,使得各个模块之间能够正确的衔接。链接过程主要包括了合并段和符号表、符号解析、分配地址和空间、和符号重定位。符号的重定位只对所有文件的global符号进行处理,local的符号不做任何处理,处理好后会分配虚拟内存地址,链接完成之后产生可执行.exe文件。
最后,我们就可以运行可执行文件。运行过程:(1)建立虚拟地址空间和物理内存的映射(创建映射结构体PCB),创建页目录、页表(建立虚拟空间到物理内存的映射)(2)加载指令和数据 load(3)把程序的入口地址写入下一行指令寄存器。
虚拟地址空间布局