编译链接原理

1.预编译阶段

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

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

2.编译阶段

编译阶段将高级语言转成汇编代码并生成.s文件,.s文件属于文本文件。要处理的主要包括:
词法分析:利用扫描器将原代码的字符序列分割成一系列记号(关键字、标识符、特殊符号等)并标记。将标识符放在符号表中,常量在文字表中。
语法分析:用语法分析器对记号进行语法分析并产生语法树(以表达式为节点的树),是无关上下文的。
语义分析:搞清楚表达式的意思,是干什么的。编译器可以做到的是静态语义,也就是在编译期可以确定的语义。语义分析之后,整个语法树的表达式都被标识了类型。
静态语义:通常包含声明和类型的匹配,类型的转换等。
动态语义:像比如0作为除数就是一个运行期的语义错误。

3.汇编阶段

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

4.链接

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

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

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

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

Makefile 是一个用于自动化构建的工具,通过 Makefile 可以定义编译链接的规则,以及依赖关系。它使用了一种称为“依赖关系图”的数据结构来管理目标文件之间的依赖关系,并根据这些依赖关系来确定需要重新编译的文件。 在 Makefile 中,我们可以定义目标(Target)、依赖关系(Dependencies)和命令(Commands)。目标是我们要生成的文件,依赖关系是指生成目标文件所需要的其他文件,而命令则是生成目标文件的具体操作。 编译链接原理如下: 1. 编译阶段:在编译阶段,Makefile 根据目标文件的依赖关系确定需要重新编译的文件,并执行相应的编译命令。编译命令将源代码转换为目标文件(通常是以 .o 结尾的文件)。这些目标文件包含了编译器将源代码转换为汇编代码、然后转换为机器码的过程。 2. 链接阶段:在链接阶段,Makefile 根据目标文件之间的依赖关系确定需要重新链接的文件,并执行相应的链接命令。链接命令将多个目标文件和库文件进行合并,生成最终的可执行文件。链接的过程包括符号解析、重定位和库文件处理,具体原理请参考前面回答的问题。 Makefile 通过检查目标文件和依赖文件的时间戳来确定是否需要重新编译链接。如果目标文件不存在或者目标文件的依赖文件的时间戳比目标文件的时间戳要新,那么 Makefile 就会执行相应的编译链接命令。 通过 Makefile 的自动化构建,我们可以方便地管理复杂的项目,减少重复编译链接的工作量,并确保代码的正确性和一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值