Linux binutils工具集简介

http://hi.baidu.com/luo9168/blog/item/dcb59901a9bc3a057bec2c88.html

 

官方下载地址

Binutils (2.14):

ftp://ftp.gnu.org/gnu/binutils/

 

在Ubuntu上

 

sudo apt-get isntall binutils 就可以了……

 

Binutils的内容

Binutils 是一组开发工具,包括连接器,汇编器和其他用于目标文件和档案的工具。

 

安装下列程序: addr2line, ar, as, c++filt, gprof, ld, nm, objcopy, objdump, ranlib, readelf, size, strings 和 strip

 

安装下列库文件: libiberty.a, libbfd.[a,so] 和 libopcodes.[a,so]

 

 

简短说明

addr2line 把程序地址转换为文件名和行号。在命令行中给它一个地址和一个可执行文件名,它就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件以及行号。

 

ar 建立、修改、提取归档文件。归档文件是包含多个文件内容的一个大文件,其结构保证了可以恢复原始文件内容。

 

as 主要用来编译GNU C编译器gcc输出的汇编文件,产生的目标文件由连接器ld连接。

 

c++filt 连接器使用它来过滤 C++ 和 Java 符号,防止重载函数冲突。

 

gprof 显示程序调用段的各种数据。

 

ld 是连接器,它把一些目标和归档文件结合在一起,重定位数据,并链接符号引用。通常,建立一个新编译程序的最后一步就是调用ld。

 

nm 列出目标文件中的符号。

 

objcopy把一种目标文件中的内容复制到另一种类型的目标文件中.

 

objdump 显示一个或者更多目标文件的信息。显示一个或者更多目标文件的信息。使用选项来控制其显示的信息。它所显示的信息通常只有编写编译工具的人才感兴趣。

 

ranlib 产生归档文件索引,并将其保存到这个归档文件中。在索引中列出了归档文件各成员所定义的可重分配目标文件。

 

readelf 显示ebf格式可执行文件的信息。

 

size 列出目标文件每一段的大小以及总体的大小。默认情况下,对于每个目标文件或者一个归档文件中的每个模块只产生一行输出。

 

strings 打印某个文件的可打印字符串,这些字符串最少4个字符长,也可以使用选项-n设置字符串的最小长度。默认情况下,它只打印目标文件初始化和可加载段中的可打印字符;对于其它类型的文件它打印整个文件的可打印字符,这个程序对于了解非文本文件的内容很有帮助。

 

strip 丢弃目标文件中的全部或者特定符号。

 

libiberty 包含许多GNU程序都会用到的函数,这些程序有: getopt, obstack, strerror, strtol 和 strtoul.

 

libbfd 二进制文件描述库.

 

libopcodes 用来处理opcodes的库, 在生成一些应用程序的时候也会用到它, 比如objdump.Opcodes是文本格式可读的处理器操作指令.

 

 

Binutils 安装依赖关系

Binutils 依赖于: Bash, Coreutils, Diffutils, GCC, Gettext, Glibc, Grep, Make, Perl, Sed, Texinfo.

 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luocolor/archive/2008/04/15/2295056.aspx

 

GNU binutils是一组二进制工具集。包括:addr2line   ar   gprof   nm   objcopy   objdump   ranlib   size   strings   strip. 本文归纳他们的常用法。

 

ar

 

ar用于建立、修改、提取档案文件(archive)。archive是一个包含多个被包含文件的单一文件(也称之为库文件),其结构保证了可以从中检索并得到原始的被包含文件(称之为archive中的member)。member的原始文件内容、模式(权限)、时间戳、所有着和组等属性都被保存在 archive中。member被提取后,他们的属性被恢复到初始状态。

ar主要用于创建C库文件(关于.o目标文件的生成和共享库的详细介绍,参考gcc笔记)

 

创建静态库

(1) 生成目标文件:

 

$ gcc -Wall -c file1.c file2.c file3.c

不用指定生成.o文件名(默认生成file1.o, file2.o, file3.o)。

 

(2) 从.o目标文件创建静态连接库:

$ ar rv libNAME.a file1.o file2.o file3.o

