【C++】编译链接运行原理

1.预编译(gcc -E hello.c -o hello.i)

预编译阶段主要处理那些源代码文件中的以“#”开头的预编译指令,并生成.i文件,.i文件属于文本文件 。处理的主要包括:

  • 删除#define并进行文本替换
  • #if #endif  #elseif
  • 递归展开#include
  • 删除注释
  • 添加行号和文件标识
  • 保留#pragma

2.编译(gcc -S hello.i -o hello.s)

编译阶段将高级语言转成汇编代码并生成.s文件,.s文件属于文本文件。要处理的主要包括:

  • 词法分析。利用扫描器将原代码的字符序列分割成一系列记号(关键字、标识符、特殊符号等)并标记。将标识符放在符号表中,常量在文字表中。
  • 语法分析。用语法分析器对记号进行语法分析并产生语法树(以表达式为节点的树),是无关上下文的。
  • 语义分析。搞清楚表达式的意思,是干什么的。编译器可以做到的是静态语义,也就是在编译期可以确定的语义。语义分析之后,整个语法树的表达式都被标识了类型。

【C++】编译链接运行原理

【C++】编译链接运行原理

静态语义:通常包含声明和类型的匹配,类型的转换等。

动态语义:像比如0作为除数就是一个运行期的语义错误。

3.汇编(gcc -c hello.s -o hello.o)

汇编阶段主要是将编译阶段生成的汇编代码编程二进制的机器语言并生成.o文件,称为目标文件,.o文件属于二进制文件。主要做的就是翻译指令。在这一阶段有生成中间文件,中间文件经过代码生成器优化(比如选择合适的寻址方式、使用位移代替乘法运算、删除多余的指令等)后才生成目标文件。中间文件使得编译器分为前端和后端,前端负责产生与机器无关的中间代码,后端(包括代码生成器和目标代码优化器)将中间代码转换成目标机器代码。

【C++】编译链接运行原理

4.链接

在前面,每个文件都是单独编译的,但是在编译链接之后,不论源文件多或少,最终都只会生成一个可执行文件。而链接阶段就是将一个或多个目标文件链接成一个可执行文件。C/C++模块之间通信的方式:函数调用和模块间的变量访问,而这两个方式都是需要知道函数或者变量的地址。链接主要就是将各个模块相互连接的部分处理好。链接有静态链接和动态链接。主要处理包括:

  • 合并各个段和符号表。
  • 符号解析
  • 分配地址和空间
  • 符号重定位

静态链接:静态链接是以目标文件为单位,如使用了静态库中的printf函数,将会把含有printf函数的整个目标文件一起链接进来,也会有很多不用的函数,而且只要修改了库函数就要重新编译链接。不仅会浪费空间,更新也会麻烦。

【C++】编译链接运行原理

动态链接:动态链接就是把程序的模块相互划分开来,形成独立的文件,而不再静态的链接在一起,把链接这个过程推迟到了运行时再进行。动态链接解决了静态链接的浪费空间的缺点,但是速度比较慢。