GNU工具链 (GNU Toolchain) 是一组用于开发应用程序和操作系统的编程工具的集合,这些工具构成了一个完整的系统。GNU工具链包括GCC、GNU Binutils、GNU m4、GNU Autoconf和GNU make等部分。这里主要介绍GCC、Binutils和Glibc。


GNU Compiler Collection
  GCC全称GNU Compiler Collection,其主要的工具包括​​​cpp、g++、gcc、gcov、gprof​​​等。其中cpp是C预处理器,主要用于在编译C、C++或Objective-C源代码之前对它们进行预处理,由编译器自动调用;g++和gcc可以大致认为分别是C++和C编译器 (当然,事实上它们都只是driver程序,分别再调用cc1plus、cc1和汇编器、链接器而已);gcov是一个检测代码覆盖率的工具,gprof是一个profile工具,这两个工具主要是跟GCC配合来分析并提高程序的性能,此时应用程序进行编译的时候需要使用类似以下方法:​​CFLAGS="-fprofile-arcs -ftest-coverage" ./configure --config-options​(./configure –help)。

GNU Binutils
  GNU Binutils (Binary Utilities) 是一组二进制工具集。其中主要的两个工具是as和ld。as是GNU汇编器,通常也称为GAS (GNU Assembler),ld是GNU链接器;as对GCC的输出文件进行汇编产生目标文件,然后由ld链接目标文件、重定位数据产生可执行文件。另外,GNU Binutils还包括其它一些工具:

  * addr2line用于将程序中的地址对应到文件名和相应的行号。给定一个地址和一个可执行文件,addr2line使用可执行文件中的调试信息来确定该地址所对应的文件和行号。​​addr2lineaddr -eexe -f​​。

  * ar用于建立、修改和提取档案文件 (archives)。档案文件经常被用作库文件,来保存程序常用的函数过程。

  * c++filt:我们知道,C++和Java中都有重载函数的特性,编译器要区分重载函数,就需要对函数标识符进行编码转换成一个汇编级别的标签 (label),这个过程称为名字改编 (name mangling) 或名字修饰 (name decoration)。而c++filt所执行的就是这个过程的逆过程。

  * dlltool用于创建Windows动态链接库。

  * gold是一种比ld更快的、但是只针对ELF文件格式的链接器。

  * nm用于列出二进制文件 (包括库文件和可执行文件) 中的符号,这些符号可以是函数、全局变量、静态变量等等。

  * objcopy用于将一种格式的目标文件复制成另外一种格式。objcopy使用GNU BFD库来读写目标文件,复制过程中要进行的转换由objcopy的命令行参数进行控制。

  * objdump用于列出关于二进制文件的各种信息。例如,可以使用它来反汇编可执行文件:​​objdump -Dexe​​;可以只显示指定段 (section) 的内容:​​objdump -jsection -sexe​。

  * ranlib用于为档案文件生成索引信息,这样可以提高档案文件的访问速度。

  * readelf类似于objdump,但是它只能处理ELF格式的文件,并且没有使用GNU BFD库。

  * size用于列出目标文件或者档案文件各段的大小。

  * strings用于列出目标文件中的可打印字符串,字符串的最小长度由-n参数指定,默认为4。

  * strip用于移除目标文件中的符号,以减少程序文件的大小,这对于嵌入式系统比较有用。

  上述这些程序大部分都使用GNU BFD (Binary File Descriptor) 库,BFD库使得应用程序可以使用同样的接口来操作不同的二进制文件格式;并且这些程序很多也都使用opcodes库来汇编和反汇编机器指令。

GNU C Library
  Glibc就是GNU的C标准库,主要支持GNU Hurd和Linux两种内核。Glibc是移植GNU工具链时一个不可或缺的部分。Glibc主要由两部分组成,一部分是头文件;另一部分是库的二进制文件,包括动态和静态两个版本,一般位于/lib/libc.so.6和/usr/lib/libc.a。

  另外,Glibc还有几个辅助程序运行的运行库 (C RunTime Library),分别是/usr/lib/crt1.o、/usr/lib/crti.o和/usr/lib/crtn.o,其中crt1.o中包含程序的入口函数_start以及两个未定义的符号__libc_start_main和main,由_start负责调用__libc_start_main初始化libc,然后调用我们源代码中定义的main函数;另外,由于类似于全局静态对象这样的代码需要在main函数之前执行,crti.o和crtn.o负责辅助启动这些代码。另外,Gcc中同样也有crtbegin.o和crtend.o两个文件,这两个目标文件用于配合glibc来实现C++的全局构造和析构。

  在进行嵌入式开发时,还有两种流行的C库分别是​​Newlib​​​和​​uClibc​​。