在学C语言的时候,编译链接的过程已经接触过了,但是其实了解的不是很全面,现在学到了C++,更能从底层了解编译链接过程做了哪些事,比如编译时期的静态绑定,运行时期的动态绑定,理解了编译链接的过程和函数地址空间的变化才能延伸学习其他内容。
编译链接过程主要分为:预编译,编译,汇编,链接
预编译:将源文件.c/.cpp 预编译生成 .i 文件
- 展开所有的宏定义,消除“#define”;
- 处理所有的预编译指令,比如#if、#ifdef等;
- 处理#include预编译指令,将包含文件插入到该预编译的位置;
- 删除所有的注释“/**/”、"//"等;
- 添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息以及错误提醒;
- 保留所有的#program编译指令,原因是编译器要使用它们;
注意一点:预编译期间,并没有做相关的安全性检测,代码的漏洞是看不出来的
那么就是编译阶段了:将预编译的 .i 文件编译成 .s 文件
-
首先词法分析,就是将源文件的字符序列划成一系列记号,同时生成符号表、文字表等,通过一个程序(lex程序)将输入的字符串分割成记号;
-
然后是语法分析,词法分析好的记号,会被语法分析器分析产生语法树,然后通过规则一步步走到语法树的尾结点,如果中途规则不对,就会产生编译错误;
-
最后就是语义分析,完善一些语法阶段没有分析定义的符号,比如乘法,加法之类的的符号就是在语义阶段赋予的意义。
语义分析分为静态语义和动态语义,静态语义通常包括声明,类型的定义和转换;动态语义是在运行阶段才能确定。
汇编阶段的任务看似比较简单:
将.s 文件生成可重定位的二进制文件(.obj)
说白了就是把代码二进制化,让电脑能看懂,符号表就是在此时生成的。
然后是链接阶段:链接阶段分为两步;
第一是将各个段合并,进行段偏移和调查段长度大小,然后合并符号表,进行符号解析;
所谓符号解析就是将所以.obj文件中对符合引用的地方都要找到其定义的地方。
第二步就符号重定位,就是将符号分配的虚拟地址写回原先未分配正确地址的地方,最终生成可执行文件。
最终运行可执行文件即可生成结果,这就是编译链接的全过程,就简简单单的几秒,其实做了那么多事情,真的越学越感慨这其中的奥秘和难度啊。