ar生成了libNAME.a库,并列出库中的文件。

r : 将flie1.o, file2,o, file3.o插入archive,如故原先archive中已经存在某文件,则先将该文件删除。

v : 显示ar操作的附加信息(如被处理的member文件名)

 

注: 对于BSD系统, 还需要在创建静态库之后创建索引: $ ranlib libNAME.a Linux中不需要这一步(运行它也是无害的).

 

创建动态库(利用gcc,未用ar)

 

(1) 生成目标文件

 

$ gcc -Wall -c -fpic file1.c file2.c file3.c

 

-fpic: 指定生成的.o目标文件可被重定址. pic是position idependent code的缩写: 位置无关代码.

 

(2)生成动态库文件

 

$ gcc -shared -o libNAME.so file1.o file2.o file3.o

 

一般地, 连接器使用main()函数作为程序入口. 但在动态共享库中没有这样的入口. 所以就要指定-shared选项来避免编译器显示出错信息.

 

实际上, 上述的两条命令可以合并为下面这条:

 

$ gcc -Wall -shared -fpic -o libNAME.so file1.c file2.c file3.c

 

 

此后,将main函数所在的程序与libNAME.so连接(注意库连接路径和头文件包含路径,以及连接顺序!参考gcc笔记)

至此,与动态库连接的函数编译成了一个可执行文件。貌似成功了,但还差最后一步。如果直接运行该程序,会给出这样的错误信息:

 

error while loading shared libraries: libhello.so:

cannot open shared object file: No such file or directory

 

这是因为与动态库连接的程序在运行时,首先将该动态库加载到内存中,而gcc默认加载动态库文件所在目录为/usr/local/lib, /usr/lib。刚才的程序虽然能编译成功,但如果我们自己建立的动态库没有位于默认目录中,则执行时会应为无法找到它而失败。

解决办法:改变加载路径对应的环境变量,然后再执行。

export LD_LIBRARY_PATH=动态库所在目录:$LD_LIBRARY_PATH

 

查看archive内容

 

$ ar tv archiveNAME

 

t : 显示archive中member的内容,若不指定member,则列出所有。

v : 与t结合使用时,显示member的详细信息。

 

要想进了解ar的详细选项,参考ar的on-line manual

 

 

nm

 

nm用来列出目标文件中的符号,可以帮助程序员定位和分析执行程序和目标文件中的符号信息和它的属性。

如果没有目标文件作为参数传递给nm, nm假定目标文件为a.out.

这里用一个简单的示例程序来介绍nm的用法:

 

main.c:

int main(int argc, char *argv[])

{

hello();

bye();

return 0;

}

 

hello.c:

void hello(void)

{

printf(“hello!
“);

}

 

bye.c:

void bye(void)

{

printf(“good bye!
“);

}

 

运行下列命令:

$ gcc -Wall -c main.c hello.c bye.c

gcc生成main.o, hello.o, bye.o三个目标文件(这里没有声明函数原型,加了-Wall,gcc会给出警告)

$ nm main.o hello.o bye.o

 

结果显示如下:

main.o:

U bye

U hello

00000000 T main

 

hello.o:

00000000 T hello

U puts

 

bye.o:

00000000 T bye

U puts

 

结合这些输出结果,以及程序代码,可以知道:

对于main.o, bye和hello未被定义, main被定义了

对于hello.o, hello被定义了, puts未被定义

对于bye.o, bye被定义了,puts未被定义

 

几个值得注意的问题:

(1)”目标文件”指.o文件, 库文件, 最终的可执行文件

.o : 编译后的目标文件,即含有最终编译出的机器码,但它里面所引用的其他文件中函数的内存位置尚未定义.

(2)如果用nm查看可执行文件, 输出会比较多, 仔细研究输出, 可以对nm用法有更清醒的认识.

(3)在上述hello.c, bye.c中, 调用的是printf(), 而nm输出中显示调用的是puts(), 说明最终程序实际调用的puts(), 如果令hello.c或bye.c中的printf()使用格式化输出,则nm显示调用printf(). ( 如: printf(“%d”, 1); )

