大致过程可分为以下4个步骤:
预处理->编译->汇编->链接
一、预处理
处理源代码文件以“#”开始的预编译指令。
1)展开宏定义
2)处理所有条件编译指令
3)处理#include预编译指令,递归地将被包含的文件插入进来
4)删除注释
5)添加行号和文件名标识,这样编译器产生错误和警告时才能显示行号
6)保留#pragma编译器指令
最终生成.i文件(c语言),或者.ii文件(C++语言)。
二、编译
1)扫描,将源代码输入到扫描器。
1)词法分析,将源代码的字符序列分割成一个个记号:关键字、标识符、字面量、特殊符号,如“(”是一个记号,变量i是一个记号。词法扫描工具:lex
2)语法分析,生成一棵结点为表达式的语法树,同时检查表达式是否合法,如括号不匹配、缺少操作符在这步可以检查出来。语法分析工具:yacc
3)语义分析,检查表达式是否有意义,如类型匹配、除0。为语法树中的所有结点标上类型。
4)源代码优化,如2 * 5,在这个期间就可以被确定,直接用10替换该表达式。在该步会将语法树生成中间代码(不包含数据的大小、变量地址、寄存器名字)。
5)目标代码生成,将中间代码生成目标机器代码。中间代码跟机器无关,目标机器代码跟机器有关,会标出字长、寄存器名字等。
6)目标代码优化,用位移代替乘法、删除多余的指令等。
最终会生成汇编代码文件。
三、汇编
将汇率代码转变为机器可以执行的指令。仅简单根据汇编指令和机器指令的对照表一一翻译,不做指令优化。
汇编器工具:as
四、链接
链接主要是处理各个模块相互引用的部分,使得它们能正确衔接。比如A模块引用了B模块的某个函数、C模块的某个全局变量等。
1)地址和空间分配
2)符号决议(也叫地址绑定)
3)重定位。有些全局变量或函数定义在其它库中,重定位找到它们的地址。