ARM LDR指令在PC寄存器上的应用

8
这是我的理解:
  • 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]

针对编辑部分:mov不能接受一个内存操作数(ARM是一个加载存储架构),因此该代码是无效的 - 如果第三条指令是ldr r0,[r1],则等效。 ldr r0,[pc,0x5678]不能编码为单个指令,因为立即数太大了(即它不能由偶数位旋转的8位值表示)。 - Notlikethat
不是那样的,谢谢,这是我的问题。 - l0gg3r
2个回答

12
引用自ARM指令集文档(ARM DDI 0029E)第4.9.4节: 当使用R15作为基础寄存器时,必须记住它包含一个地址,该地址与当前指令的地址相差8个字节。 因此,该指令将加载位于当前指令后4个字节处的单词,希望该处包含有效地址。

方括号[]是否已经取消引用pc-4地址? - l0gg3r
1
LDR PC,[PC, -4] 的意思是从当前 PC (R15) 减去 4 所形成的地址中加载一个字,并将该值放入 PC 中。因为 PC 比当前指令前进了 8 个字节,所以您将会从 current_instruction_address+8-4 == current_instruction_address+4 加载。 - Michael
谢谢,还有一个问题 [PC, -4] 它是做什么的?是“pc - 4”还是*(pc - 4)? - l0gg3r
那将是后者。 - Michael
啊,谢谢。我的问题在于LDR指令。我一直以为LDR会在赋值前解引用第二个操作数,但事实证明它只是简单地进行赋值而不解引用,解引用是由括号完成的 :) - l0gg3r
显示剩余2条评论

4
由于ARM架构的一个怪癖LDR PC, [PC,-4](假设我们这里讨论的是ARM而不是Thumb)实际上是跳转到存储在紧随其后的单词内存地址的指令。我混淆了ADRLDR - 如果是ADR,那么上面就是正确的,但这种情况更加简单。现在,它只是一个简单的函数调用跳板。函数地址将作为LDR指令紧随其后的数据单词存储(由链接器设置为某个初始值),可以在运行时仅仅通过重写数据来重新定向分支,而不需要采用自修改的代码。

不是这样的,分支到当前指令不是SUB PC,#-4吗? - l0gg3r

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接