ELF可重定位目标文件详解

#(1)典型的ELF可重定位目标文件(由一个ELF头,若干节和一个节头部表组成),如下图所示

摘自百度图片。

#(2)实例源程序

main.c

int sum(int *a, int n);//声明sum函数,入口参数是一个整型指针变量a和一个整型变量n,返回值为整型

int array[2] = {1, 2};//定义了一个含两个元素的整型全局数组array,并完成初始化

int main() 
{
    int val = sum(array, 2);//调用sum函数实现数组元素求和,利用返回值为局部变量val赋值
    return val;//返回所求和
}

sum.c

int sum(int *a, int n)//定义sum函数
{
    int i, s = 0;//定义局部变量i和s
    
    for (i = 0; i < n; i++) { 
        s += a[i];//做n次循环,将数组中每个元素加到s中
    }
    return s;//返回所求和
}  

#(3)使用指令gcc -c main.c sum.c生成可重定位目标文件main.o和sum.o

#(4)使用指令readelf -h main.o查看ELF头

如上图所示ELF头以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。其中7f 45 4c 46表示这是ELF文件。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头大小(64B),目标文件的类型(REL即可重定位文件),机器类型(x86-64),节头部表的文件偏移(720B),节头部表中条目的大小(64B),节头部表中条目的数量(12)等信息。

扫描二维码关注公众号,回复: 8902496 查看本文章

#(5)使用指令readelf -S main.o查看节头部表的信息

不同节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目。

下面介绍一下ELF头和节头部表之间的各个节

.text:已编译程序的机器代码;

.rodata:只读数据;

.data:已初始化的全局和静态C变量;

.bss:未初始化的全局和静态C变量,以及所有被初始化为0的全局或静态变量;

.symtab:是一个符号表,它存放程序中定义和引用的函数和全局变量的信息;

.rel.text:关于指令的重定位信息;

.rel.data:关于数据的重定位信息;

.debug:是一个调试符号表,其条目是程序中定义的局部变量和类型定义,程序中定义和引用的全局变量,以及原始的C源文件;

.line:原始C源程序的行号和.text节中机器指令之间的映射;

.strtab:是一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部表中的节名字。

#(6)使用指令readelf -s main.o查看符号表信息

如上图所示,全局符号main是一个位于.text节(Ndx==1表示.text节)中偏移量为0(即value值)处的33字节函数;

全局符号array是一个位于.data节(Ndx==3表示.data节)中偏移量为0处的8字节目标;外部符号sum是该文件中的一个引用,不存在本文件的任何节中(即Ndx==UND)。其他条目是链接器内部使用的局部符号。

#(7)使用指令objdump -d main.o查看该重定位目标文件反汇编情况

如上图所示,可重定位目标文件地址从0开始。由于还未进行链接,第14行调用sum函数未跳转到任何位置。

#(8)使用指令ld -o prog main.o sum.o完成链接,并生成可执行目标文件prog;再使用指令objdump -d prog查看prog的反汇编情况

发布了25 篇原创文章 · 获赞 6 · 访问量 2005

猜你喜欢

转载自blog.csdn.net/weixin_44711653/article/details/102055574