结合SimpleSection实例练习Binutils工具集的使用方法

来源:互联网 发布:sql left join on 编辑:程序博客网 时间:2024/05/21 22:28

想要对ELF等二进制文件格式有深入的了解,熟练使用readelf、objdump、nm、size等二进制工具是非常必要的,接触好长时间了还没有一个系统性的认识,这里总结一下加深知识,即便以后忘了,也有资料可以查。这里只记录各个命令的输出和作用,对ELF文件格式不再说明,不知道的可以Google。

SimpleSection的源码:

#include <stdio.h>
int global_init_var = 0;
int global_uninit_var;
void func(int i)
{
  printf("%d\n", i);
}
int main(void)
{
  static int static_init_var = 85;
  static int static_uninit_var;
  int a = 1;
  int b;
  func(static_init_var + static_uninit_var +
      a + b);

  return 0;

}


文章整体以链接视图和加载视图来区分,曾经我对节表和段表的区别一直不太明白,很容易混淆,节表是对于链接视图而言的,对链接器的工作有指示作用,所以目标文件必须有节表,而没有段表。而段表是对于加载视图而言的,对系统加载可执行文件到内存中有指示作用,系统加载器只会去找段表,忽略节表,所以可执行文件必须有段表,有没有节表无所谓。其它更具体信息大家可以Google。

一、链接视图

由于ELF文件分为链接视图和加载视图,所以首先看编译后的目标文件的结构,即链接前的.o文件的结构,这个是链接视图。因为我开发用的是Mac系统,用系统提供的gcc编译出的不是ELF格式,所以我用Android NDK交叉编译。

  • 查看目标文件的头部信息,命令:
readelf -h SimpleSection.o

    输出:
              

因为这个是链接视图,所以只有节表,没有段表。
另外,头部中有个e_shStrndx字段,即上图中的字符串表索引节头,它表示的是节表中所用到的字符串(比如节的名字等)所在的节的索引下标,这里是9,结合下面的看就明白了。
  • 查看目标文件的各个节表信息,命令:
readelf -S SimpleSection.so

    输出:


上面看头部信息的时候e_shstrndx的值是9,这里就可以看到索引下表是9的节表名字是shstrtab表,即节表字符串表,存储的是节表中用到的字符串。

而上图各个字段的含义可以自己去查,这里只说明几个字段。

sh_link和sh_info字段的含义是与sh_type字段相关的,对于SHT_DYNAMIC类型的节,它的sh_link字段表示的是该节所使用的字符串表在节头部表中的下标;对于SHT_HASH类型的节,它的sh_link字段表示的是该节所使用的符号表在节头部表中的下标;而对于SHT_REL和SHT_RELA类型的节,它的sh_link字段同样是表示该节所使用符号表在节头部表中的下标,而sh_info字段表示该重定位表所作用的节在节头部表中的下标。上图中.rel.text节的sh_link字段等于10,表示它用的符号表是.symtab,而sh_info字段等于1,表示它所作用的节是.text节。

  • 查看目标文件的符号表,命令:
greadelf -s SimpleSection.o

    输出:

符号表是一个数组,这个数组的第一个元素,即下标为0的元素为无效的未定义符号。

对于st_shndx字段,符号有可能是定义在本目标文件中,也有可能定义在其它的目标文件中,如果符号定义在本目标文件中,这个字段表示符号所在的节在节头部表中的下标;如果符号定义不在本目标文件中,那它有些特殊值:

    1. SHN_ABS表示该符号包含了一个绝对值,比如表示文件名的符号就属于此类型。
    2. SHN_COMMON表示该符号是一个COMMON块,一般来说,未初始化的全局符号定义就是这种类型,具体不多说。
    3. SHN_UNDEF表示该符号为定义,其定义是在其它目标文件中。例如上图的printf符号。

对于st_value字段,每个符号都有一个对应的值,如果这个符号是一个函数或变量,那么符号的值就是这个函数或变量的地址,st_value的值分三种情况:

    1. 如果符号定义在本目标文件中,并且不是COMMON块,那st_value的值表示这个符号在它所在的节中的偏移,它所在的节的下标由st_shndx字段给出,比如上图中的static_init_var符号,它的st_value是0,它的st_shndx即所在的节的下标是3,再看节头部表中下标是3的节是.data节,也就是说这个符号在.data节中,偏移是0。
    2. 如果符号是COMMON块类型的,那st_value表示它的对齐属性。
    3. 在可执行文件中,st_value表示符号的虚拟地址。

持续更新中。。。



0 0