1 笨笨的孩子慢慢学stay hungry stay foolish 2 学习,思考,实践,改变

0%

编译、链接和生成的目标文件

编译、链接和生成的目标文件

基础编译链接知识

gcc编译C程序经过预处理,编译,汇编,链接。

GNU编译器套装(英语:GNU Compiler Collection,缩写为GCC),指一套编程语言编译器。

预编译

image-20220925194018558

预处理就是展开所有的头文件、替换程序中的宏、解析条件编译并添加到文件中。

c语言中条件编译相关的预编译指令,包括 #define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined。

删除所有的注释。添加行号和文件名标识,保留所有的 #pragma 编译器指令。

gcc -E test.c -o test.i preprocessing 显示的预处理之后的源代码。

编译

编译:编译是将经过预编译处理的代码编译成汇编代码。对预处理后的.i文件进行词法分析,语法分析,语义分析及优化等等。

这里就是编译原理会涉及的东西,扫描,词法(有限状态机)语法(语法树 yacc)语义分析(对语法树的表达式标识类型),中间语言生成(IR 三地址码等),源码优化(优化寻址等),代码生成和目标代码优化等等。

gcc -S test.i -o test.s 可直接对生成的test.i文件编译,生成汇编代码

/usr/lib/gcc/x86_64-linux-gnu/5.4.0/cc1 test.c 现在版本的gcc将预编译和编译俩步骤合并到了一起,cc1这个程序。

汇编

将汇编代码转变为机器可以执行的指令,就根据汇编指令和机器指令的对照表去一一翻译即可。

gcc -c test.s -o test.o 汇编Assembly,gas汇编器负责将其编译为目标文件,.o文件是机器代码 (即 目标文件)

as -c test.s -o test.o 直接调用汇编器来做也可以。

链接

gcc test.o -o test 将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。附加的目标文件包括静态连接库和动态连接库。

ld其实会将许许多多的文件链接起来,包括一些glibc里的库文件的 .o 文件等等。

链接工作无非是把一些指令对其他符号地址的引用加以修正,解决了各个模块间符号引用的问题。主要过程有地址和空间的分配,符号决议(symbol resolution)和重定位等。

其他概念

  1. 重定位relocation:重新计算每个子程序或跳转的目标地址,然后把所有引用到这个符号的指令修正到正确的地址。这种重新计算各个目标地址的过程是重定位。
  2. 静态链接的基本过程:链接器在链接的时候,会根据你所引用的符号foo,自动去相应的func.c 模块查找foo的地址,然后将main.c模块中所有引用到foo的指令重新修正,让他们的目标地址为真正的foo函数的地址。

Reference

  1. 《程序员的自我修养》