GCC编译过程探索

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ferrycooper/article/details/50708462

GCC编译过程

GCC编译程序的四个阶段:

1、  预处理(也称预编译)

2、  编译

3、  汇编

4、  链接

在编译程序的过程,可以加上不同的参数使其在不同阶段停止,以便观察不同阶段的输出信息和输出问文件。

GCC文件类型:

.c为后缀的文件,C语言源文件

.a为后缀的文件是由目标文件构成的档案库文件

.C、.cc、.cpp、.C++、.cp或.cxx为后缀的文件,是C++源文件

.h为后缀的文件,是程序所包含的头文件

.i为后缀的文件是已经预处理过的C源代码文件

.ii为后缀的文件是已经预处理过的C++源代码文件

.m为后缀的Objective-C源代码文件

.o为后缀的文件是编译后的目标文件

.s为后缀的文件是汇编语言源代码文件

.S为后缀的文件是经过预编译的汇编语言源代码文件

GCC在各阶段的角色

Gcc首先调用cpp进行预处理,在预处理过程中队源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编过程就是针对汇编语言的步骤,调用as进行工作,一般来讲,.S为后缀的汇编语言源代码文件和.s为后缀的汇编语言文件经过预编译和汇编后都生成以.o为后缀的目标文件。当所有的目标文件都生成之后,Gcc就调用ld来完成最后的关键性工作,这个阶段就是链接,在链接阶段所有的目标文件被安排在可执行程序的恰当位置,同时,该程序所调用到的库函数也从各自所在的库连到合适的地方。

在windows环境下我使用MinGW来学习GCC,Linux环境下直接使用GCC就可以了。先看看gcc是怎样完成整个编译过程的。

先安装好MinGW为了操作方便,将MinGW安装位置的Bin文件夹的路径加入到环境变量path后面,这样就可以直接在dos命令下使用bin下的各种工具。

先用记事本类的工具写个最简单的C程序保存为my.c,如下:

#include<stdio.h>

int main(void){

         printf("Hello world!");

         return 0;

}

先看下gcc如何生成可执行文件,最简单的方法就是在dos窗口中执行gcc my.c –o my,当然先要cd到my.c文件所在的路径下不然是找不到my.c,之后即可看到my.exe可执行文件。


为了更好的理解GCC的工作过程,我们可以让GCC在预处理、编译、汇编、链接任何一个阶段停止下来,只要加上相关的参数:

-E 预处理后停下来,生成后缀为.i的预编译文件;

-S 汇编后停下来,生成后缀为.s的汇编源文件;

-c 编译后停下来,生成后缀为.o的目标文件。

第一步,进行预编译使用-E参数让gcc在预处理结束后停止编译过程:gcc–E my.c –o my.i

会发现多了一个my.i的文件,按照gcc首先调用cpp进行预编译,刚好发现MinGW安装目录bin有cpp.exe这个工具,把之前生成的my.i删除,尝试使用cpp –Emy.c –o my.i进行预编译,发现也会生成一个my.i,my.i文件是预编译文件,查看该文件发现stdio.h的内容确实插到文件中去了,其他应当被预处理的宏定义也作了相应的处理。

第二步,编译。将源代码文件编译成汇编代码,gcc –S my.c –o my.s也可以使用gcc –S my.i –o my.s效果是一样的,为了更好理解GCC编译过程,使用gcc –S my.i –o my.s刚好利用了前面第一步预处理生成的my.i文件。按照GCC是调用cc1进行编译的,开始在MinGW安装位置的Bin文件夹并没找着cc1.exe,后来在MinGW安装位置的libexec目录往下找找到了,将my.i文件放到cc1.exe的同级目录下,用cc1 –S my.i –o my.s发现GCC的确是调用cc1进行编译。

第三步,汇编。将第二步生成的my.s源文件汇编成目标代码文件,使用gcc –c my.c –o my.o或gcc –c my.i –o my.o或gcc –c my.s –o my.o或as my.s –o my.o,根据GCC在编译阶段是调用as将汇编源代码进行编译,使用as my.s –o my.o进行编译。

第四步,链接。将第三步生成的my.o目标文件链接成可执行文件,使用gcc my.c –o my或gcc my.i –o my或gcc my.o –o my,按照GCC是调用ld来链接的可是使用ld my.o –o my会出现undefined reference to `__main'、undefined referenceto `printf'的错误,加上-lc参数又显示找不到-lc,但是在linux下使用ld –e main my.o –lc –o my没问题,我用的是Fedora23的虚拟机,估计在windows下对应的c库没找着,暂时放在这。

现在来理清下整个过程,GCC编译的预处理、编译、汇编、链接四个阶段对应调用的四个工具是cpp、cc1、as、ld,预处理后生成.i的文件,cc1将预处理后的.i文件编译成汇编源文件,as将汇编源文件汇编成.o的目标代码文件,然后通过ld链接成可执行文件。




猜你喜欢

转载自blog.csdn.net/ferrycooper/article/details/50708462