将程序计数器添加到目标寄存器(Rd)的重点

时间:2014-03-25 15:45:42

标签: assembly arm

我已经使用IDA Demo反汇编了一个.so文件(ELF文件),我对这条指令感到困惑

ADD R4, PC ; _GLOBAL_OFFSET_TABLE_

这是什么意思?我知道PC是一个保存下一个指令地址的变量,但是将它添加到R4的目的是什么?

提前致谢。

更新:

PUSH.W {R4 - R11, LR}
LDR R4, =(_GLOBAL_OFFSET_TABLE_ - 0x11FACC)
LDR.W R11, =0x4D4
MOV R9, R3
ADD R4, PC
SUB SP, SP, #0x34
ADD R7, SP, #0xC
MOV.W R8, 0

2 个答案:

答案 0 :(得分:2)

这个想法是与位置无关的代码。

加载模块时,它会获得一个任意的基址。所有全局对象(即变量和函数)都驻留在某些虚拟地址上;在构建时,你不知道那些地址是什么。但链接器知道它们之间的相对偏移;那些在加载时不会改变。

因此,为了避免重定位并因此加速模块加载,并且出于其他有益的原因,正在生成与位置无关的代码。在您的示例中,R4最初包含当前PC与某些感兴趣的全局对象之间的地址差异。所述差异是链接时间常量 - 它由链接器计算并且永远不会改变。通过将PC添加到所述差异,代码获得该全局对象的绝对地址。它是什么 - 你可以通过检查R4接下来会发生什么来了解它。是否被取消引用或分支到。

答案 1 :(得分:0)

这是针对位置独立代码(PIC)完成的。在

LDR R4, =(_GLOBAL_OFFSET_TABLE_ - 0x11FACC)

从全局offset-table加载一个值。此值是代码中两个位置之间的差异。然后将PC添加为基础,获取您想要访问的实际位置。

这主要是针对库完成的,因为不同的程序可以将库映射到不同的地址空间。

如果没有PIC,则必须重新定位库,具体取决于为每个程序加载的基址。现在允许共享实际的内存页面。