想要对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交叉编译。
上面看头部信息的时候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节。
符号表是一个数组,这个数组的第一个元素,即下标为0的元素为无效的未定义符号。
对于st_shndx字段,符号有可能是定义在本目标文件中,也有可能定义在其它的目标文件中,如果符号定义在本目标文件中,这个字段表示符号所在的节在节头部表中的下标;如果符号定义不在本目标文件中,那它有些特殊值:
对于st_value字段,每个符号都有一个对应的值,如果这个符号是一个函数或变量,那么符号的值就是这个函数或变量的地址,st_value的值分三种情况:
持续更新中。。。