ELF重定位

版权声明:欢迎转载,注明出处 https://blog.csdn.net/youyou519/article/details/82699670

ELF重定位

首先重定位就是将符号定义和符号引用进行连接的过程。可重定位文件需要包含描述如何修改节内容的相关信息,从而使得可执行文件和共享目标文件能够保存进程的程序镜像所需要的正确信息。重定位条目就是我们上面说的相关信息。
重定位记录保存了如何对给定的符号对应代码进行补充的相关信息。重定位实际上时一种给二进制文件打补丁的机制,如果使用了动态链接器,可以使用重定位在内存中打热补丁。用于创建可执行文件和共享库的链接程序/bin/ld,需要某种列席的元数据来描述如何对特定的指令进行修改,这种元素数据就放在前面说的重定位记录中。
假设将2个目标文件链接到一起产生一个可执行文件。一个obj1.o文件中存放了调用函数fun()的代码,而fun()定义在obj2.o中。链接程序会对obj1.o和obj2.o中的重定位记录进行分析并将这两个文件链接在一起产生一个可独立运行的可执行程序。符号引用会被解析成符号定义。目标文件中的代码会被重定位到可执行文件的段中一个给定的地址。在进行重定位之前,无法确定obj1.o或者obj2.o中的符号和代码在内存中的位置,无法进行引用。只能在链接器确定了可执行文件的段中存放的指令或者符号的位置之后才能进行修改。

重定位结构:

typedef struct
{
	Elf64_Addr r_offset;
	Uint64_t r_info;
	int64_t r_addend;
}Elf64_Rel;

r_offset 指向需要进行重定位操作的位置。
r_info指定必须对其进行重定位的符号表索引以及要应用的重定位类型。
r_addend指定常量加数,用于计算存储在可重定位字段中的值。
32位ELF文件的重定位记录跟64位一样,不过用的时32位的整型。指定常量加数分为隐式加数和显式加数进行存储。 不包含r_addend就需要隐式加数。这时隐式加数存储在重定位目标本身中。64位的可执行文件一般使用ElfN_Rela的结构显示地对加数进行存储。
比如隐式加数e8 fc ff ff ff call 7数字7就是要进行修改的重定位目标偏移量,当链接器产生一个可执行文件,链接器会对偏移量位7的位置重定向,随后,当此函数被包含进了可执行文件之后,链接器会对偏移进行补齐4字节,这样就相当于存储了这个函数实际偏移地址。

R_386_PC32类型重定位

每一种重定位类型都对应一种计算方式,这种入下:
他的计算方式是“S+A-P”的方式重定位目标。
S是所以位于重定位条目中0符号的值(比如真正函数定义的地址)。
A是重定位条目中的加数。(比如补齐4字节)。
P是要进行重定位(使用r_offset进行计算)的存储单元的地址(节偏移或者地址)。(比如就是call之后的函数地址)
所以要将一个偏移量计算成虚拟地址,可以利用下面公式:
address_of_call(这个就是call这条指令的地址了,不是call后的地址)+offset+5(5是调用指令的长度)
用下面的计算也可以将一个地址转换成偏移量:
address-address_of_call-4(4是调用指令立即操作数的长度,为32位)

猜你喜欢

转载自blog.csdn.net/youyou519/article/details/82699670