基础知识的介绍 (转载表明出处)
环境都是Ubuntu,工具自行安装。
基础知识
C编译原理
编译过程分为4个阶段:预处理、编译、汇编、链接。

C代码编过程(图片来自网络)
预处理
C的源文件包含 #define 和 include 指令。预处理扩展了源代码中所有的 #define 和 #include 指令,剩下的就是准备编译的纯C代码。
#include<stdio.h>
#define TEST_STR "%s"
#define MESSAGE "hell0\n"
int main(int argc,char* angv[])
{
printf(TEST_STR,MESSAGE);
return 0;
}
预处理指令如下:
gcc -E -P test.c
-E 表示预处理后停止, -P 使GCC忽略调试信息。处理结果如下“

typedef(不完整)

struct(不完整)

extern(不完整)

main
1、stdio.h 头文件全部包含在内,其所有的类型定义、全局变量及函数原型都被”复制“到了源文件中。
2、#define 所表示的字符串在代码中被进行了替换。
编译
预处理结束后,下个阶段是编译。该阶段编译器会进行大量优化,通常可以通过命令行开关配置优化级别,比如GCC中的选项-01到-03。优化级别对反汇编影响很大。
关于编译器在这个阶段为什么不直接转成机器码,而转成汇编代码。是因为其他语言都直接转成不同平台的二进制难度太大,所以最好翻译为汇编代码,后转为机器语言。gcc编译指令如下:
gcc -S -masm=intel test.c
-S : 告诉编译器在编译阶段后停止(.s 是汇编文件常见的扩展名)
-masm-intel : 以 Intel 语法而不是默认的 AT&T 语法翻译汇编语言
编译结果如下:

编译结果
这里的汇编代码相对容易阅读,因为符号和函数已经被保留下来了。
如 “hello” 的匿名字符串是 LCO 。
main 函数有一个显式标签
代码中的任何引用都是有符号的,如 lea eax,.LCO[rip]
汇编
汇编阶段的输入是编译阶段生成的汇编语言集,输出是一组对象文件,有时简称模块。gcc汇编指令如下
gcc -c test.c
然后使用 file 工具来检测生成的文件类型
结果如下:

file工具结果
file 工具是用来检测文件类型的工具,ELF表示是Linux下可执行文件。
MSB 和 LSB 介绍:
MSB(Most Significant Bit):最高有效位,个人理解为大端存储
LSB(Least Significant Bit):最低有效位,个人理解为小端存储
relocatable 表示 “可重定位” ,在文件中看到表示文件不是可执行文件而是对象文件。对象文件相互独立编译,因此汇编程序在组装对象时候无法知道其他文件的内存地址。这就是对象文件需要可重定位的原因,这样你就可以按照任意顺序将对象文件链接到一起,组成完整的可执行二进制文件。
链接
链接是编译过程的最后阶段,此阶段将所有对象文件链接到一个可执行二进制文件中。此阶段会进行链接时优化(Link-Time Optimization,LTO)。静态库(在Linux操作系统扩展名为 .a ,在链接时被合并到可执行文件中。还有动态(共享)库,它们在系统上运行的所有程序的内存中共享。大多数编译器在编译过程结束时会自动调用链接器。指令如下:
gcc test.c
file a.out

file结果