GCC编译过程(预处理->编译->汇编->链接)

GCC编译过程(预处理->编译->汇编->链接)
这里gcc编译器 是指在linux类操作系统下,windows编译器 MinGW(相当于windows版GCC)
一个C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等4步才能变成可执行文件。
在这里插入图片描述

生成可执行程序过程为成四个步骤:

1、 由.c文件到.i文件,这个过程叫预处理。
以“#”号开头的预处理指令如包含#include,宏定义制定#define等。在源程序中这些指令都放在函数之外,而且一般放在源文件的前面。

C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一步处理。

2、由.i文件到.s文件,这个过程叫编译。
这里的编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理文件(test.i)之后的程序转换成特定汇编(test.s)代码的过程。

汇编是机器语言的直接翻译形式

人们便尝试用英文助记符代替晦涩的机器指令,例如ADD代表一条机器加法指令,助记符和机器指令一一对应,就这样汇编语言出现了,它极大的提高了人的工作效率。但是计算机并不认识汇编指令,必须将它替换为对应的机器指令,计算机才能执行它,这个过程叫汇编!

***人的追求永无止境,后来出现了各种高级语言,它接近人类自然语言的表达方式,便于人理解和使用。***其中C语言脱颖而出,它不可撼动的成为了系统编程语言,众多操作系统例如unix,linux,ios,andriod等底层全部由C语言实现。C语言虽然是一种高级语言,但是它的硬件亲和性决定了适合于底层,驱动,操作系统等领域,在嵌入式领域,首选的也是C语言。计算机无法执行高级语言程序,需要通过编译程序把它翻译成汇编代码,然后通过汇编程序翻译成二进制序列(机器语言),计算机才能执行它!

C语言封装了很多汇编变成需要考虑的事情,比如函数传参和调用栈管理

编译就是把C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码,所用到的工具为cc1(它的名字就是cc1,x86有自己的cc1命令,ARM板也有自己的cc1命令)。

3、由.s文件到.o文件,这个过程叫汇编。
汇编过程将上一步的汇编代码转换成机器码,这一步产生的文件叫做目标文件,是二进制格式。

有两种方式:
使用 gcc直接从源代码生成目标代码 gcc -c .s -o .o
使用
汇编器
从汇编代码生成目标代码 as *.s -o *.o

到编译阶段,代码还都是人类可以读懂的。汇编这一阶段,正式将汇编代码生成机器可以执行的目标代码,也就是二进制码。

汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件),用到的工具为as。x86有自己的as命令,ARM版也有自己的as命令,也可能是xxxx-as(比如arm-linux-as)。

“反汇编”是指将机器代码转换为汇编代码,这在调试程序时常常用到。

4、由.o文件到可执行文件,这个过程叫链接。
链接过程使用链接器将该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。附加的目标文件包括静态连接库和动态连接库。
-L 与 -l 链接器参数,就是指定链接时去(哪里)找(什么)库。
• -l,代表链接哪个库,会自动检索lib开头的对应库名。 例如-lpthread,-lQt5Core。会自动检索libpthread.so,libpthread.a,libQt5Core.so,libQt5Core.a
o 如果静态库动态库同时存在,优先链接动态库

• -L,指定去哪里找库文件。例如指定:-L/home/threedog/test,则在编译时会优先检索/home/threedog/test/libpthread.so等文件。
• 链接库最直接的办法是不用任何参数,直接写库的路径加载编译参数里。
• 查找顺序 :
o 如果直接写的库的全路径,则会直接去找到库,不走下面的顺序检索。
o -L,优先级最高
o 然后是系统的环境变量LIBRARY_PATH
o 最后再找内定目录 /lib/usr/lib/usr/local/lib 这是当初编译 gcc时写在程序内的
o 如果都找不到,会报错找不到文件或找不到-lxxxx

编译程序时,加上-v选项就可以看到这几个步骤。比如:
gcc -o hello hello.c -v
可以看到很多输出结果,我们把其中的主要信息摘出来:
cc1 hello.c -o /tmp/cctETob7.s
as -o /tmp/ccvv2KbL.o /tmp/cctETob7.s
collect2 -o hello crt1.o crti.o crtbegin.o /tmp/ccvv2KbL.o crtend.o crtn.o

以上3个命令分别对应于编译步骤中的预处理+编译、汇编和链接,ld被collect2调用来链接程序。预处理和编译被放在了一个命令(cc1)中进行的,可以把它再次拆分为以下两步:
cpp -o hello.i hello.c
cc1 hello.i -o /tmp/cctETob7.s

我们不需要手工去执行cpp、cc1、collect2等命令,我们直接执行gcc并指定不同的参数就可以了。
可以通过各种选项来控制gcc的动作,下面介绍一些常用的选项。
常用选项 描述
-E 预处理,开发过程中想快速确定某个宏可以使用“-E -dM”
-c 把预处理、编译、汇编都做了,但是不链接
-o 指定输出文件
-I 指定头文件目录
-L 指定链接时库文件目录
-l 指定链接哪一个库文件

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页