关于nm的参数选项,参考on-line manual

 

 

objcopy

 

objcopy可以将一种格式的目标文件转化为另外一种格式的目标文件. 它使用GNU BFD库进行读/写目标文件.使用BFD, objcopy就能将原格式的目标文件转化为不同格式的目标文件.

以我们在nm中使用的hello.o目标文件和hello可执行为例:

 

$ file hello.o hello

file命令用来判别文件类型, 输出如下:

hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.0, dynamically linked (uses shared libs), not stripped

现在运行objcopy来改变hello的文件类型: 原先它是ELF格式的可执行程序, 现将它转换为srec格式. srec格式文件是Motolora S-Record格式的文件, 主要用来在主机和目标机之间传输数据.

$ objcopy -O srec hello hello_srec

$ file hello.o hello

 

file命令结果: hello_srec: Motorola S-Record; binary data in text format

 

注意objcopy的格式, “-O”指定输出文件类型; 输入文件名和输出文件名位于命令末尾. 关于objcopy命令的详细选项, 参考on-line manual

 

 

objdump

 

objdump用来显示目标文件的信息. 可以通过选项控制显示那些特定信息. objdump一个最大的用处恐怕就是将C代码反汇编了. 在嵌入式软件开发过程中, 也可以用它查看执行文件或库文件的信息.

下面我们用上文提到的hello可执行文件和hello_srec可执行文件为例, 介绍objdump的简单用法:

$ objdump -f hello hello_srec

 

输出如下:

hello:     file format elf32-i386

architecture: i386, flags 0×00000112:

EXEC_P, HAS_SYMS, D_PAGED

start address 0x080482c0

 

hello_srec:     file format srec

architecture: UNKNOWN!, flags 0×00000000:

start address 0x00000000080482c0

-f : 显示目标文件的头文件概要信息.

 

生成反汇编代码:

$ objdump -d hello.o

 

显示如下:

hello.o:     file format elf32-i386

 

Disassembly of section .text:

 

00000000 <hello>:

0:   55                      push   %ebp

1:   89 e5                   mov    %esp,%ebp

3:   83 ec 08                sub    $0×8,%esp

6:   83 ec 0c                sub    $0xc,%esp

9:   68 00 00 00 00          push   $0×0

e:   e8 fc ff ff ff          call   f <hello+0xf>

13:   83 c4 10                add    $0×10,%esp

16:   c9                      leave

17:   c3                      ret

 

-d : 显示目标文件中机器指令使用的汇编语言. 只反汇编那些应该含有指令机器码的节(显示.text段); 如果用-D, 则反汇编所有节的内容.

关于objcopy命令的详细选项, 参考on-line manual

 

 

readelf

 

readelf用来显示ELF格式目标文件的信息.可通过参数选项来控制显示哪些特定信息.(注意: readelf不支持显示archive文档, 也不支持64位的ELF文件).

下面利用先前的hello可执行文件演示readelf的简单用法:

$ readelf -h hello

 

ELF Header:

Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00

Class:                               ELF32

Data:                                            2′s complement, little endian

Version:                                        1 (current)

OS/ABI:                          UNIX – System V

ABI Version:                     0

Type:                                              EXEC (Executable file)

Machine:                                        Intel 80386

Version:                                          0×1

Entry point address:                       0x80482c0

Start of program headers:            52 (bytes into file)

Start of section headers:         3848 (bytes into file)

Flags:                           0×0

Size of this header:                          52 (bytes)

Size of program headers:            32 (bytes)

Number of program headers:          7

Size of section headers:          40 (bytes)

Number of section headers:            34

Section header string table index:   31

 

注意: readelf只能用于ELF格式目标文件, 且选项中至少要指定一个(除V, H外)的选项!

 

 

gprof

 

gprof被用来测量程序的性能. 它记录每个函数被调用的次数以及相应的执行时间. 这样就能锁定程序执行时花费时间最多的部分, 对程序的优化就可集中于对它们的优化.

关于gprof更多的描述,参考gprof的on-line manual

 

这部分文章来自:http://blog.chinaunix.net/u/13991/showart_104690.html

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>