binutils工具集,软件开发利器

如果使用gcc编译器,那么在开发中就离不开使用与之配套的工具集(tool chain),即binutils。工具集中的部分工具除了被gcc在后台使用为我们创建程序文件之外,其他则有助于方便开发和调试.


在binutils工具集中,以下工具是我们在做嵌入式软件开发时需要掌握的。


·as

是汇编编译器,用于将汇编代码转换为目标文件。

·addr2line

用于得到程序指令地址所对应的函数,以及函数所在的源文件名和行号。指令地址翻译器

·ar

用于创建和修改档案文件,以及从档案文件中抽取文件。静态库(.a文件)就是一种档案文件,需要用它生成和管理。静态库生成器

·ld

是链接器

·nm

用于列出程序文件中的符号及符号在内存中(开始)地址。符号包含C程序中的函数名和变量名。(符号显示器)

·objcopy

可以用来从程序文件中拷贝出我们所指定的段。在将引导加载器烧至闪存中时,有时需要通过从程序中抽取段的方式生成烧写文件,这时objcopy工具就能派上用场。(段剪辑器)

·objdump

能显示程序文件的相关信息和对程序文件进行反汇编。(信息查看器)

·ranlib

用于生成一个档案文件的内容索引,以加快对档案文件的查找速度。将该工具运用与静态库能提高库参与链接的效率。(库索引生成器)

·size

用于了解程序文件中各段的大小。(段大小查看器)

·string

用于查看程序文件内的可显示字符串。(字符串窥视器)

·strip

用于剥去程序文件的调试信息,以减少程序文件所占用的存储空间。这个工具对于存储空间有限的嵌入式系统尤为重要。(程序文件瘦身器)


在嵌入式开发环境中,编译器的名称往往不是gcc,而是像arm-rtems-gcc这样的名称。对于这种命名形式的编译器,读者可以找到arm-rtems-addr2line,arm-rtems-objdump等相应名称的工具,这是GNU工具集的命名惯例。



addr2line,指令地址   翻译器

要使用addr2line,在编译器必须带上-g加加上调试信息。

addr2line 地址 -f -e a.out将显示地址所指位置在哪个文件中哪个函数中,该函数在该函数的第几行。比如用nm查看段位置foo函数紧接在main函数前面,那么参数给的地址在之间的话,得到结果就是:foo,文件,foo在文件中的行号

用在C++上可能得到的函数名与原来的函数名不一样,乱码。这体现了C++的语言特性。在GNU工具集存在“mangling”这样一个称呼,而在window中称为“decorating”,都是指对C++中的函数名进行名字分裂。名字分裂是因为在C++源程序中允许多个函数重名的(重载)。为了做到这点,C++编译器的处理方法是对每个函数,将根据其输入参数采用一定的编码方式,形成不同的C函数名,这一过程就是名字分裂过程。可以加上--demangle=gnu-v3 将输出未分裂的番薯名。



ar,静态库生成器

如果要将多个.o文件生成一个库文件,则存在两种类型。一种是静态库,在Linux世界里其后缀是.a;另一种是动态库,其后缀是.so

对于嵌入式系统,大多数情况下都是整个软件就是一个可执行程序且不支持动态加载的方式,即以静态库为主。

binutils中的ar被用来管理静态库。先看看一个静态库中到底有什么。拿库文件/lib/libc.a为例。对其采用ar的x参数进行解压操作:

ar -x libc.a

ls

acltotext.o    fsetpos.o   initgroups.o    recomp.o   tmpfile.o   chown.o  fstat.o    lchown.o  ftello.o  libc.a  lseek.o  ..............等

对于解压后的.o文件并不陌生。每个.o文件差不多都能找到其文件名所对应的C库函数。采用GNU工具集进行开发时,一个静态库其实就是将.o文件打包而生成的档案文件。

如何用ar生成静态库:ar crs libmy.a  foo.o   bar.o  将foo.o和bar.o放入静态库libmy.a中。其中c参数表示创建一个档案文件,而r参数指示将文件增加到所创建的库文件中,s参数是为了生成库索引以提高库被链接时的效率。

采用t参数可以查看一个静态库有什么内容。ar t libmy.a 结果:foo.o bar.o

使用d参数可以删除库中的目标文件,ar d libmy.a foo.o                ar  t  libmy.a 结果:bar.o


nm,符号显示器

总体来说nm用于列出程序文件中的符号,实例:

nm  -n  main.exe

00401100    T    foo

0040111c    T    main

004011b8    T    printf

nm所列出的每一行由三部分组成。第一列是指程序运行时符号在内存中的地址,它表示函数或变量的开始地址;第二列是指相应的符号存放在哪一个段;最后一列则是符号的名称。

