解码ARM BL指令

decode ARM BL instruction

我刚刚开始在我的 Nucleo STM32F303RE 上使用 ARM 架构,我正在尝试了解指令的编码方式。

我有运行一个简单的LED闪烁程序,前几个反汇编的应用指令是:

08000188:   push    {lr}
0800018a:   sub     sp, #12
235         __initialize_hardware_early ();
0800018c:   bl      0x80005b8 <__initialize_hardware_early>

这些指令在十六进制文件中解析为以下内容(在 Eclipse 中显示很奇怪——每个 32 位字都是按 MSB 顺序排列的,但 Eclipse 似乎并不知道……但那是另一个话题了) :

address 0x08000188:  B083B500 FA14F000

使用 ARM 体系结构参考手册,我已经确认了前 2 条指令,push (0xB500) 和 sub (0xB083)。但是我无法理解 "bl" 指令。

十六进制指令是0xFA14F000。参考手册说它是这样分解的:

31.28   27 26 25 24   23............0
cond     1  0  1  L   signed_immed_24

第一个"F"(0xF......)是有道理的:所有条件都已设置(总是)。

"A" 没有意义,因为应该设置 L 位 (1011)。不应该是0xFB……吗?

而且 signed_immed_24 也没有意义。参考手册说:

- start with 0x14F000
- sign extend to 30 bits (signed 2's-complement), giving 0x0014F000
- shift left to form 32-bit value, giving 0x0053C000
- add to the PC, which is the current instruction + 8, giving 0x0800018c + 8 + 0x0053C000, or 0x0853C194.

所以我得到一个分支地址0x0853C194,但是反汇编显示0x080005B8。

我错过了什么?

谢谢! -埃里克

bl 是两条独立的 16 位指令。 armv5(及更早版本)ARM ARM 在记录它们方面做得更好。

111HHoffset11

来自ARM ARM

The first Thumb instruction has H == 10 and supplies the high part of the branch offset. This instruction sets up for the subroutine call and is shared between the BL and BLX forms.

The second Thumb instruction has H == 11 (for BL) or H == 01 (for BLX). It supplies the low part of the branch offset and causes the subroutine call to take place.

0xFA14 0xF000

0xF000 是第一条指令上偏移量为零 0xFA14是第二条指令偏移量是0x214

如果从 0x0800018c 开始,则为 0x0800018C + 4 + (0x0000214<<1) = 0x080005B8。 4是当前PC的两条指令头。并且偏移量是(16位)指令的单位。

我想 armv7-m ARM ARM 也涵盖了它,但更难阅读,而且显然添加了功能。但是他们不会影响你这个分支 link.

ARMv5 ARM ARM 在描述发生的事情方面也做得更好。你当然可以把这两个单独的指令分开

.byte 0x00,0xF0
nop
nop
nop
nop
nop
.byte 0x14,0xFA

并且它将分支到相同的偏移量(相对于第二条指令)。也许在某些内核中坏了,但我知道在某些内核中(在 armv5 之后)它可以工作。