在这篇文章中,介绍了 gcc 编译、优化c程序的过程,本文将详细介绍gcc执行的四个步骤(预处理、编译、汇编、链接),来控制编译过程。
当 gcc 执行时,默认的行为是基于源代码产生可执行文件,举个例子
$ gcc -Wall circle.c
-Wall
命令在程序出现问题的时候给出警告,如果没问题则生成一个默认名为a.out的可执行文件
$ ./a.out
如果想指定名字为circle,则使用下面的命令:
$ gcc -Wall -o circle circle.c
预处理
在源代码传给编译器之前,预处理器会执行预处理指令,展开源代码中的宏,默认情况下gcc不会保留预处理阶段的中间输出文件,但可以选择利用 -E
选项来保留中间输出文件,以便观察预处理结果。
注意:-E 选项会造成gcc在预处理结束后立即停止
可以使用 -o
选项将中间输出文件导入到某个文件:
$ gcc -E -o circle.i circle.c
如果想阻止编译器删除注释,可以使用-C
选项
$ gcc -E -C -o circle.i circle.c
编译
gcc 一般会把汇编语言输出到临时文件,并且在汇编执行完后立即删除,但可以使用-S
选项,让编译程序让汇编输出后立即停止,默认汇编语言的输出在一个.s 为后缀名的文件中
$ gcc -S circle.c
汇编
gcc 调用宿主系统的汇编器,将汇编语言翻译成可执行的二进制文件,二进制文件是一个对象文件,包含机器码和行源文件指定的功能,也包含一个符号表,描述源文件中有外部链接的所有对象
使用-c
选项,gcc不会链接临时文件,直接产生文件后缀名为.o的对象文件
$ gcc -c circle.c
将产生名为 circle.o 的对象文件
使用gcc 的-Wa
选项把命令行选项传递给汇编,例如,希望汇编器使用下面的选项
-as=circle.sym
在一个单独的列表中输出模块的符号表,并把指定的列表输出到名为 circle.sym 的文件中
-L
在符号表内包含局部符号
接着可以让 gcc 在引用汇编器时加上这些选项, 选项用逗号分隔成一个列表,放在 -Wa 选项中:
$ gcc -v -o circle -Wa,-as=circle.sym,-L circle.c
注意:-Wa 后面必须紧跟一个逗号,后面接着选项列表,选项之间完全不能有空格
在汇编器的-a
选项后加上多个开关选项,如果使用时没有指定开关选项,默认输出包含汇编语言的程序代码,后面跟着符号表。
gcc的 -g
选项让编译器在输出中包含调试信息,如果同时包含-a 选项和 -g 选项会发生什么呢?
$ gcc -g -o hello -Wa,-as=hello.list,-L hello.c
上述命令执行结果文件是 hello.list
链接
链接器把多个二进制对象文件链接成单一的可执行文件。在链接过程中,必须完成程序中多个模块之间的外部参考,把“参数符号”用对象实际位置代换。链接器还必须将程序中所用到的C标准链接库内的函数加入其中。
标准链接库的大部分内容一般放在libc.a 中,或者放在动态链接的共享版本libc.so中,这些链接库一般位于/lib/或者/usr/lib/,或者位于GCC 默认情况下会搜索的其他链接库目录。
-save-temps
选项可以一次获得全部的中间输出文件,例如
wu@ubuntu:~/cfun$ gcc -save-temps hello.c
执行完后,出现不同后缀名的各种文件,具体如下
wu@ubuntu:~/cfun$ ls
a.out hello.c hello.c~ hello.i hello.o hello.s
.i 表示预处理输出文件,.s 表示汇编语言输出,.o 表示对象文件
Comments