1

从https://www.keil.com/support/man/docs/armasm/armasm_dom1361289866046.htm读到arm-thumb 指令的blx指令可以支持最大 4MB 的跳转范围。

但据我所知,arm-thumb 指令只有 16 位长,那么 16 位怎么能包含 4MB 的偏移量呢?

4

1 回答 1

3

在原始 Thumb 指令集中,该BL指令包含两条 16 位指令,编码如下:

1111 HOOO OOOO OOOO   BL <label>
     |            |
     |            \.. long branch and link offset high/low
     \............... low/high offset
                        0 -- offset high
                        1 -- offset low

两条指令中的第一条必须将 H 位设置为 0。11 位偏移量向左移动 12,添加PC并放入LR寄存器。

LR = PC + (offset << 12)

两条指令中的第二条必须将 H 位设置为 1。11 位偏移量左移 1,添加到LR寄存器的内容中,并用作分支目标。LR寄存器设置为返回地址。

temp = next instruction address
PC = LR + (offset << 1)
LR = temp | 1

在 ARMv5T 中,BLX添加了指令的 Thumb 编码,允许 Thumb 代码调用 ARM 代码。BL这是通过在指令的后半部分*定义一个新的拇指位来完成的。

111T 1OOO OOOO OOOO   BL/BLX <label> (second half)
   |              |
   |              \.. long branch link exchange offset low
   \................. thumb bit
                        0 -- BLX is encoded
                        1 -- BL  is encoded

的操作BLX类似于指令的后半部分BL,但偏移量必须是偶数。该函数在 ARM 状态而不是 Thumb 状态下调用。

temp = next instruction address
PC = (LR + (offset << 1)) & 0xfffffffc
LR = temp | 1
CSPR T bit = 0

请注意,总共 22 个立即位给出半字偏移量,实现了观察到的 ±4 MiB 的分支偏移量。

将这两部分放在一起,我们还可以看到32 位指令BLBLX其编码如下:

1111 0OOO OOOO OOOO  111T 1OOO OOOO OOOO   BL/BLX <label>
                  |     |              |
                  |     |              \.. 22 bit offset (low half)
                  |     \................. thumb bit
                  \....................... 22 bit offset (high half)

在 Thumb2 中,该方案得到了扩展。 BLBLX成为正确的 32 位指令,它们的一半必须连续给出。†</sup> 定义了第二个指令字的某些位以将分支偏移量扩展到 ±16 MiB。

1111 0SOO OOOO OOOO  11AT BOOO OOOO OOOO   BL/BLX <label>
      |           |    || |            |
      |           |    || |            \.. 21 bit offset (low half)
      |           |    || \............... additional bit J2
      |           |    |\................. thumb bit
      |           |    \.................. additional bit J1
      |           \....................... 21 bit offset (high half)
      \................................... sign bit

如果设置了拇指位,则对BL指令进行编码。如果清晰,则对BLX指令进行编码。在后一种情况下,21 位偏移量必须是偶数。然后分支偏移量计算如下:

I1 = !(J1 ^ S)
I2 = !(J2 ^ S)
imm32 = (S ? 0xffff << 24 : 0) | (I1 << 23) | (I2 << 22) | (imm21 << 1)
temp = next instruction address
PC = LR + offset
LR = temp | 1
if thumb bit clear
    CSPR T bit = 0 

BL虽然编码附加偏移位的方案一开始看起来很复杂,但它只是将两个附加位编码到分支偏移中的最简单方法,同时与和BLX指令的现有编码兼容。


请参阅ARM 体系结构参考手册、ARMv7-A 和 ARMv7-R 版本、 ARM7TDMI数据表和 ARMv5 的ARM 体系结构参考手册以进行进一步阅读。

* 相关编码1110 0OOO OOOO OOOO对16位无条件分支指令进行编码B <label>

BL† 在 Thumb2 之前,a或指令的两个部分BLX是独立的指令,可以与其他指令穿插甚至单独发出,但强烈建议按顺序发出。一条BLBLX指令的两半之间也可能发生中断,从而使LR寄存器的临时内容可观察。在包括 ARMv6-M 在内的 Thumb2 目标上,这不再可能,BL并且BLX表现为 32 位指令。

于 2022-01-18T13:33:21.147 回答