写了好几年代码了,一直记不住gcc是如何编译。今天特地写篇笔记记录下来,以后忘记了还可以回来看笔记。
对于一个深爱着C语言的我来说,灵活使用gcc编译器非常重要,加深对C语言的理解也很重要。
生成可执行文件期间有4个步骤:
1、预编译
2、编译
3、汇编
4、链接
0、编写C文件test.c
C文件.png1、预处理阶段
处理预处理指令(#include #define #ifdef 等 大多数带#的),并删除注释和多余的空白字符,生成一份新的代码。(这里生成的还不是汇编文件)
命令: gcc -E -o test.i test.c
-E 解释:
Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.
Input files that don't require preprocessing are ignored.
(在预处理阶段之后停止;不要正确运行编译器。输出以预处理源代码的形式发送到标准输出。不需要预处理的输入文件将被忽略。)
-o 解释:
后面跟输出的文件名,如果不加 -o 选项的话,输出的文件默认是 a.out
将gcc -E test.c
操作的结果输出到 test.i
中
预处理会将#include <stdio.h>
作一个简单的替换,打开test.i
文件:
796行往上的就是
#include <stdio.h>
替换的结果
2、编译
对代码进程语法分析、词语分析、错误检查,生成汇编代码。还没生成二进制文件。(这一步还会对代码进行优化)
命令:gcc -S -o test.s test.i
-S 解释:
Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified.
By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.
Input files that don't require compilation are ignored.
(在适当的编译阶段之后停止;不要汇编。对于指定的每个非汇编程序输入文件,输出都是汇编程序代码文件的形式。默认情况下,源文件的汇编程序文件名是通过将后缀.c、.i等替换为.s来生成的。不需要编译的输入文件将被忽略。)
3、汇编
通过汇编文件,生成机器代码。还没链接。
目标文件由段组成,通常一个目标文件中至少有两个段:
- 代码段:主要包含程序的指令。该段一般是可读和可执行的,一般不可写。
- 数据段:主要存放程序中用到的各种全局变量和静态的数据。一般数据段是可读、可写、可执行的。
命令:gcc -c -o test.o test.s
-c 解释:
Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.
By default, the object file name for a source file is made by replacing the suffix .c, .i, .s, etc., with .o.
Unrecognized input files, not requiring compilation or assembly, are ignored.
(编译或汇编源文件,但不链接。链接阶段根本没有完成。最终输出是每个源文件的对象文件形式。默认情况下,源文件的对象文件名是通过将后缀.c、.i、.s等替换为.o来生成的。不需要编译或汇编的无法识别的输入文件将被忽略。)
打开test.o文件,发现完全看不懂,这就对了。反正计算机能看懂。
4、链接
将多个 .o
文件合并为一个可执行文件。
命令:gcc -o test test.o
生成可执行文件 test
可以使用命令 objdump -d test
查看汇编(二进制指令转汇编)
根据开发人员指定的同库函数的链接方式的不同,链接处理分为两种:
- 静态链接:
函数代码将从其所在的静态链接库中被拷贝到最终的可执行程序中。- 动态链接:
此时,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所做的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的信息,在可执行程序被执行时,动态链接库的全部内容将被影射到运行时相应进程的虚拟地址空间。动态链接程序将根据可执行程序中记录的信息找到对应的函数代码。- 备注:使用动态链接能使最终的可执行文件较小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。
5、运行
运行.png部分内容转自:C语言编译过程
2020.3.31 22:43 广州
网友评论