use*_*400 2 assembly arm machine-code thumb instruction-encoding
从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>\n | |\n | \\.. long branch and link offset high/low\n \\............... low/high offset\n 0 -- offset high\n 1 -- offset low\nRun Code Online (Sandbox Code Playgroud)\n两条指令中的第一条必须将 H 位设置为 0。11 位偏移量向左移动 12,添加到PC并放入LR。
LR = PC + (offset << 12)\nRun Code Online (Sandbox Code Playgroud)\n两条指令中的第二条必须将H位设置为1。11位偏移量左移1,与寄存器的内容相加LR,并用作分支目标。这LR设置为返回地址。
temp = next instruction address\nPC = LR + (offset << 1)\nLR = temp | 1\nRun Code Online (Sandbox Code Playgroud)\n在 ARMv5T 中,添加了指令的 Thumb 编码BLX,允许 Thumb 代码调用 ARM 代码。这是通过在后半部分*定义一个新的拇指位来完成的。BL。
111T 1OOO OOOO OOOO BL/BLX <label> (second half)\n | |\n | \\.. long branch link exchange offset low\n \\................. thumb bit\n 0 -- BLX is encoded\n 1 -- BL is encoded\nRun Code Online (Sandbox Code Playgroud)\n操作BLX与后半部分类似BL,但偏移量必须为偶数。该函数在 ARM 状态而不是 Thumb 状态下调用。
temp = next instruction address\nPC = (LR + (offset << 1)) & 0xfffffffc\nLR = temp | 1\nCSPR T bit = 0\nRun Code Online (Sandbox Code Playgroud)\n请注意,总共 22 个立即位给出半字偏移量,从而实现了观察到的分支偏移量 \xc2\xb14\xe2\x80\x89MiB。
\n将两半放在一起,我们还可以BL看到BLX视为具有如下编码的 32 位指令:
1111 0OOO OOOO OOOO 111T 1OOO OOOO OOOO BL/BLX <label>\n | | |\n | | \\.. 22 bit offset (low half)\n | \\................. thumb bit\n \\....................... 22 bit offset (high half)\nRun Code Online (Sandbox Code Playgroud)\n在 Thumb2 中,这个方案得到了扩展。 BL并BLX成为正确的 32 位指令,并且它们的一半必须连续给出。\xe2\x80\xa0 第二个指令字的一些位被定义为将分支偏移扩展到\xc2\xb116\xe2\x80\x89MiB。
1111 0SOO OOOO OOOO 11AT BOOO OOOO OOOO BL/BLX <label>\n | | || | |\n | | || | \\.. 21 bit offset (low half)\n | | || \\............... additional bit J2\n | | |\\................. thumb bit\n | | \\.................. additional bit J1\n | \\....................... 21 bit offset (high half)\n \\................................... sign bit\nRun Code Online (Sandbox Code Playgroud)\n如果设置了拇指位,则BL对指令进行编码。如果清楚的话,则BLX指令被编码。在后一种情况下,21 位偏移必须是偶数。然后分支偏移计算如下:
I1 = !(J1 ^ S)\nI2 = !(J2 ^ S)\nimm32 = (S ? 0xffff << 24 : 0) | (I1 << 23) | (I2 << 22) | (imm21 << 1)\ntemp = next instruction address\nPC = LR + offset\nLR = temp | 1\nif thumb bit clear\n CSPR T bit = 0 \nRun Code Online (Sandbox Code Playgroud)\n虽然对附加偏移位进行编码的方案一开始看起来很复杂,但这只是将两个附加位编码到分支偏移中同时与现有的 和 编码兼容的最简单方法BL。BLX。
如需进一步阅读,请参阅ARM 架构参考手册、ARMv7-A 和 ARMv7-R 版本、 ARM7TDMI数据表以及ARMv5 的ARM 架构参考手册。
\n*\xe2\x80\x83相关编码对1110 0OOO OOOO OOOO16位无条件分支指令进行编码B <label>。
BL\xe2\x80\xa0\xe2\x80\x83在 Thumb2 之前, a or指令的两个部分BLX是独立的指令,可以与其他指令穿插给出,甚至可以单独给出,但强烈建议按连续顺序发出它们。中断也可能发生在BLorBLX指令的两半之间,使得寄存器的临时内容LR可观察。在包括 ARMv6-M 在内的 Thumb2 目标上,这不再可能,并且BL表现BLX为 32 位指令。