第二列信息非常有用,下面列出常见字母的含义:

————————————————————————————————

A :表示符号所对应的值是绝对的且在以后的连接过程中也不会改变 

B或b:表示符号位于未初始化的数据段(.bss)中                                           

C:表示没有被初始化的公共符号                                                               

D或d:表示符号位于初始化的数据段(.data)中                                      

N:表示符号是调试用的                                                                            

p:表示符号位于一个栈回溯段中                                                               

R或r :表示符号位于只读数据段(.radata)中                                          

T或t :表示符号位于代码段(.text)中                                                        

U :表示符号没有被定义                                                                             

————————————————————————————————

·静态变量和全局变量在哪个段与其是否初始化有关,未初始化在.bss中,否则在.data中

·函数无论是静态还是非静态的,总是被分配在.text段中。字母“t”的大小写表示了符号是否是静态函数,小写表示静态。

·函数内的局部变量由于是在栈上的,所以在nm中看不到他们。


objdump,信息查看器

有时需要知道所生成文件的段信息以分析问题,或则查看C语言所对应的汇编的代码,此时objdump帮了大忙。

-h选项,用来查看程序文件中的段信息,从得出的结果中可以看到每个段的大小,以及当程序运行时各段在内存中的开始地址。File off信息表示每个段在程序文件中的存储位置。对于引导加载器来说,当加载程序时,就是通过File off信息从文件中读出相应段的内容,然后将这一内容写到所指定的VMA(内存)处。“Algn”指示了每一段的边界对齐字节数是多少。另外还可以看到每个段的属性,比如READONLY,ALLOC等。也可以看到以.debug _开头的,这些段是调试时需要使用的,其中存储了程序中每一个符号的调试信息。这些调试信息采用一定的编码格式,最常用的格式是DWARF(Debugging With Attributed Record Formats),DWARF规范可以从网站上http://www.dwarfstd.org/找到。使用-W选项可以查看的DWARF信息。正是因为其中存在每个函数的起始地址信息,所以用addr2line工具才能反向找到指令地址所对应的函数名,文件和文件行号。总而言之,所有在调试时能查看的符号信息都采用DWARF格式放在调试段中,包括局部变量的栈帧中为重。当通过调试器查看一个变量的值时,调试器首先通过DWARF格式中的信息找到变量在内存中的地址,然后将内存中内容根据变量的类型显示给我们看。

-d 选项可以显示汇编代码

 -S  -d  选项在反汇编时同时显示C/C++源程序(不能对编译程序时使用优化选项,否则因为程序被优化是的无法与源程序一一对应)

-f 选项可以显示程序文件头信息(其中的start address指示执行时的入口地址,即第一条指令在内存中的地址)

-s -j 能查看一个段的具体内容,如objdump   -s  -j    .data   main


objcopy,段剪辑器

-j  参数,用于指定拷贝程序中的哪一段

-R 相反,用于删除一个段

如:objcopy   - j   .text  main     main.text表示将main中的.text拷贝到main.text文件中,要拷贝多个段,可以多次-j,如objcopy   -j  .text   -j    .data   -j   .bss   main     main2

生成一个不含.text段的文件objcopy   -R  .text   main   notextmain


ranlib,库索引生成器

ar的s参数有同样的功能。就是在档案文件中生成索引。当档案文件生成索引后,对其内文件的存取速度将更快。如果档案文件是静态库,那么生成索引文件后的库链接速度更快。     (ranlib    libmy.a)

可以使用nm加上-s参数查看档案文件中的索引信息


size,段大小观察器

用objdump查看时,出了.text    .data  和.bsss三个段外,还有.rdata和.idata两个段。在size信息中,.rdata段被归到.text段中,而.idata段被归到.data中。如果使用-A参数,size将给出更详细的信息。


strings,字符串窥视器

工作原理:针对输入数据查找以换行符号或NUL结尾的四个(或以上)可打印的序列,再将结果打印到标准输出。

strings mian

从结果中可以看到程序中定义的字符串,还有很多函数名。

因为这些信息存放在.data(或.rdata段)中,这些信息会向他人泄露程序的“痕迹”。

所以如果在程序中要定义密码等加密信息,则最好不要用字符串形式,或则定义也不要直接用它作为密码,而采用一定的算法加工,防止其他人猜到它。

strings对于调试也是有用的。比如将版本信息放入程序中,当发布软件时,不知道版本号,可以用strings获得版本信息。

另外strings工具与具体的处理器无关,也就是说可以在x86处理器上用strings查看其他处理器上运行的程序文件中的字符信息。


strip,瘦身器

用于剥去程序文件中的调试信息,减少程序文件的大小。objcopy 加--strip-debug参数也可以实现这点。strip所就有的功能,objcopy也都有。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值