GNU编译工具链简述
B站有个视频讲这部分比较透彻,可以去看一下。链接
上图涉及的内容比较多,主干部分就是下图:
具体实现指令如下:
- 预处理:gcc -E hello.c -o hello.i
- 编译:gcc -S hello.i -o hello.s
- 汇编:gcc -c hello.s -o hello.o
- 链接:gcc hello.o -o hello
其中:
-E:提示编译器执行完预处理就停下来,后边的编译、汇编、链接就先不执行了。
-S:提示编译器执行完编译就停下来,不去执行汇编和链接了。
-c:提示编译器执行完汇编就停下来。
所以,这三个选项相当于是限定了编译器执行操作的停止时间,而不是单独的将某一步拎出来执行。
1. 预处理
gcc -E hello.c -o hello.i
- 需要申明的是,linux不在乎文件的后缀是什么,文件后缀仅是便于我们区分文件的类型而存在的
- .c表示需要预处理的源代码
- .i表示不需要预处理的源代码(说明已经完成预处理了)
- -E:提示编译器执行完预处理就停下来,后边的编译、汇编、链接就先不执行了。
- -o file表示将输出文件存于文件file中
该阶段主要是处理 # 开头的内容,包括:
- #inlcude 头文件展开
- #define 宏定义代换
- 条件编译处理
可以看到预处理后的.i文件有800多行,只有最末端是主函数的代码,前面一大堆都是头文件的东西,直接被拷贝过来了。宏定义也是直接完成了替换。
2. 编译:
gcc -S hello.i -o hello.s
- -S表示只是编译,不汇编,生成.s的汇编文件
- .i表示不需要预处理的源代码
- -o file表示将输出文件存于文件file中
- .s表示不需要预处理的汇编代码,是汇编文件的后缀。
该阶段主要是语法检查并且将文件编译成汇编文件,下面是生成的汇编文件hello.s的具体内容,用汇编语言写的。
3. 汇编
gcc -c hello.s -o hello.o
- -c表示只是编译,不链接,生成.o目标文件
- .s表示不需要预处理的汇编代码,是汇编文件的后缀
- -o file表示将输出文件存于文件file中
- .o是目标文件的后缀
这个阶段是调用交叉汇编器as来完成的,主要是将汇编文件转化成二进制文件,该二进制文件没有经过链接(下面马上介绍链接的含义),不可执行(一方面没有权限,一方面执行会报错)。
用file指令查看文件的信息
用vi编辑器打开该文件发现全是乱码,都是二进制内容,可以发现的是该文件格式是ELF。
用gedit编辑器不能打开。
4. 链接
链接的主要内容就是将各个模块之间相互引用的部分正确的衔接起来。分为动态链接和静态链接。是调用交叉连接器ld来完成的
- 动态链接:将printf等依赖的位置信息放入可执行文件
gcc hello.o -o hello
- 静态链接:直接将printf等依赖的定义放入可执行文件
gcc hello.o -o hello -static
由上面的定义可知:
- 动态链接的文件小,但是对环境依赖要求高
- 静态链接文件大,但是对环境依赖要求低
更多动静态链接的内容可以参考我的另一篇博客嵌入式系统作业3——gcc、gdb简单使用
5. 多步合并
- 预处理和编译两步可以用下面的一步代替
gcc -S hello.c -o hello.s
- 预处理、编译和汇编三步可以用下面的一步代替
gcc -c hello.c -o hello.o
- 预处理、编译、汇编、链接四步可以用下面的一步替代
gcc hello.c -o hello
- 使用 gcc 命令不跟任何的选项的话,会默认执行预处理、编译、汇编、链接这整个过程,如果程序没有错,就会得到一个可执行文件,默认为a.out
gcc hello.c
相关过程如下:
本文来自博客园,作者:静候佳茵,转载请注明原文链接:https://www.cnblogs.com/hitwherznchjy/p/16104026.html