编译和链接-介绍
编译和连接
过程:预编译,编译,汇编,连接
预编译
将.c文件和.h头文件被编译为一个.i文件,是一个编译单元。
预编译主要是处理一些预编译指令,如将#include的文件放入.c文件等,主要的处理规则:
<li>#define替换,展开所有宏定义。</li>
<li>处理条件编译指令,如#if等。</li>
<li>处理#include指令,将被包含的文件插入到指令位置(递归,.h文件中也可有include)。</li>
<li>删除注释</li>
<li>添加行号和文件名标识,以便编译器调试。</li>
编译和汇编
通过词法分析、语法分析、语义分析及优化产生相应的汇编代码文件。
词法分析:扫描器扫描源代码,根据有限状态机等算法可以识别代码每个单词或符号的物理含义。
语法分析:根据词法分析获得的代码的物理记号,产生语法树。语法书是以表达式为节点的树。进完成表达式语法层面的分析,并不了解这个语句的真实含义。
语义分析:语义分析分析每个表达式的类型。
汇编将汇编代码文件转化为机器可执行的指令(机器码),汇编过程就是一个简单的翻译器。汇编输出的文件叫目标文件(Object File),他是一个通向可执行文件的里程碑。
编译器会将整个语法树转为中间代码,它是语法书的顺序表示。它与机器和运行环境无关,比较常见的有三地址码: x=y op z。根据三地址码可以进行一些优化,比如将常数运算直接求出结果。
基于中间代码,将编译器分为前端和后端。前端生成与机器无关的中间代码,后端根据中间代码生成目标机器代码,后端与机器和运行环境有关。
中间代码通过代码生成器基于具体的机器生成目标代码。这时会出现问题:变量的地址没有确定。如果变量的定义在同一个编译单元,编译器可以为其分配空间,但是如果变量在其他编译模块呢?
这时候就需要链接!
综上所述,编译器是将源代码编译为一个未链接的目标文件,连接器最终将不同的目标文件链接为可执行文件。
链接
当一个代码项目非常大时,我们希望将其分割成不同模块,对这些模块进行编译后,然后通过连接将其拼装。连接主要是把一些指令对其符号地址的引用加以修正。链接过程主要包括:地址和空间分配,符合决议和重定位。
连接可以看成以下过程:当一个模块使用另一个模块的函数foo()时,运行调用时需要知道确切的地址,但在编译阶段因为foo不在该编译单元,所以编译时无法知道确切地址,因此编译器先留出位置,等到连接阶段重新修正为真正的地址。(全局变量机制相同)