GCC是一套由GNU开发的编程语言编译器,在Linux系统下可以用它调用其他不同的工具进行预处理、编译、汇编、链接这样的工作,其执行效率比一般编译器高20%~30%。由于它是GNU项目之一,是开源的软件,我们可以直接从网上免费地下载安装它。

编译过程:

1.预处理阶段:

GCC在第一个阶段会调用预处理器cpp(c pre process)来对C源程序进行预处理,所谓的预处理就是解释源程序当中的所有的预处理指令,那些诸如#include、#define、#if等以井号#开头的语句就是预处理指令,预处理指令实际上并不是语言本身的组成部分,而是为了更好地组织程序所使用的一些"预先处理的"工作,这些工作用一种叫做预处理指令的语句来描述,然后用预处理器来解释,这些工作包括我们熟悉的诸如文件包含、宏定义、条件编译等等。

gcc hello.c -o hello.i -E // -o 执行输出的文件名

加上一个编译选项 -E 就可以使得 GCC 在进行完第一阶段的预处理之后停下来,生成

一个默认后缀名为.i 的文本文件

2.编辑阶段:

经过预处理之后生成的.i 文件依然是一个文本文件,不能被处理器直接解释,我们需要进一步的翻译。接下来的编译阶段是四个阶段中最为复杂的阶段,它包括词法和语法的分析,最终生成对应硬件平台的汇编语言(不同的处理器有不同的汇编格式),具体生成什么平台的汇编文件取决于所采用的编译器,如果用的是 GCC,那么将会生成 x86 格式的汇编文件,如果用的是针对 ARM 平台的交叉编译器,那么将会生成 ARM 格式的汇编文件。

gcc hello.i -o hello.s -S

再加上一个编译选项 -S 就可以使得 gcc 在进行完第一和第二阶段之后停下来,生成一个

默认后缀名为.s 的文本文件。打开此文件看一看,你会发现这是一个符合 x86 汇编语言的源程序文件

3.汇编阶段

接下来的步骤相对而言比较简单,编译器 gcc 将会调用汇编器 as 将汇编源程序翻译成为可重定位文件。汇编指令跟处理器直接运行的二进制指令流之间基本是一一对应的关系,该阶段只需要将.s 文件里面的汇编翻译成指令即可。

gcc hello.s -o hello.o -c

只要在编译的时候加上一个编译选项-c,则会生成一个扩展名为.o 的文件,这个文件是一个 ELF 格式的可重定位(relocatable)文件。程序中的所有的全局符号尚未定位,所谓的全局符号,就是指函数和全局变量,函数和全局变量默认情况下是可以被外部文件引用的。

由于定义和调用可以出现在不同的文件当中,因此他们在编译的过程中需要确定其入口地址,比如 a.c 文件里面定义了一个函数 func( ),b.c 文件里面调用了该函数,那么在完成第三阶段汇编之后,b.o 文件里面的函数 func( )的地址将是 0,显然这是不能运行的,必须要找到 a.c 文件里面函数 func( )的确切的入口地址,然后将 b.c 中的“全局符号”func重新定位为这个地址,程序才能正确运行。

4.链接阶段

如前面所述,经过汇编之后的可重定位文件不能直接运行,因为还有两个很重要的工作没完成,首先是重定位,其次是合并相同权限的段。关于重定位的问题,上面已经给出了简单的描述。一般地,我们编译一个程序通常都需要链接系统的标准 C 库、gcc 内置库等基本库文件。因为 Linux 下任何一个程序编译都需要用到这些基本库的全局符号。

gcc hello.o -o hello -lc -lgcc

标准 C 库 和 gcc 内置库是如此的基本,因此-lc 和-lgcc 是默认的,可以省略。

Logo

更多推荐