简体   繁体   English

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

[英]Can ARM PC register point to address not on instruction boundary?

Here is GDB output I've received on some very rare SEGV while running application on linux, Cortex-A8: 这是我在Linux Cortex-A8上运行应用程序时在一些非常罕见的SEGV上收到的GDB输出:

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

Stack trace and values passed to strcpy (upper backtrace frame) seem correct, but PC value is 0xb6341668 which is not at the beginning of any instruction in gdb disassembly. 堆栈跟踪和传递给strcpy的值(上溯跟踪帧)似乎是正确的,但PC值为0xb6341668,这不是gdb反汇编中任何指令的开头。 Is it legal? 合法吗

As others have noted, the PC is free to point anywhere that's sufficiently aligned - that's on a 4-byte boundary in ARM state, or a 2-byte boundary in Thumb state. 正如其他人指出的那样,PC可以自由指向足够对齐的任何位置-在ARM状态下为4字节边界,在Thumb状态下为2字节边界。

This particular situation gets more fun when you look at the machine code, and consider the significance of Thumb's variable-length encodings: 当您查看机器代码并考虑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

But hey, we're already in bugsville, so who says we had to start from <strcpy> ? 但是,嘿,我们已经在Bugsville,那么谁说我们必须从<strcpy>开始? Let's try disassembling the same thing, but knocking off the first two halfwords to start from <strcpy+4> and throw the 32-bit encodings out of sync: 让我们尝试分解相同的内容,但是将前两个半字从<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

So there you go, if you point your PC at 0xb6341668 it sees a perfectly valid bl . + 0x400006 因此,如果您将PC指向0xb6341668,它将看到一个完全有效的bl . + 0x400006 bl . + 0x400006 , so if 0xb674166e is indeed unmapped (or mapped no-execute) then it's only right you should get a SEGV from trying to execute it. bl . + 0x400006 ,因此,如果确实未映射0xb674166e(或映射未执行),则应该尝试执行SEGV才是正确的。 Now, how you might have wound up doing that is another matter entirely... 现在,您可能会如何做完全是另一回事...

The processor is in Thumb mode , which uses 16-bit instructions; 处理器处于Thumb模式 ,使用16位指令。 decode the cpsr to see what mode it's in. 解码cpsr以查看其处于哪种模式。

Although this is certainly the source of the problem, there is no check in the processor to verify that it is at a valid instruction boundary. 尽管这当然是问题的根源,但是处理器中没有检查以确认它在有效的指令边界上。 And there is actually no way to verify it: the processor just fetches the instructions, decodes if it looks like a 32-bit or 16-bit one, and executes it. 实际上,没有办法对其进行验证:处理器只是获取指令,对看起来像32位还是16位的指令进行解码,然后执行它。

In this case, there is a good chance that one (junk) instruction is actually underfined, causes an alignment or MMU fault, as it is actually running random instructions. 在这种情况下,很有可能一个(垃圾)指令实际上未充分定义,导致对齐或MMU故障,因为它实际上正在运行随机指令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM