【问题标题】:ARM LDR instruction on PC registerPC 寄存器上的 ARM LDR 指令
【发布时间】:2014-07-29 17:38:13
【问题描述】:

我是这样理解这个故事的:

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

还有我的问题:

我找到了这段代码

LDR PC, [PC,-4]

它被评论为猴子补丁等。

我如何理解这段代码

pc = *(pc - 4)

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



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

移动 r1, 0x5678 添加 r1, 电脑 移动 r0, [r1]

这段代码是否等同于?

LDR r0,[pc,0x5678]

【问题讨论】:

  • 重新编辑:mov 不能采用内存操作数(ARM 是加载存储体系结构),因此代码按原样无效 - 如果第三条指令是 ldr r0, [r1] 它将是等效的. ldr r0, [pc, 0x5678] 不能编码为单条指令,因为立即数太大(即不能用偶数位旋转的 8 位值表示)。
  • 不喜欢,谢谢,这是我的问题

标签: assembly arm patch monkeypatching


【解决方案1】:

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

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

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

【讨论】:

  • 方括号 [] 还没有取消引用 pc - 4 地址?
  • LDR PC,[PC, -4] 表示从当前PC (R15) 形成的地址中加载一个字减去4,并将该值放入PC。由于 PC 比当前指令提前 8 个字节,您将从 current_instruction_address+8-4 == current_instruction_address+4 加载
  • 谢谢,但还有一件事 [PC, -4] 它有什么作用? "pc - 4" 或 *(pc - 4) ?
  • 应该是后者。
  • 在这种情况下LDR PC,[PC,-4] 将相当于这个代码pc = **((pc - 4)),或者我的误解是LDR 没有取消引用指针?
【解决方案2】:

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

现在我已经不再困惑了,这只是一个简单的函数调用 trampoline。函数地址将存储为紧跟LDR 指令之后的数据字(可能由链接器设置为某个初始值),并且可以在运行时简单地重写为数据以重定向分支,而无需求助于自修改代码。

【讨论】:

  • 不一样,跳转到当前指令不是SUB PC,#-4 ?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
相关资源
最近更新 更多