ELF64加载程序如何知道如何更新.got.plt中的初始地址? [英] How does the ELF64 loader know to update the initial addresses in .got.plt?
问题描述
考虑以下程序 hello.c
:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("hello");
return 0;
}
使用 gcc -o hello -Og -g hello.c
编译文件,然后使用 gdb hello
加载文件.
The file is compiled with gcc -o hello -Og -g hello.c
and then loaded with gdb hello
.
使用 p'printf@got.plt'
检查对调用 printf
的GOT可以
Inspecting the GOT for the call to printf
with p 'printf@got.plt'
gives
$1 = (<text from jump slot in .got.plt, no debug info>) 0x1036 <printf@plt+6>
这是相应PLT条目中第二条指令相对于节开头的偏移量.
which is the offset of the second instruction in the corresponding PLT entry relative to the start of the section.
启动并使用 starti
链接程序后, p'printf@got.plt'
现在给出
After starting and linking the program with starti
, p 'printf@got.plt'
now gives
$2 = (<text from jump slot in .got.plt, no debug info>) 0x555555555036 <printf@plt+6>
是相应PLT条目中第二条指令的绝对地址.
which is the absolute address of the second instruction in the corresponding PLT entry.
我了解发生了什么以及为什么.我的问题是动态链接程序/加载器如何知道将节偏移量(0x1036)更新为绝对地址(0x555555555036)?
I understand what is going on and why. My question is how does the dynamic linker/loader know to update the section offset (0x1036) to the absolute address (0x555555555036)?
链接前的 p&'printf@got.plt'
$1 = (<text from jump slot in .got.plt, no debug info> *) 0x4018 <printf@got.plt>
和 readelf -r simple
显示此地址的重定位条目
and readelf -r simple
shows a relocation entry for this address
Relocation section '.rela.plt' at offset 0x550 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000004018 000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0
但是,我阅读的系统V应用程序二进制接口AMD64体系结构处理器补充内容,第76页,仅当 LD_BIND_NOW
不为空时,才使用这些重定位条目.还有其他我想念的搬迁条目吗?相对于GOT最终地址重新设置偏移量的机制是什么?
But my reading of the System V Application Binary Interface AMD64 Architecture Processor Supplement, p.76, is that these relocation entries are only used when LD_BIND_NOW
is non-null. Are there other relocation entries that I missed? What is the mechanism for rebasing offsets relative to the GOT's ultimate address?
推荐答案
根据Drepper的操作方法写共享库,动态链接器将重新定位两种依赖项:
According to Drepper's How To Write Shared Libraries, the dynamic linker relocates two kinds of dependencies:
- 相对重定位:对同一对象内位置的依赖性.链接器只是将对象的加载地址添加到目标目的地的偏移量中.
- 符号重定位:基于复杂的符号解析算法的过程更加复杂且昂贵.
- Relative relocations: dependencies to locations within the same object. The linker simply adds the load address of the object to the offset to the target destination.
- Symbol relocations: more complicated and expensive process based on a sophisticated symbol resolution algorithm.
对于PLT的GOT,Drepper声明(第1.5.5节)在启动时,动态链接程序使用指向相应PLT条目的第二条指令的地址填充GOT插槽. glibc 源代码表明,链接程序确实会遍历 R_X86_64_JUMP_SLOT
重定位( elf/do-rel.h:elf_dynamic_do_Rel
)并增加它们包含的偏移量( sysdeps/x86_64/dl-machine.h:elf_machine_lazy_rel
):
For the PLT's GOT, Drepper states (§1.5.5) At startup time the dynamic linker fills the GOT slot with the address pointing to the second instruction of the appropriate PLT entry. A reading of the glibc source code suggests that the linker indeed loops through the R_X86_64_JUMP_SLOT
relocations (elf/do-rel.h:elf_dynamic_do_Rel
) and increments the offsets they contain (sysdeps/x86_64/dl-machine.h:elf_machine_lazy_rel
):
if (__glibc_likely (r_type == R_X86_64_JUMP_SLOT))
{
/* Prelink has been deprecated. */
if (__glibc_likely (map->l_mach.plt == 0))
*reloc_addr += l_addr;
else
...
使用惰性PLT绑定时(默认情况).
when lazy PLT binding is used (the default case).
这篇关于ELF64加载程序如何知道如何更新.got.plt中的初始地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!