通过readelf工具解析ELF可重定位目标文件
创建可重定位目标文件(main.o)
//main.c
int sum(int *a,int n);
int array[2]={1,2};
int mian()
{
int val=sum(array,2);
return val;
}
//linux中利用gcc工具将将main.c翻译成main.o
linux>gcc -c main.c
ELF可重定位目标文件结构
- ELF头
- 各个节(.text .rodata .data .bss .symtab等 )
- 节头部表
ELF头
说明
- magic:头四个字节(7f 45 4c 46)说明该文件是ELF格式的。
- 可重定位文件不会进行执行,没有程序头表,所以:程序头起点,程序头大小,Number of program headers(程序头表中表项个数)皆为0。
- Start of section headers:节头部表的偏移量。(本例中672的16进制表示为2a0,所以节头部表从0x2a0的位置开始。)
- 字符串表索引节头:节头部表中字符串表(strtab)的索引值。
节头部表
(表头弄成两行我也很迷惑,不过还是对齐了的)
各节的分布
现在, 通过ELF头中节头部表的信息,以及节头部表中各表项里偏移和大小的值,我们可以画出文件中各节的分布:
右侧数字表示节的大小,左侧数字表示偏移。(都是用16进制表示的)
(本例中.note.GNU-stack的size是0,这里为了不落下这个节所以画了出来,其实0x9e到0xa0之间是空的。)
符号表(.symtab)
符号表存放在程序中定义和引用的函数和全局变量的信息。 (书上是这么写的)
但我以为符号表从字面上理解是存放符号的信息的,而静态变量也是符号。所以为了弄清符号表到底包不包括静态变量,我把main.c中的main函数稍稍改动了一下,加了个静态变量:
int main()
{
static int a;
int val=sum(array,2);
return val;
}
然后得到新的main.o并且查看符号表
gcc -c main.c
readelf -s main.o
得到结果:
由此可知:Bind为LOCAL的a.1836即为我们新加入的静态变量a,且在bss节中。
说明
- value:距定义目标的节的起始位置的偏移(对可重定位模块来说)
- Ndx:index,到节头部表的索引。(特殊值:UNDEF表示未定义的符号,ABS表示不该被重定义的符号,COMMON表示未被分配位置未初始化的符号)
- 所以,array的Ndx为3表示在data节中;main的Ndx为1表示在text节中;sum的Ndx为UND因为是在另一个文件中定义的,而在本文件引用。