ARM PC寄存器可以指向不在指令边界上的地址吗?

时间:2016-03-23 13:08:40

标签: assembly arm

这是我在Linux上运行应用程序时在一些非常罕见的SEGV上收到的GDB输出,Cortex-A8:

Program received signal SIGSEGV, Segmentation fault.
0xb6341668 in strcpy () at ../ports/sysdeps/arm/armv6/strcpy.S:48
(gdb) info registers
r0             0x161598 1447320
r1             0x153eec 1392364
r2             0x161598 1447320
r3             0x2e     46
r4             0x0      0
r5             0xbb8    3000
r6             0xd8     216
r7             0xbefff408       3204445192
r8             0x0      0
r9             0x0      0
r10            0xb6fff000       3070226432
r11            0xa      10
r12            0x14d1e4 1364452
sp             0xbefff408       0xbefff408
lr             0x80461  525409
pc             0xb6341668       0xb6341668 <strcpy+8>
cpsr           0xf0030  983088
(gdb) disas
Dump of assembler code for function strcpy:
   0xb6341660 <+0>:     mov     r12, r0
   0xb6341662 <+2>:     pld     [r0]
   0xb6341666 <+6>:     pld     [r1]
   0xb634166a <+10>:    and.w   r3, r1, #7
   0xb634166e <+14>:    rsb     r3, r3, #16
   0xb6341672 <+18>:    ldrb.w  r2, [r1], #1

传递给strcpy(上部回溯帧)的堆栈跟踪和值似乎正确,但PC值为0xb6341668,这不是gdb反汇编中任何指令的开头。这是合法的吗?

3 个答案:

答案 0 :(得分:4)

正如其他人所指出的那样,PC可以自由指向任何足够对齐的地方 - 这是ARM状态下的4字节边界,或Thumb状态下的2字节边界。

当您查看机器代码时,这种特殊情况会变得更有趣,并考虑Thumb的可变长度编码的重要性:

   0:   4684            mov     ip, r0
   2:   f890 f000       pld     [r0]
   6:   f891 f000       pld     [r1]
   a:   f001 0307       and.w   r3, r1, #7
   e:   f1c3 0310       rsb     r3, r3, #16
  12:   f811 2b01       ldrb.w  r2, [r1], #1

但是,嘿,我们已经在bugsville,所以谁说我们必须从<strcpy>开始?让我们尝试拆解同样的东西,但是从<strcpy+4>开始敲掉前两个半字,并使32位编码不同步:

   //   4684 f890       (skipped)
   0:   f000 f891       bl      0x126
   4:   f000 f001       bl      0x40000a
   8:   0307            lsls    r7, r0, #12
   a:   f1c3 0310       rsb     r3, r3, #16
   e:   f811 2b01       ldrb.w  r2, [r1], #1

所以你去,如果你把你的PC指向0xb6341668,它会看到一个完全有效的bl . + 0x400006,所以如果0xb674166e确实未映射(或映射为不执行)那么你应该从尝试获得一个SEGV执行它。现在,你如何做到这一点完全是另一回事......

答案 1 :(得分:1)

处理器位于Thumb mode,使用16位指令; decode the cpsr了解它的模式。

答案 2 :(得分:1)

虽然这肯定是问题的根源,但是没有检查处理器以验证它是否在有效的指令边界。实际上没有办法验证它:处理器只是获取指令,如果它看起来像32位或16位,则解码并执行它。

在这种情况下,很可能一条(垃圾)指令实际上未定义,导致对齐或MMU错误,因为它实际上正在运行随机指令。