探寻ELF文件内容,理清符号所在section

来源:互联网 发布:桃源网络硬盘安装 编辑:程序博客网 时间:2024/05/29 03:08


受《CSAPP》P453启发,想实际的看看ELF文件的内容,所以做了简单的尝试,希望不虚此行。

采用的程序demo是:

swap.c

extern int buf[];int *bufp0 = &buf[0];int *bufp1;void swap(){    int temp;    bufp1 = &buf[1];    temp = *bufp0;    *bufp0 = *bufp1;    *bufp1 = temp;}
main.c

#include <stdio.h>void swap();int buf[2] = {1, 2};static int foo = 99;int f(){        static int x = 1;        return x;}int g(){        static int x = 2;        return x;}int main(){    swap();    printf("Hello World.\n");    return 0;}
下面通过命令readelf命令来探寻ELF内部。

可以看到ELF头的一些信息:采用补码,小段序;目标文件的类型是可重定位目标文件;机器类型是Intel80386;ELF header的大小是52B;有30个section header,共40B;等等。


可以看到ELF中各个section的索引号,起始地址,大小,标志字段。只读数据段15,已初始化全局变量24,未初始化全局变量25,符号表28,字符串表29,代码段13.(其他的现在还不懂)。接下来结合上面的代码看符号表信息。



Ndx列表明每个符号所在的段,其中有三个伪段(pseudo section):ABS表示不该被重定位的符号,UNDEF表示在本模块引用,却在其他模块定义,COMMON表示还未分配位置的未初始化对象。

main.c, swap.c代表源文件名,类型是ABS。

f, g是在main.c中定义的俩函数,type=FUNC, bind=GLOBAL, 表示全局函数,所在的section是13(.text),起始地址分别为80483d4,de,大小都是10B.

变量foo, buf都是初始化的全局变量,在24号段(.data)中,大小分别是4,8B,不同在于foo有static修饰,所以bind=LOCAL,对于buf0,buf1也是类似情况.

特别值得关注的是定义在函数f, g中的有static修饰的同名局部变量x,在符号表中有唯一的local linker symbols:x.1688, x.1691都在全局初始化段中,bind=LOCAL.


接下来看swap.o的ELF信息:


可以看到类型是可重定位目标文件。(REL)

与前面readelf -a a.out很大不同的地方在于这里多了一些.rel.text  .rel.data等可重定位的section,这是有目标文件的类型决定的,可重定位目标文件存在的意义就是被链接到其他目标文件中,构建可执行目标文件,所以就需要在ELF中表明哪些符号需要进行地址的修改。调用外部函数或者引用全局变量的指令都需要修改,本地函数调用是相对地址,所以不需要修改。上述代码段位置列表在这里显然表示的就是swap()里面需要重定位的对象,其中操纵了1次buf符号,3次bufp1, 2次bufp0, 所以出现了对应的条目,并且根据偏移量可以更好的理解。在重定位数据段中就只有我们引用的外部变量buf。


在swap.o的符号表中,bu所在的section是UND Type=NOTYPE,表明其是extern的。bufp0是以初始化的全局变量,32位系统指针大小是4B,所在的section number是3(.data).特别要注意的是bufp1是未初始化未分配位置的对象,所以Ndx=COM, value值指明的是对齐要求。


总结:通过以上的分析可以更清晰的理解可执行文件的内存布局, 不同对象所在的section,从而指导自己的程序设计。




0 0
原创粉丝点击