编译与链接
被隐藏的过程
$gcc hello.c |
第一步|预编译
gcc -E hello.c -o hello.i #C |
- 删除#define,展开对应的宏定义
- 处理条件预编译指令,#if,#ifdef,#else等
- 递归讲#include包含文件插入对应位置
- 删除注释,添加行号,文件明标识,方便调试
- 保留下面编译用的#prama编译器指令
第二步 | 编译
gcc -S hello.i -o hello.s |
对预处理的文件词法,语法,语义分析,并优化
第三步 | 汇编
as hello.s -o hello.o #as 是汇编器 |
从汇编代码到机器指令
第四步 | 链接
简单来说:链接器是将很多的目标文件(.o)链接起来
编译 | 了解一下
array[index]=(index+4)*(2+6);
词法分析
扫描器扫描分割,比如array是标识符,[是左括号等等,C语言的宏展开交给独立的预处理器。
语法分析
语法分析器已表达式为节点,构建语法分析树。
语义分析
静态语义分析:声明,类型匹配,类型转换
源码优化&目标代码生成及优化
源码优化:比如2+6被优化成8,目标代码生成及优化:删除多余指令,是有合适的寻址方式等等。
链接 | 略懂略懂
历史久远 | 从纸带说起
上图就是纸带,左侧是行号,试想要是插入指令在某一行,对应的在其中的目标地址就要全部重新算,这个过程即是重定位,由于地址是数字,变化会很复杂,所以才去地址符号化策略,譬如’foo’,无论实际地址如何变化,在编译时会重新计算’foo’地址,将引用到’foo’的指令修正到正确地址;
静态链接 | 模块拼装
重定位 | 地址
比如a模块用b模块的var变量,var=0x1,编译a时,var的地址为0x00 00 00 00(因为不知道实际地址),之后链接器会讲正确地址覆盖0x00 00 00 00,每个修正的地方叫重定位入口。