首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用pc偏移量理解Cortex-M组件LDR

用pc偏移量理解Cortex-M组件LDR
EN

Stack Overflow用户
提问于 2021-12-27 03:42:17
回答 3查看 456关注 0票数 0

我正在查看这段C代码的反汇编代码:

代码语言:javascript
复制
#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
int main(void){    
    // Initialization code
    while(1) {
        SW1 = GPIO_PORTF_DATA_R&0x10;  // Read PF4 into SW1
        // Other code
        SW2 = GPIO_PORTF_DATA_R&0x01;
    }
}

SW1=行的程序集为(对不起不能复制代码):

https://imgur.com/dnPHZrd

以下是我的问题:

  • 在第一行,PC = 0x00000A56,PC + 92 = 0x00000AB2,它不等于0x00000AB4,显示的数字。为什么?

我对此做了一些研究,发现PC实际上指向了下一个要执行的指令。

当pc用于读取时,ARM模式有8字节偏移,拇指模式有4字节偏移。

然而,0x00000AB4-0x00000A56= 0x5E = 94,它也不匹配92+8或92+4。

参考文献

Strange behaviour of ldr [pc, #value]

Why does the ARM PC register point to the instruction after the next one to be executed?

LDR Rd,-Label vs LDR Rd,[PC+Offset]

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-12-27 06:21:01

您忽略了拇指模式规则的一个关键部分,引用在您链接的一个问题(Why does the ARM PC register point to the instruction after the next one to be executed?)中:

对于所有使用标签的其他指令,PC的值是当前指令的地址加上4个字节,与bit1的结果清除为0,使其字对齐。

  • (0xA56 + 4) & -4 = 0xA58是在该ldr r0, [PC, #92]

执行过程中与PC相关的事物相对的位置。

  • ((0xA56 + 4) & -4) + 92 = 0xab4,反汇编程序计算的位置。

  • --它相当于执行0xA56 & -4 = 0xa54然后是+4 + 92,因为+4没有修改bit #1;您可以考虑在添加+4之前或之后清除它。但是,在添加PC相对偏移量之后,您无法清除该位;对于其他指令(如ldrb ),可以不对齐。(拇指模式ldr用文字编码偏移量,以更好地利用有限的位数,因此缩放的偏移量和最终的负载地址总是1:0清晰。)

(感谢陈雷蒙德发现了这一点,我一开始也错过了!)

还请注意,调试器在断点停止时向您显示一个PC值,但这是被停止的指令的地址。(因为我认为ARM异常就是这样工作的,它保存了要返回的实际指令,而不是一些偏移量。)在指令的执行过程中,PC相关内容遵循不同的规则.调试器也不会“编写”这个值来显示在执行过程中PC会是什么。

这个规则不是“相对于这个/开始下一个指令的结尾”。的答案和注释指出,在这种情况下,规则碰巧得到了正确的答案,但在其他拇指情况下,会得到错误的答案,比如在LDR Rd,-Label vs LDR Rd,[PC+Offset]中,PC相对加载指令恰好从一个4字节对齐地址开始,因此PC的位#1已经被清除。

您的LDR位于address 0xA56,其中设置了位#1,因此舍入有效果。您的ldr指令使用的是2字节编码,而不是Thumb2 32位指令,因为您可能需要更大的偏移量。这两种情况都意味着四舍五入+4恰好是下一条指令的地址,而不是后面的2条指令或这条指令的中间地址。

票数 1
EN

Stack Overflow用户

发布于 2021-12-27 11:31:08

来自ARM文件:

代码语言:javascript
复制
Operation 
  address = (PC[31:2] << 2) + (immed_8 * 4) 
  Rd = Memory[address, 4]

pc是0xA56+4,因为前面有两个指令,这是拇指,所以是4个字节。

代码语言:javascript
复制
(0xA5A>>2)<<2 + (0x17*4)
or
(0x00000A5A&0xFFFFFFFC) + (0x17<<2)
0xA58+92=0xA64

这是一个LDR,所以理想情况下它是一个基于字的地址。由于拇指指令可以位于非字对齐地址上,所以首先添加两个指令(当然,thumb2会使这一点复杂化,而拇指则添加四个)。然后,零下两位(LDR)偏移量是字,所以需要把它转换成字节,乘以4。这使编码更有意义,如果你考虑它的每一个部分。在arm模式下,PC已经是字对齐了,所以不需要步骤(在arm模式下,您有更多的位用于即时,所以它是基于字节的,而不是基于字的),使得arm和拇指之间的偏移编码可能会混淆。

不同的文档将以不同的方式显示数学,但它仍然是相同的数学。个人电脑是唯一令人困惑的部分,特别是拇指。对于ARM,您可以在前面添加8,2,对于拇指,它基本上是4,因为执行不能判断是否有一个thumb2即将到来,而且如果他们试图这样做的话,它会破坏很多事情。所以前面的两个加4,拇指。由于拇指是压缩的,它们不使用字节偏移量,而是使用单词偏移量,使范围增加了4倍。同样,此指令和/或其他指令只能向前看,而不能向后看,这样没有符号的偏移量。这就是为什么在用拇指装配东西时,你会得到对齐错误,而在手臂上的东西只是不对齐(根据架构和设置,你得到了你得到的东西)。拇指不能为这样的指令编码任何地址。

为了理解指令编码,特别是基于pc的寻址,最好回到早期的ARM (在armv5之前,但如果不是那样的话,只得到armv5的)以及armv7 6-m和armv7 7-m和全尺寸的armv7 7-ar。看看每个人的伪码。旧的通常有最好的伪码,但有时他们没有掩蔽低位的地址。没有一个文档是完美的,它们和其他任何东西一样都有bug。当然,与您所使用的核心相关联的体系结构是芯片供应商使用的IP的正式文档(甚至到了TRM的特定版本,因为这些文件可能因不同而不同)。但是,如果该文档不太清楚,您有时可以从其他人那里得到一个想法,在检查时,它具有兼容的指令和体系结构特性。

票数 2
EN

Stack Overflow用户

发布于 2021-12-27 03:56:15

由于程序计数器指向下一条指令,当它在地址0x00000A56处执行LDR时,程序计数器将保存下一条指令的地址,即0x00000A58

0x0A58 + 0x5C (decimal 92) == 0x00000AB4

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70491482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档