1 GCC常用命令
1.0 引言
GCC 的意思也只是 GNU C Compiler 而已。GCC 已经不仅仅能支持 C语言;它还支持 Ada 语言、C++ 语言、Java语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU编译器家族的意思了。另一方面,说到 GCC 对于操作系统平台及硬件平台支持,概括起来就是一句话:无所不在。
接下来我们通过一个示例程序对GCC的常用命令进行认识,示例程序如下:
#include<stdio.h>
int main(void)
{
printf("Hello World!\n");
return 0;
}
1.1 简单编译
键入命令:gcc test.c -o test ,即可完成编译;接着运行完成。
1.2 实际编译
实质上,上述编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编(Assembly)和连接(Linking)。
(1) 预编译 键入命令:gcc -E test.c -o test.i 生成的 test.i 文件中存放着 test.c 经预处理之后的内容。 (2) 编译为汇编代码 键入命令:gcc -S test.i -o test.s 生成的 test.s 文件中存放着 test.i 在编译期间的生成的汇编代码内容。 (3) 汇编 键入命令: gcc -c test.s -o test.o 将生成的汇编代码文件 test.s,汇编器负责将其编译为目标文件。 (4) 连接 键入命令:gcc test.o -o test 将生成的 test.o,将其与C标准输入输出库进行连接,最终生成程序 test。
1.3 多个程序文件的编译
(1) gcc test1.c test2.c -o test 生成的可执行文件 例如: (2) 如果同时处理的文件不止一个,GCC 仍然会按照预处理、编译和链接的过程依次进行。如果深究起来,上面这条命令大致相当于依次执行如下三条命令:
gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o
例如:
1.4 检错
gcc -pedantic illcode.c -o illcode
-pedantic :能够帮助程序员发现一些不符合ANSI/ISO C 标准的代码,但不是全部,事实上只有 ANSI/ISO C 语言标准中要求进行编译器诊断的那些情况,才有可能被 GCC 发现并提出警告。
gcc -Wall illcode.c -o illcode GCC
-Wall :能够使 GCC 产生尽可能多的警告信息。
gcc -Werror test.c
-Werror :GCC 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改。
1.5 库文件连接
库文件:动态链接库(.so),静态链接库(.a) 函数库:头文件(.h),库文件(.so)
Linux 下的大多数函数都默认将头文件放到/usr/include/目录下,而库文件则放到/usr/lib/目录下。
(1) 编译
gcc –c –I /usr/dev/mysql/include test.c –o test.o
(2) 链接
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
(3) 强制性使用静态链接库
gcc链接时会优先使用动态链接库,想强制使用静态链接库执行在命令中加-static
gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test
静态链接时搜索路径顺序: a、ld会去找gcc命令中的参数-L b、gcc的环境变量LBRARY_PATH(指定程序静态链接库文件的搜索路径) c、内定目录/lib /usr/lib /usr/local/lib 动态链接时搜索路径顺序: a、编译目标代码时指定的动态库搜索路径 b、环境变量LD_LIBRARY_PATH(指定程序动态链接库文件的搜索路径) c、配置文件/etc/ld.so.conf中指定的动态库搜索路径 d、默认的动态库搜索路径/lib e、默认的动态库搜索路径/usr/lib
2 GCC大家族
2.1 gcc的伙伴
GCC 不是一个人在战斗,GCC 背后其实有一堆战友。
这里进行简单介绍
工具 | 作用 |
---|
addr21line | 帮助调试器在调试过程中定位对应的源代码 | ar | 用于创建静态链接库 | ld | 用于链接 | as | 用于汇编 | ldd | 查看执行文件所用到的链接库 | objcopy | 将一种对象文件翻译成另一种格式 | size | 查看执行文件中各部分的大小 | readelf | 查看ELF各个部分的内容 | objdump | 进行反汇编 |
例如:
- 采用动态连接库:
- 采用静态链接库:
通过上述例子也可见采用动态链接库会时执行文件小很多。
2.2 分析ELF文件
2.2.1 ELF 文件的段
链接器链接后生成的最终文件为 ELF 格式可执行文件,一个 ELF 可执行文件通常被链接为不同的段。位于 ELF Header 和 Section Header Table 之间的都是段。一个典型的 ELF 文件包含下面几个段:
段 | 含义 |
---|
.text | 已编译程序的指令代码段 | .rodata | ro 代表 read only,即只读数据(譬如常数 const) | .data | 已初始化的 C 程序全局变量和静态局部变量 | .bss | 未初始化的 C 程序全局变量和静态局部变量 | .debug | 调试符号表,调试器用此段的信息帮助调试 |
2.2.2 查看ELF
键入命令: readelf -S hello (这里用作者的hello文件,也可以是其他。)
2.2.3 反汇编ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包含的指令和数据,需要使用反汇编的方法。使用 objdump -D 对其进行反汇编如下:
- 使用
objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来: 分别键入:
gcc -o hello -g hello.c
objdump -S hello
3 总结
上面对GCC的进一步学习和了解,能认识不少与GCC相互协作的工具。在此基础上,也能促使更进一步了解和掌握GCC的灵活运用。当然,光知道了不用也不行,在你尝试过这次操作之后,希望能多多应用和思考。
4 参考资料
使用gcc和gcc的伙伴
|