我在这里理解这个故事:
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]
答案 0 :(得分:7)
引自 ARM指令集文档(ARM DDI 0029E)的4.9.4节:
使用
R15
作为基址寄存器时,必须记住它包含8字节的地址 从当前指令的地址开始。
因此该指令将在当前指令之后加载位于4字节的字,希望它包含有效地址。
答案 1 :(得分:4)
感谢a quirk of the ARM architecture,LDR PC, [PC,-4]
是跟随指令的分支(假设我们正在谈论ARM,而不是Thumb),因此正常情况下它没有效果(性能除外)。关键是,通过将该指令放在函数的开头,然后通过重写分支到紧跟在指令之后的字中的存储器中的地址。 Herp derp,我得到LDR
指令的底部12位来改变偏移量,代码在运行时修补自身非常简单,因此将该函数重定向到其他地方。ADR
和LDR
混淆了 - 如果它是ADR
,上面的情况就是如此,但这种情况更为直白。
现在我已经完全没有注意到它只是一个简单的函数调用蹦床。函数地址将紧跟在LDR
指令之后存储为数据字(可能由链接器设置为某个初始值),并且可以在运行时简单地重写为数据以重定向分支,而无需求助于自身 - 修改代码。