一、GCC背后的战友
1、GCC
GCC(GNU C Compiler)是编译工具。
将C/C++语言编写的程序转换成为处理器能执行的二进制代码的过程即由编译器完成。
2、Binutils
一组二进制程序处理工具,包括:addr2line、ar、 objcopy、objdump、as、ld、ldd、readelf、 size等。这一组工具是开发和调试不可缺少的工具,分别简介如下:
(1)addr2line:用来将程序地址转换为其对应的程序源文件及所对应的代码行,也可以得到所对应的函数。该工具将帮助调试器子啊调试过程中定位对应的源代码位置。
(2)as:用于汇编
(3)ld:用于链接
(4)ar:主要用于创建静态库
动态库与静态库的相关概念:
·如果要将多个.o目标文件生成一个库文件,则存在两种类型的库:"静态库"、"动态库"
·windows中静态库以.lib为后缀的文件,共享库是以.so为后缀的文件
·静态库与动态库的不同点在于载入时刻不同。
静态库代码在编译过程就已经被载入可执行文件,因此体积较大。
共享库代码在文件执行时才载入内存,在编译时只需简单引用,因此代码体积较小。
在linux系统中,可以用ldd命令查看一个可执行程序依赖的共享库。
在静态库与共享库同时存在时,系统自动选择动态库。
·如果一个系统中存在多个需要同时运行的程序且这些程序之间存在共享库,
那么采用动态库的形式将更省内存。
(5)ldd:用于查看一个可执行程序依赖的共享库
(6)objcopy:将一种对象文件翻译成另一种格式,譬如将.bin转换成.elf、或者将.elf转换为.bin等。
(7)readelf:显示有关ELF文件等信息。
(8)objdump:用于反汇编。
(9)size:列出可执行文件每个部分的尺寸和总尺寸,代码段、数据段、总大小等。
一、准备工作
在linux系统中进行。
为能演示编译整个过程,先创建一个工作目录test0,
mkdir test0
cd test0
vi hello.c
然后用文本编译器生成一个C语言编写简单Hello.c程序为示例,源代码为:
#include<stdio.h>
//作用仅打印一个hello word字符串
int main(void)
{
printf("Hello World! \n");
return 0;
}
保存并退出
二、编译过程
1、预处理
预处理命令:
gcc -E hello.c -o hello.i
这个命令将源文件hello.c 文件预处理生成hello.i
GCC的选项-E使GCC在进行完预处理后即停止。
hello.i文件可以作为普通文本文件打开进行查看
下面为hello.i文件的部分内容
2、编译
编译过程就是对预处理完成的文件进行一系列的词法分析,语法分析,语义分析及优化后 生成相应的汇编代码。
GCC编译命令如下
gcc -S hello.i -o hello.s
此命令将预处理生成的 hello.i文件编译生成汇编程序hello.s .
GCC选项-S使GCC在执行完编译后停止,生成汇编程序。
以下为hello.s部分代码
3、汇编
汇编过程调用处理汇编代码,生成处理器能识别的指令,保存为后缀.o的目标文件。
当程序由多个源代码文件构成时,每个文件都要先完成汇编工作,生成.o目标文件后,才能进入下一步的链接工作。
注:目标文件是最终程序的某一部分了,但是在链接之前还不能执行。
gcc汇编命令如下:
gcc -c hello.s -o hello.o
这将编译生成的hello.s文件汇编生成目标文件hello.o
GCC的选项-C使GCC在执行完成汇编后停止,生成目标文件
或者直接调用as进行汇编
as -c hello.s -o hello.o
使用Binutils中的as将hello.s文件汇编生成目标文件
注:hello.o目标文件为ELF格式的可重定向文件。
4、链接
分为:静态库链接和动态链接
动态链接:
gcc hello.c -o hello
size hello //使用size查看大小
ldd hello //可以看出该可执行文件链接列其他动态库
删掉之前动态链接的结果后
静态链接:
gcc -static hello.c -o hello
size hello
ldd hello
三、分析ELF文件
1、ELF内含段
一个典型的ELF文件包含下面几个段
·text:已编译程序的指令代码段
·rodate:ro代表read only,即只读数据
·data:已初始化的C程序全局变量和静态局部变量。
·bss:未初始化的C程序全局变量和静态局部变量。
·debug:调试符号表,调试器用此段的信息帮助调试。
readelf -S可查看各个section的信息
readelf -S hello
2、反汇编ELF
想查看ELF文件包含的指令和数据,需要使用反汇编的方法
用命令:
objdump -D hello
使用objdump -S将其反汇编并且将其c语言源代码混合显示出来:
gcc -o hello -g hello.c
objdump -S hello