一、GCC概念
1.1 背景
在计算机CPU中实际是执行高低电平二进制代码。而直接编写二进制代码是过于复杂的,所以产生了各种高级语言,随之在创造高级语言同时产生了多种翻译器。GCC最初的全名是GUN C Compiler(C语言的翻译器),后来GCC支持的语言越来越多,名字就变成了GUN Compiler Collection(翻译器集合)。
1.2 含义
GCC在意义上可以理解为一个一个翻译组织,组织里面有很多的翻译官。GCC实际就是一个将高级语言翻译成机器语言的工具集合。
1.3 GCC使用
gcc在使用时-o后面必须跟输出文件名。
表1.1 GCC使用规则
| 使用规则 | 作用 | 使用组件 |
|---|---|---|
| gcc -o 输出文件名 输入文件名 | ||
| gcc -v -o 输出文件名 输入文件名 | 显示编译过程 | |
| gcc -E -o | 进行预处理生成 | 将C语文件进行预处理生成.i预处理完后的文件 |
| gcc -v -S -o | 编译输出汇编文件 .s | /usr/lib/gcc/x86_64-linux-gnu/7/cc1 -o a.s 001.c |
| gcc -v -c -o | 将.s汇编文件汇编成二进制文件.o | as -v --64 -o /tmp/cc1q3nbM.o /tmp/ccPlWdwZ.s |
| 链接 | 将各种二进制原材料进行链接 | /usr/lib/gcc/x86_64-linux-gnu/7/collect2 -o build a.o+… |
二、编译过程
2.1 编译过程
1、预处理
2、编译
3、汇编
4、链接
实验环境:ubuntu18.4操作系统,x64位酷睿i5处理器。实验中首先创建C语言文件001.c如下图;然后再进行单独编译文件产生.s的汇编文件;然后将编译文件进行汇编产生二进制文件。
2.1.1 预处理
使用指令gcc -v -E -o a.i 001.c,系统将显示预处理过程,在这里过程中将会把include和define的内容进行替换。
如下图可以看到生成的a.i文件内容,include和define内容全被替换了。实际预处理就是一个替换的过程。
2.1.2 编译
首先使用指令gcc -v -S a.s 001.c,系统将显示编译的过程,GCC将会调用/usr/lib/gcc/x86_64-linux-gnu/7/cc1翻译器将C语言文件编译成汇编文件。
从图中可以看出GCC调用编译翻译器的指令/usr/lib/gcc/x86_64-linux-gnu/7/cc1 -v 输入文件 -o 输出文件,而我们查看生成的.s文件可以发现GCC实际是将C语言文件编译成x64的汇编文件当然这是和我的机器有关系,如果你使用x86或者ARM的汇编,这里的汇编文件就将会是对应的x86汇编或者ARM汇编文件。
2.1.3 汇编
得到a.s的汇编文件后我们使用指令gcc -v -c -o a.o a.s,系统显示调用as翻译器将汇编文件翻译成二进制机器语言文件。
从图中可以很明显的看到GCC调用汇编翻译器的指令as -v -o 输出文件 输入文件,经过翻译就将产生.o二进制文件。
2.1.4 链接
最终我们通过使用链接翻译器/usr/lib/gcc/x86_64-linux-gnu/7/collect2 -o build a.o+…将多种二进制文件链接成可执行文件,这里出了链接你自己编写的C语言的二进制文件还会链接多种资源和系统库。而链接包括静态链接和动态链接。这里参考动态链接和静态链接区别
其实在我们使用指令gcc -o 输出文件 输入文件时其实就包含了预处理过程和调用-S,-c指令,并且GCC会自动进行链接生成可执行文件。