微处理器如何检测它是否在一条指令之间?

How does the Microprocessor detect if it's in-between an instruction?

我正在使用 ST32F401RE(ARM Cortex -M4 32 位 RISC)并且对以下内容感到好奇。

通常 32 位 ARM 上的指令可以是 2 字节或 4 字节长。 我不小心跳到 2 字节指令之间,微处理器随后立即进入无限错误处理程序循环。

我后来对此进行了测试,并故意在 4 字节和 2 字节指令之间跳转,微处理器将始终进入错误处理程序。

我使用下面的 c 代码跳转到内存地址。

void (*foo)(void) = (void (*)())0x80002e8;
foo( ) ;

函数和指令的地址来自反汇编。 编译器在将地址存储到 r3 后使用了以下汇编指令。

blx     r3

问题:微处理器如何准确判断它不是在一条指令的开头而是在一条指令之间开始的?
特别是在已经非常局促的 16 位拇指指令的情况下。

我有多种猜测,但想知道到底发生了什么。

Normally instructions on a 32 bit ARM can be 2 byte or 4 byte long.

仅适用于 Thumb2;在 Thumb 上它们都是 2 个字节,在 ARM(“A32”)模式下它们都是 4 个字节。

Question: How exactly can the Microprocessor tell that it didn't start at the beginning of an instruction but actually started in-between one?

不能。如果一个 4 字节指令的 2 个高位字节碰巧形成了一个有效的 2 字节指令并且你跳转到那里,它将被执行。在你的情况下,这些高 2 字节可能都是无效指令,导致错误异常。

例如程序

.code 16
.syntax unified

test4byte:
    mov.w r0, #0x88000000
    
test2byte:
    ands r0, r1

会组装成

00000000 <test4byte>:
   0:   f04f 4008   mov.w   r0, #2281701376 ; 0x88000000

00000004 <test2byte>:
   4:   4008        ands    r0, r1

或作为字节方式的十六进制转储

4f f0 08 40 08 40

如您所见,序列 08 40 出现了两次 - 作为 mov.w 的高 2 字节和 ands 指令,两者是相同的。所以,处理器无法区分这些。

在刚刚包含显示的mov.w指令的程序中,如果您跳转到地址0,则会执行mov.w;如果您跳转到地址 2,则会执行 ands,即使它没有出现在汇编代码中。