主要查看了 CSAPP
从 C 程序到可执行文件, 总共经过了这样几个部分:
1. Preprocess
在C语言中#
开头的预处理指令对源代码进行不同形式的转换
当我们使用C语言编写程序时
生成纯C文件的过程gcc -E
来执行-E
参数表示只进行预处理test.c
的源文件
复制代码gcc -E test.c -o test.i
其中-o
参数指定了输出文件的名称为 test.i
(也可以是.c格式的)
生成纯C文件的主要目的是方便调试和分析源代码
![hello.i文件居然有550行](https://naturalifica.oss-cn-nanjing.aliyuncs.com/~/Users/wuchentian/SoloLearning/Blog/source/imgs/image-20230427164042332.png)
上图是对 hello.c 程序进行操作, 生成的纯C中间文件居然多达550行
.i 格式 和 .c 格式有什么区别
.i
格式和 .c
格式都是C语言的源文件格式
- 后缀不同
: .i
是纯C文件的后缀 而, .c
是包含了所有源代码和预处理指令的源文件的后缀。 - 是否经过预处理
: .i
文件是经过预处理器预处理后的纯C文件 而, .c
文件则包含了所有的源代码和预处理指令 在生成。 *.i
文件时 预处理器会对源代码中的预处理指令进行展开并替换为相应的代码, 同时还会去除注释和空行等无用信息, 最终得到一个只包含有效C代码的文件, 。 - 用途不同
: .c
文件是编译器直接使用的源文件 其中包含了所有需要编译的代码和预处理指令, 而。 .i
文件通常用于调试和分析源代码 它已经去除了预处理指令和无用信息, 方便用户查看和分析纯C代码, 。
总之.i
和 .c
文件都是C语言的源文件格式.i
文件是经过预处理器处理后的纯C文件.c
文件则包含了所有的源代码和预处理指令.i
文件一般用于调试和分析源代码.c
文件是编译器直接使用的源文件
2. Compile
3.
链接
在计算机科学中
在链接的过程中
- 符号解析
Symbol Resolution( ) 将目标文件中使用到的未定义符号与其他目标文件中定义的符号进行匹配: 并将它们连接起来, 。 - 重定位
Relocation( ) 由于目标文件中的地址空间与最终可执行文件中的地址空间可能会不同: 因此链接器需要对目标文件中的一些地址进行修正, 以便使它们在最终可执行文件中能够正确地访问目标对象, 。 - 优化
Optimization( ) 链接器还可以对目标文件中的代码进行优化: 以提高最终程序的性能和效率, 。
在不同的操作系统和编程语言中
链接分为静态链接和动态链接两种类型
静态链接
静态链接是指将所有目标文件和库文件直接链接到最终生成的可执行文件中的过程
具体来说做了两件事:
- 空间和地址分配
- 符号解析与重定位
优点
- 可以在不安装任何其他软件的情况下
将可执行文件直接复制到其他计算机上运行, 。 - 执行速度相对较快
因为所有代码和数据都已经被复制到同一个文件中, 。
缺点
- 可执行文件比较大
包含了所有需要的库代码和数据, 因此占用的存储空间较大, 。 - 如果多个程序使用同一份库文件
则会出现代码重复的情况, 浪费存储空间, 。 - 如果库文件更新了
需要重新链接并重新编译整个程序, 。
动态链接
动态链接是指在程序运行时才从共享库文件 (Shared Library) 中加载所需的函数和数据的链接方式
具体来说有四个步骤:
- 动态链接器自举
- 装载共享对象
- 重定位与初始化
- 转交控制权
优点
- 可执行文件相对较小
因为它只包含了函数名等链接信息, 而没有库代码和数据, 。 - 不同的程序可以共享同一份库文件
节省存储空间, 。 - 如果库文件更新了
不需要重新编译整个程序, 只需要替换共享库文件即可, 。
缺点
- 程序在运行时需要加载共享库文件
会增加启动时间和内存使用量, 。 - 执行速度相对静态链接较慢
因为需要从共享库中加载函数和数据, 。
总之