一、GCC交叉编译工具链
GCC编译工具链包含了GCC编译器在内的一整套工具,主要包含了GCC编译器、Binutils工具集、glibc标准函数库。一般情况下,我们说的GCC编译工具链就是指GCC编译器。
1. GCC编译器
GCC原名为GNU C语言编译器(GNU C Compiler),只能对C语言进行编译等处理。后来随着其功能的扩展,可以支持更多编程语言,如C++、Java、Fortran、Pascal、Objective -C、Ada、Go以及各类处理器架构上的汇编语言等。所以,现在我们所说的GCC是指GNU编译器套件(GNU Compiler Collection),并且现在的GCC还可以进行交叉编译(在一个平台下编译包含另一个平台的代码)。通过下面的命令可以查看GCC版本和GCC的安装路径。
gcc -v
which gcc
C语言编译器是gcc-core,C++语言编译器是gcc-c++。
2. Binutils工具集
(1)链接器与汇编器
binutils(bin utility,GUN二进制工具集),GNU binutils是一组二进制工具集。包括:addr2line ar gprof nm objcopy objdump ranlib size strings strip等。工具集默认在目录 /usr/bin 目录下,在这个工具集中我们必须要知道的工具有两个:ld 链接器和 as 汇编器。这两个工具和我们编译一个源文件息息相关。
as 汇编器用于把汇编文件(汇编语言)转换为目标问价(机器码),完成 .s到 .o 的工作;
ld 链接器用于把编译生成的多个目标文件链接组织为可执行文件;
这两个工具我们一般不会直接调用,它们大多是在GCC编译文件的时候由GCC编译器调用的。
(2)其它常用工具介绍及用法演示
首先我们准备几个文件,包括.s文件.o文件.c文件.i文和可执行文件,具体这些文件怎么生成,以及这些文件是什么含义在后面的章节有详细介绍(可以先看下一章再返回看本小节)。
① size: 列出文件每个部分的内存大小,如代码段、数据段、总大小等。
输入 size 文件名 就可以看到文件的内存占用情况
text是代码段,用于存放代码;data是用来放已初始化的数据;bss是用来放未初始化的数据。
② readelf: 显示有关ELF格式文件内容的信息。ELF格式是UNIX系统实验室作为应用程序二进制接口开发的。ELF格式是Unix/Linux平台上应用最广泛的二进制工业标准之一。
可以输入 readelf 查看说明及选项参数
readelf -h 显示可执行文件或目标文件的ELF Header的文件头信息(就是ELF文件开始的前52个字节)
③ nm: 查看目标文件中出现的符号(函数、全局变量等)。
上面可以看到,nm列出的信息总共有三列:第一列是指程序运行时的符号所对应的地址,对于函数来说表示的是函数的开始地址,对于变量则表示的是变量的存储地址;第二列是指相应符号是放在内存的哪一个段;第三列则是指符号的名称。这个命令通常会和 addr2line (后面会介绍)一块使用,因为nm列出了符号的地址,但是并没有行号和源文件名称,而 addr2line 可以根据符号地址给出行号和源文件目录及名称。更多信息可以查看man手册
nm只能用于目标文件和可执行文件,对普通文件无效
④ objcopy: 将目标文件的一部分或者全部内容拷贝到另外一个目标文件中,或者实现目标文件的格式转换。可用于目标文件格式转换,如.bin转换成.elf、.elf转换成.bin等。
比如,格式转换命令
objcopy -O binary xx xx.bin
⑤ objdump: 显示程序文件相关信息,最主要的作用是反汇编。这里介绍两个常用的选项参数:
可以通过 -d 选项来对可执行文件进行反汇编
也可以对目标文件反汇编
通过 -h 选项查看目标程序中的段信息和调试信息
⑥ addr2line: 将程序地址翻译成文件名和行号;给定地址和可执行文件名称,它使用其中的调试信息判断与此地址有关联的源文件和行号,通常搭配 nm 使用。
这个命令一般用于调试信息时快速定位错误位置。它的命令用法为addr2line 地址 -e 可执行文件名。为演示这个命令用法,首先创建一个文件,这个文件包含一个函数,函数功能为打印函数地址,代码如下
然后编译这个文件,编译时必须要加上 -g 包含调试信息,然后运行,得到打印出的地址
输入命令addr2line 地址 -e 可执行文件名 -f,可以看到文件位置,行号都打印出来了
我么可以确认一下是不是第11行,cat -n 显示行号
⑦ strings: 显示程序文件中的可显示字符串。
可以通过管道和grep过滤自己需要的信息
3. glibc库
glibc是GNU发布的libc库,即c运行库。glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc。glibc和libc都是Linux下的C函数库。libc是Linux下的ANSI C函数库,glibc是Linux下的GUN C函数库。
在CentOS操作系统下,查看glibc的版本
如果你是Ubuntu系统,可以用这个命令
/lib/x86_64-linux-gnu/libc.so.6