在某些体系结构(例如x86_64)中,可以使用PC(RIP)相对寻址模式来引用数据(例如mov)和代码(jmp,调用),这确实是技术的原因证明需要这种结构(got,plt)吗?
我的意思是,如果我想将全局数据(例如)移动到寄存器,则可以执行以下指令(标准PIE):
mov rax,QWORD PTR [rip + 0x2009db]
mov eax,DWORD PTR [rax]
(其中0x2009db是rip和包含符号地址的get右侧条目之间的偏移量)
为什么我们不能做这样的事情:
mov rax,rip + 0xYYYYYY
mov eax,DWORD PTR [rax]
(0xYYYYYYY是RIP值和符号(例如全局变量)之间的直接增量
我不习惯做ASM,所以我的例子也许是错误的。但是我的想法是:为什么不仅仅基于RIP简单地计算符号的绝对地址,将其放入EAX,然后访问其内容。如果指令集允许对相对寻址做我们想做的任何事情,为什么要使用这样的结构(got,plt)?
同一问题将适用于呼叫/跳转指令。
是因为指令集不允许这样做吗? 是因为偏移值不能覆盖整个地址空间吗?但是..重要吗?由于节的结构保持不变,因此将其映射到进程的虚拟寻址空间中(例如,.dat节,后跟.got或类似内容)。我的意思是,为什么偏移量在直接引用符号地址而不是get中的入口地址时会更大? 其他原因?
谢谢!
答案 0 :(得分:0)
基本上,这些结构的原因正是具有额外的间接级别。
这样,您可以使用LD_PRELOAD
在动态库中插入符号。即使没有它,动态绑定规则也使得可执行文件中定义的符号会覆盖共享库中定义的符号,即使是对该共享库中的调用也是如此(请参见this)。
还要考虑这些要点。
ld.so
的一个功能,称为 ASLR ),因此动态加载程序需要将重定位应用于至少所有在运行时执行的调用站点。关于GOT / PLT的重定位机制已在here中介绍。总而言之,互联网上有足够的信息说明PLT和GOT的工作方式(以及原因)。
此外,请查看GCC的-fno-plt
选项。这是一种优化,但是请注意,仍然需要GOT,并且没有PLT条目的函数不支持惰性绑定。