创建并编写test.c
#include
int main(void)
{
printf("Hello World!\n");
return 0;
}
过程 | 代码 |
---|---|
预处理 | gcc -E test.c -o test.i 或gcc -E test.c |
编译为汇编代码 | gcc -S test.i -o test.s |
汇编 | gcc -c test.s -o test.o |
连接 | gcc test.o -o test |
gcc -E test.c -o test.i 或gcc -E test.c
输出test.i文件中存放着test.c经预处理之后的代码,后面的指令直接在命令行窗口输出预处理后的代码。
gcc的-E选项,可以让编译器在预处理后停止,并输出预处理结果。
本例中,预处理结果将stdio.h文件的内容插入到test.c中。
gcc -S test.i -o test.s
预处理之后,可直接对生成的 test.i 文件编译,生成汇编代码。
编译过程就是对预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码。
gcc 的-S 选项,表示在程序编译期间,在生成汇编代码后,停止,-o 输出汇编代码文件。
gcc -c test.s -o test.o
对于上一步生成的汇编代码文件 test.s,gas汇编器负责将其编译为目标文件。
汇编过程调用对汇编代码进行处理,生成处理器能识别的指令,保存在后缀为.o的目标文件中。由于每一个汇编语句几乎都对应一条处理器指令,因此,汇编相对于编译过程比较简单,通过调用 Binutils 中的汇编器 as 根据汇编指令和处理器指令的对照表一一翻译即可。
当程序由多个源代码文件构成时,每个文件都要先完成汇编工作,生成.o 目标文件后,才能进入下一步的链接工作。
注意:目标文件已经是最终程序的某一部分了,但是在链接之前还不能执行。
2.4 连接
gcc test.o -o test
gcc 连接器是 gas 提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来,最终生成可执行文件。
附加的目标文件包括静态连接库和动态连接库。
通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用 GCC 能够很好地管理这些编译单元。
假设有一个由 test1.c 和 test2.c 两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序 test,可以使用下面这条命令:
gcc test1.c test2.c -o test
如果同时处理的文件不止一个,GCC 仍然会按照预处理、编译和链接的过程依次进行。上面这条命令大致相当于依次执行如下三条命令:
gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o -o test
gcc -pedantic test.c -o test1
gcc -pedantic test.c -o test1
gcc -Wall test.c -o test2
-Wall:帮助发现一些不符合ANSI/ISO C标准的代码,当出现不符合的代码,gcc会发出尽可能多的警告信息
gcc -Werror test.c -o test3
-Werror:gcc会在所有产生警告的地方停止编译,迫使进行代码的修改
库文件:动态链接库(.so),静态链接库(.a)
函数库:头文件(.h),库文件(.so)
注意:头文件一般放在/usr/include目录下,库文件一般放在/usr/lib目录下
首先我们要进行编译 test.c 为目标文件,这个时候需要执行
gcc –c –I /usr/dev/mysql/include test.c –o test.o
gcc -c -I /usr/include 源文件 -o 生成.o文件
我们把所有目标文件链接成可执行文件:
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
gcc -L /usr/lib 动态链接库文件名 生成.o文件 -o 生成可执行文件
默认情况下, GCC 在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static 选项,强制使用静态链接库。
gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test
gcc -L /usr/lib -static 静态链接库文件名 生成.o文件 -o 生成可执行文件
静态库链接时搜索路径顺序:
- ld 会去找 GCC 命令中的参数-L
- 再找 gcc 的环境变量 LIBRARY_PATH
- 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初 compile gcc 时写在程序内的
动态链接时、执行时搜索路径顺序:
- 编译目标代码时指定的动态库搜索路径
- 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径
- 配置文件/etc/ld.so.conf 中指定的动态库搜索路径
- 默认的动态库搜索路径/lib
- 默认的动态库搜索路径/usr/lib
ELF是一种文件格式,用于存储Linux程序。
ELF文件分三种类型:
1、目标文件(通常是.o)
2、可执行文件(我们的运行文件)
3、动态库(.so)
一个典型的 ELF 文件包含下面几个段:
.text:已编译程序的指令代码段。
.rodata:ro 代表 read only,即只读数据(譬如常数 const)。
.data:已初始化的 C 程序全局变量和静态局部变量。
.bss:未初始化的 C 程序全局变量和静态局部变量。
.debug:调试符号表,调试器用此段的信息帮助调试。
查看ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包含的指令和数据,需要使用反汇编的方法。
使用 objdump -D对其进行反汇编如下:
使用objdump -S将其反汇编并且将其C语言源代码混合显示出来。
一组二进制程序处理工具,包括:addr2line、ar、objcopy、objdump、as、ld、ldd、readelf、 size 等。这一组工具是开发和调试不可缺少的工具 ,分别简介如下:
工具 | 用途 |
---|---|
addr2line | 用来将程序 地址转 换成其所对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对应的源代码位置 |
as | 主要用于汇编 |
ld | 主要用于链接 |
ar | 主要用于创建静态库 |
ldd | 可以用于查看一个可执行程序依赖的共享库 |
objcopy | 将一种对象文件翻译成另一种格式,譬如将.bin 转换成.elf、或者将.elf 转换成.bin 等 |
objdump | 主要的作用是反汇编 |
readelf | 显示有关 ELF 文件的信息 |
size | 列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等 |