关于arm pc值在拇指16 / 32bits混合指令流

时间:2015-04-12 06:09:35

标签: arm instruction-set thumb

我在SO Why does the ARM PC register point to the instruction after the next one to be executed?中阅读了几篇文章,包括问题,pc寄存器值实际上是当前正在执行的指令地址加上前面的2条指令,因此在ARM状态下它是+8字节(2 * 32位)。 / p>

我的问题是,对于拇指状态,可能有16位或32位指令,是否意味着取出的pc地址可能分别为+4字节或+8字节的16/32位指令的偏移量?

例如:

279ae6: f8df 9338   ldr.w   r9, [pc, #824] --> pc value= 279aea or 279aee
279aea: f44f 7380   mov.w   r3, #256
279aee: 48cd        ldr r0, [pc, #820]

我使用以下代码进行了更多测试:

1598:   467b        mov r3, pc
159a:   f8bf 4000   ldrh.w  r4, [pc]    ; 159c
159e:   46f9        mov r9, pc
15a0:   f83f 5001   ldrh.w  r5, [pc, #-1]   ; 15a3
15a4:   f83f 6002   ldrh.w  r6, [pc, #-2]   ; 15a6
15a8:   f83f 7003   ldrh.w  r7, [pc, #-3]   ; 15a9
15ac:   f83f 8004   ldrh.w  r8, [pc, #-4]   ; 15ac
15b0:   f04f 0908   mov.w   r9, #8
15b4:   f8d9 0008   ldr.w   r0, [r9, #8]    ; Trigger crash to check registers

崩溃时,寄存器为:

I/DEBUG   ( 2632): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
I/DEBUG   ( 2632):     r0 b8ef4fc0  r1 aca6bb6c  r2 00000000  r3 aca7c59c
I/DEBUG   ( 2632):     r4 00004000  r5 00003f50  r6 00006002  r7 000003f8
I/DEBUG   ( 2632):     r8 0000f83f  r9 00000008  sl 00000000  fp aca6bbc0
I/DEBUG   ( 2632):     ip aca7c591  sp aca6bb40  lr acab722d  pc aca7c5b4  cpsr 60070030

上面的代码注释(159c / 15a3 / 15a6 / 15a9 / 15ac)中显示的地址是由objdump生成的,我用寄存器检查了这些位置的内容,似乎没问题。

对于16位指令:

1598:   467b        mov r3, pc  ;    // r3 = 1598 + 4 = 159c, correct for +4 theory

对于32位拇指指令:

159a:   f8bf 4000   ldrh.w  r4, [pc]    ; // ld addr = 159a + 2 = 159c, where the content is 4000(hw), exactly r4 shows
                                        ; // Inconsistent with +4 theory

这样,对于32位指令,pc read = pc执行+2。我错过了什么?现在我对pc偏移感到困惑。

BTW,这是使用thumb2的armv7a平台。

谢谢你们。

1 个答案:

答案 0 :(得分:3)

在Thumb状态下,PC偏移始终为4个字节。原因是它提前两个指令提取,并且Thumb指令提取(概念上)总是半字 - 因此为什么32位编码仍然具有两个小的有趣字节顺序 - endian halfwords,而不是一个小尾词。

一个" 32位"原始Thumb指令集bl中的编码使每个半字的操作分别定义为"前缀"和"后缀"说明,巧妙的技巧是,在执行第一部分时,返回地址直接来自PC,因为在那个阶段,它指向第二部分之后的指令。当Thumb-2技术出现并使32位编码成为正式的东西(包括 bl追溯)时,PC偏移已承载no relation to the actual microarchitecture几代 * ,因此根据指令流将其定义的行为更改为变量几乎没有任何好处,并引入了大量的兼容性问题。

更复杂的是,当PC被用作寻址操作的基址寄存器时(即adr / ldr / str /等),它始终是即使在Thumb状态下,也会使用单词对齐的值。因此,在0x159a执行加载指令时,PC寄存器将读取为0x159e,但ldr...[pc]的基址为Align(0x159e, 4),即0x159c。由于PC相对寻址通常是通过指定标签而不是手动计算偏移量来编写的,因此很容易错过这个细节。

*就ARM自己的设计而言,ARM7是最初的基于原始3阶段管道的微体系结构。