现在的位置: 首页 > 综合 > 正文

我的binutils工具集

2013年10月21日 ⁄ 综合 ⁄ 共 3635字 ⁄ 字号 评论关闭

1.addr2line能够把程序地址转换为文件名和行号,前提是这个可执行文件包括调试符号

 1 #include <stdio.h>

  2 

  3 void foo()

  4 {

  5     printf("The address of foo() is %p\n",foo);

  6 }

  7 int main()

  8 {

  9     foo();

 10     return 0;                                                               

 11 }

运行如下命令,得到:

现在,我们可以用这一地址来看看addr2line是如何使用的。在终端中运行如下命令,从命令的运行结果可以看出,addr2line工具正确指出了0x80483c4所对应的程序的具体位置以及所对应的函数名。在调用 addr2line 工具时,要使用 -e 选项来指定可执行映像是 test。通过使用 -f 选项,可以告诉工具输出函数名。

2.nm可以列出目标文件中的符号。用法虽然简单,但是功能很强大。符号是指函数名或变量。 

nm所列出的每一行有三部分组成:第一列是指程序运行时的符号所对应的地址,对于函数则地址表示的是函数的开始地址,对于变量则表示变量的存储地址;第二列是指对应符号放在哪一个段;而最后一列则是指符号的名称。在前面我们讲解addr2line时,我们提到addr2line是将程序地址转换成这一地址所对应的具体函数是什么,而nm则是全面的列出这些信息。但是,nm不具备列出符号所在源文件及其行号这一功能,因此,我们说每一个工具有其特定功能。

 为了更清楚的理解nm中的符号和我们程序中的关系,我们看一下下列程序其所对应的nm输出结果。

1 #include <stdio.h>

  2 int gloable1;

  3 int gloable2 = 9;

  4 

  5 static int static_gloable1;

  6 static int static_gloable2 = 99;

  7 

  8 void foo()

  9 {

 10     static int intermal1;

 11     static int intermal2 = 999;

 12 }

 13 

 14 static void bar()

 15 {

 16     

 17 }

 18 

 19 int main()

 20 {

 21     int local;

 22     int local2 = 9999;

 23     foo();

 24     return 0;                                                               

 25 }

从nm输出的信息,我们可以看出:

Ø 不论一个静态变量是定义在函数内还是函数外,其在程序段中的分配方式都是一样的。如果这一静态变量是初始化好的,那么被分配在data段中,否则就在bss段中

Ø 非静态的全局变量,其分配的段也是和是否初始化有关。如果被初始化了,分配在data段中,否则就在bss段中。

Ø 函数无论是静态还是非静态的,其总是被分配在text段,但T(t)的大小写代表这一符号所对应的函数是否是静态函数。

Ø 函数内的局部变量并不是分配在databsstext段中,其分配在栈上,nm是看不到的。

3. readelf –h test

这条命令查看可执行文件test”section的头信息。

每一个头信息都是一个Elf32_Shdr结构,其成员含义如下所述:

typedef struct {

      Elf32_Word sh_name; //指定了这个section的名字

      Elf32_Word sh_type; //sections按内容和意义分类

      Elf32_Word sh_flags; //sections支持位的标记,用来描述多个属性

      Elf32_Addr sh_addr; //section 在内存中的位置

      Elf32_Off  sh_offset; //section的字节偏移量

      Elf32_Word sh_size; //section的字节大小

      Elf32_Word sh_link; //section报头表的索引连接

      Elf32_Word sh_info; //保存着额外的信息

      Elf32_Word sh_addralign; //地址对齐的约束

      Elf32_Word sh_entsize; //保存着一张固定大小入口的表

  } Elf32_Shdr;

4.ar用来管理档案文件,在嵌入式系统当中,ar主要用来对静态库进行管理。现在先让我们看看静态库里有些什么。我们采用lib.a为例,对其用ar -t来查看,如下所示:

采用GNU工具集进行开发时,一个静态库其实是将所有的.o文件打成一个档案包。现在,我们就来看看如何使用ar来生成静态库。

foo.c

#include  <stdio.h>

void foo()

{

printf("This is foo()\n");

}

bar.c

#include  <stdio.h>

void  bar()

{

printf("This is bar()\n");

}

我们希望将foo()和bar()函数做成一个库,为此先要将它们编译成.o目标文件。有了目标文件之后,我们采用ar命令来生成libmy.a库,如下所示。其中,arc参数表示创建一个档案文件,而r参数表示增加文件到创建的库文件中,s参数是为了生成库索引以提高连接速度。

   

现在可以在当前目录下看到一个libmy.a文件,这就是我们的静态库。下面验证库是否可用,

 #include <stdio.h>

  2 int main()                                                                  

  3 

  4 {

  5     foo();

  6     bar();

  7     return 0;

  8 }  

     编译我们的验证程序,并与libmy.a进行连接,运行程序,从运行的运行结果可以看出,我们的libmy.a是起作用的。

如果想删除档案文件中的文件,我们可以使用d参数。下面是使用d参数删除libmy.a中的foo.o文件。从操作的最后结果看,当执行完d操作后,libmy.a中只存在一个bar.o文件了。

现在总结一下ar的几个参数:采用c参数创建一个档案文件,r参数表示向档案文件增加文件,t参数用于显示档案文件中存在哪些文件,s参数用于指示生成索引以加快查找速度,d参数用于从档案文件中删除文件,最后x参数是用于从档案文件中解压文件。

5.objdump可以显示一个或者更多目标文件的信息,主要用来反汇编。

如下所示(部分未显示):

6.objcopy可以进行目标文件格式转换。

arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec

arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

7.size工具很简单,就是列出程序文件中各段的大小。

 1 #include <stdio.h>

  2 int gloable1;

  3 int gloable2 = 9;

  4 

  5 static int static_gloable1;

  6 static int static_gloable2 = 99;

  7 

  8 static void foo()

  9 {

 10     static int intermal1;

 11     static int intermal2 = 999;

 12 }

 13 

 14 static void bar()

 15 {

 16 }                                                                                                                                         

 17 

 18 int main()

 19 {

 20     int local;

 21     int local2 = 9999;

 22     foo();

 23     return 0;

 24 }

 

8.strip用来丢弃目标文件中的全部或者特定符号,减小文件体积。对于嵌入式系统,这个命令必不可少。

9.strings用来打印某个文件的可打印字符串。

抱歉!评论已关闭.