从https://www.keil.com/support/man/docs/armasm/armasm_dom1361289866046.htm读到arm-thumb 指令的blx
指令可以支持最大 4MB 的跳转范围。
但据我所知,arm-thumb 指令只有 16 位长,那么 16 位怎么能包含 4MB 的偏移量呢?
从https://www.keil.com/support/man/docs/armasm/armasm_dom1361289866046.htm读到arm-thumb 指令的blx
指令可以支持最大 4MB 的跳转范围。
但据我所知,arm-thumb 指令只有 16 位长,那么 16 位怎么能包含 4MB 的偏移量呢?
在原始 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 位指令BL
,BLX
其编码如下:
1111 0OOO OOOO OOOO 111T 1OOO OOOO OOOO BL/BLX <label>
| | |
| | \.. 22 bit offset (low half)
| \................. thumb bit
\....................... 22 bit offset (high half)
在 Thumb2 中,该方案得到了扩展。 BL
并BLX
成为正确的 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
是独立的指令,可以与其他指令穿插甚至单独发出,但强烈建议按顺序发出。一条BL
或BLX
指令的两半之间也可能发生中断,从而使LR
寄存器的临时内容可观察。在包括 ARMv6-M 在内的 Thumb2 目标上,这不再可能,BL
并且BLX
表现为 32 位指令。