【Linux】程序翻译的四个阶段及编译器gcc/g++的验证

“没有做不会的题,没有背不下的书,起不来的早晨,熬不下的夜,只有不想追的梦”
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第1张图片

目录

  • 前言:
  • 一.程序翻译的四个阶段
    • 1.预处理阶段
      • 1.1预处理的验证(gcc -E)
    • 2.编译
      • 2.1编译的验证(gcc -S)
    • 3.汇编
      • 3.1汇编的验证(gcc -c)
    • 4.链接
      • 4.1链接的验证
  • 二.gcc选项补充
  • 三.总结

前言:

为了在系统上运行一个程序,每条C语句都必须被其他程序转化为一系列的低级机器语言指令,然后这些指令按照一种为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。目标程序也称为可执行目标文件。

在Linux操作系统上,从源文件到目标文件的转化是由编译器驱动程序(gcc/g++)完成的。
gcc在Linux下负责编译C语言,g++主要负责编译C++。

gcc -o hello hello.c

上面这个指令,gcc编译器驱动程序读取源程序文件hello.c,并把它翻译成一个可执行目标文件hello。
这个翻译过程分为四个阶段:预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)、链接(Linking)。执行这四个阶段的程序(预处理器、编译器、汇编器、和链接器)一起构成了编译系统。
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第2张图片

一.程序翻译的四个阶段

1.预处理阶段

预处理功能主要包括宏替换,头文件包含,条件编译,去注释等

头文件包含:处理#include指令,一个源文件可以将另外一个文件的全部内容包含进来

宏替换:#define a b,在编译预处理时,将程序中在该语句以后出现的所有的a都用b来代替。

去注释:删掉源代码中注释的部分

条件编译:一般情况下,C语言源程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。比如#if、#ifdef、#elif、#else、#endif等

1.1预处理的验证(gcc -E)

我们先在hello.c中加上宏定义,头文件,注释,和条件编译
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第3张图片

接下来我们执行:gcc -E hello.c -o hello.i

选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序

我们的文件直接变成了800多行,因为头文件被包含了进来。此外也进行了宏替换,M替换成了5,注释的信息也没有了,并且进行了条件编译。
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第4张图片

2.编译

编译器(gcc)将预处理完的文本文件hello.i进行一系列的词法分析、语法分析、语义分析和优化,翻译成文本文件hello.s,它包含一个汇编语言程序。

所以编译就是把语言代码转换成汇编代码文件( . s ) \color{#FF0000}{所以编译就是把语言代码转换成汇编代码文件(.s)} 所以编译就是把语言代码转换成汇编代码文件(.s)

2.1编译的验证(gcc -S)

-S:从现在开始进行程序的翻译,当编译做完就停下来

我们进行下面的操作:

gcc -S hello.i -o hello.s 或者
gcc -S hello.i 会默认生成hello.s文件

【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第5张图片
我们查看hello.s文件,可以看到变成了汇编代码

【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第6张图片

3.汇编

汇编器(as)将hello.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序的格式,并将结果保存在目标文件hello.o中,hello.o是一个二进制文件。

所以汇编就是把汇编语言转化为可重定位的二进制文件,它是不可以被执行的 \color{#FF0000}{所以汇编就是把汇编语言转化为可重定位的二进制文件,它是不可以被执行的} 所以汇编就是把汇编语言转化为可重定位的二进制文件,它是不可以被执行的

在绝大多数window的编译器下生成的是bin.obj文件

3.1汇编的验证(gcc -c)

-c:从现在开始进行程序的翻译,当汇编做完就停下来

我们进行下面的操作
gcc -c hello.s -o hello.o

【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第7张图片
我们查看hello.o文件的内容
可以看到一堆乱码
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第8张图片

4.链接

hello程序调用了printf函数,它存在于一个名为printf.o的单独的预编译好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o程序中。连接器(ld)就负责处理这种合并。结果就得到了hello文件,它是一个可执行目标文件(或者称为可执行文件
上一步汇编只是把我们的代码进行翻译成二进制目标文件,但我们调用了printf函数,还需要链接到库文件中的库函数去。

所以链接就是把我们的 o b j 文件和我们的库文件进行合并,形成可执行程序 \color{#FF0000}{所以链接就是把我们的obj文件和我们的库文件进行合并,形成可执行程序} 所以链接就是把我们的obj文件和我们的库文件进行合并,形成可执行程序

4.1链接的验证

我们进行下面的操作:
gcc hello.o -o hello 生成hello的可执行程序
gcc hello.o 默认生成a.out可执行程序

【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第9张图片

./hello去执行代码
【Linux】程序翻译的四个阶段及编译器gcc/g++的验证_第10张图片

二.gcc选项补充

之前用到的-E,-S,-e,下面补充一些选项

-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S 编译到汇编语言不进行汇编和链接
-c 编译到目标代码
-o 文件输出到 文件
-static 此选项对生成的文件采用静态链接
-g 生成调试信息。GNU 调试器可利用该信息。
-shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
-O0 -O1-O2-O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-w 不生成任何警告信息。
-Wall 生成所有警告信息。

三.总结

本文介绍了程序编译的四个阶段,分别是预处理,编译,汇编和链接的知识,以及使用gcc在Linux中对各个阶段进行验证使用了-E,-S,-c,可以使用左上角键盘Esc键进行记忆,以及生成对应的文件后缀iso。

链接阶段涉及函数库的知识,我们下文见。。
完结。。。。

你可能感兴趣的:(Linux,linux,jvm,运维)