PC寄存器上的ARM LDR指令

时间:2014-06-09 07:49:38

标签: assembly arm patch monkeypatching

我在这里理解这个故事:

  • PC寄存器保存指向下一条指令的指针
  • LDR指令将第二个操作数的值加载到第一个操作数中 (例如)
    LDR r0, [pc, 0x5678]
    相当于这个“C代码”
    r0 = *(pc + 0x5678)
    
    它的指针取消引用了基本偏移量。

我的问题:

我找到了这段代码

LDR PC, [PC,-4]

它被评论为猴子修补等。

我如何理解这段代码

pc = *(pc - 4)

我这种情况下“pc”寄存器将取消引用前一条指令的地址,并包含指令的“机器代码”(不是指令的地址), 程序将跳转到该无效地址继续执行,可能我们将得到“分段错误”。 那么我缺少什么或不理解?


使我想到的是LDR指令中第二个操作数的括号。 据我所知,在x86架构上,括号已经解除引用指针,但我无法理解ARM架构中的含义。

mov r1, 0x5678
add r1, pc
mov r0, [r1]

此代码相当于?

LDR r0, [pc, 0x5678]

2 个答案:

答案 0 :(得分:7)

引自 ARM指令集文档(ARM DDI 0029E)的4.9.4节:

  

使用R15作为基址寄存器时,必须记住它包含8字节的地址   从当前指令的地址开始。

因此该指令将在当前指令之后加载位于4字节的字,希望它包含有效地址。

答案 1 :(得分:4)

感谢a quirk of the ARM architectureLDR PC, [PC,-4] 跟随指令的分支(假设我们正在谈论ARM,而不是Thumb),因此正常情况下它没有效果(性能除外)。关键是,通过将该指令放在函数的开头,然后通过重写LDR指令的底部12位来改变偏移量,代码在运行时修补自身非常简单,因此将该函数重定向到其他地方。分支到紧跟在指令之后的字中的存储器中的地址。 Herp derp,我得到ADRLDR混淆了 - 如果它是ADR,上面的情况就是如此,但这种情况更为直白。

现在我已经完全没有注意到它只是一个简单的函数调用蹦床。函数地址将紧跟在LDR指令之后存储为数据字(可能由链接器设置为某个初始值),并且可以在运行时简单地重写为数据以重定向分支,而无需求助于自身 - 修改代码。