ARM中有两种程序跳转方式:
- 跳转指令;
- 向PC写入目标地址值;
跳转指令
通过跳转指令,可以实现从当前指令向前或者向后32MB的地址空间跳转(一般来讲也足够了,基本上没有需要使用汇编语言写超过32MB程序的场景),总共有4种跳转指令:
- B:跳转指令;
- BL:带返回的跳转指令;
- BLX:带返回和状态切换的跳转指令;
- BX:带状态切换的跳转指令;
带X的指令中的状态切换指的ARM状态和Thumb状态的切换,我们不关注,所以这些指令暂不介绍。
B指令和BL指令
B{L}{cond} <target_address>
// 其中signed_immed_24是编译器根据指令中的target_address计算出来的
if ConditionPassed(cond) then
if L == 1 then
LR = address of the instruction after the branch instruction
PC = PC + (SignExtend(signed_immed_24) << 2)
这两个指令可以带条件执行。B指令仅仅是跳转到目标地址,BL指令会在跳转前先将PC值保存在LR中,所以BL常常用作子程序调用。
在实际编程中,<target_address>通常用标签代替,毕竟程序员不可能在编码的时候知道目标地址的具体值。<target_address>在指令编码中占24位,汇编器会将该值左移2位(所以跳转范围才是正负32MB),然后和PC值相加后作为跳转的目标地址,具体的计算方法可以参考书籍的介绍。
注:正是因为这类指令是将跳转的目标地址编码到指令中的,所以它们的跳转范围才是有限的。
长跳转指令
向PC赋值可以实现在0~4GB地址空间内的任意跳转,所以也叫做长跳转,并且如果在跳转之前,使用“MOV LR, PC”等指令将返回地址保存在LR中,也可以实现类似BL指令的功能。
注:通常使用ADR、LDR等伪指令来实现长跳转。