00. 目录
文章目录
01. 跳转指令概述
跳转(B)和跳转连接(BL)指令是改变指令执行顺序的标准方式。ARM 一般按照字地址顺序执行指令,需要时使用条件执行跳过某段指令。只要程序必须偏离顺序执行,就要使用控制流指令来修改程序计数器。尽管在特定情况下还有其他几种方式实现这个目的,但转移和转移连接指令是标准的方式。跳转指令改变程序的执行流程或者调用子程序。这种指令使得一个程序可以使用子程序、if-then-else 结构及循环。执行流程的改变迫使程序计数器(PC)指向一个新的地址,ARMv5 架构指令集包含的跳转指令如表 3-12 所示
另一种实现指令跳转的方式是通过直接向 PC 寄存器中写入目标地址值,实现在 4GB地址空间中任意跳转,这种跳转指令又称为长跳转。如果在长跳转指令之前使用“MOVLR”或“MOV PC”等指令,可以保存将来返回的地址值,也就实现了在 4GB 的地址空间中的子程序调用。
02. 跳转指令 B 及带连接的跳转指令 BL
跳转指令 B 使程序跳转到指定的地址执行程序。带连接的跳转指令 BL 将下一条指令的地址复制到 R14(即返回地址连接寄存器 LR)寄存器中,然后跳转到指定地址运行程序。需要注意的是,这两条指令和目标地址处的指令都要属于 ARM 指令集。两条指令都可以根据 CPSR 中的条件标志位的值决定指令是否执行。
2.1 B/BL指令的语法格式
B{L}{<cond>} <target_address>
BL 指令用于实现子程序调用。子程序的返回可以通过将 LR 寄存器的值复制到 PC 寄存器来实现。下面 3 种指令可以实现子程序返回。
① BX R14(如果体系结构支持 BX 指令)。
② MOV PC,R14。
③ 当子程序在入口处使用了压栈指令:
STMFD R13!,{<registers>,R14}
可以使用指令:
LDMFD R13!,{<registers>,PC}
将子程序返回地址放入 PC 中。
ARM 汇编器通过以下步骤计算指令编码中的 signed_immed_24。
① 将 PC 寄存器的值作为本跳转指令的基地址值。
② 从跳转的目标地址中减去上面所说的跳转的基地址,生成字节偏移量。由于 ARM指令是字对齐的,该字节偏移量为 4 的倍数。
③ 当上面生成的字节偏移量超过−33 554 432~+33 554 430 时,不同的汇编器使用不同的代码产生策略。否则,将指令编码字中的 signed_immed_24 设置成上述字节偏移量的bits[25:2]。
2.2 应用示例
① 程序跳转到 LABLE 标号处。
B LABLE ;
ADD R1,R2,#4
ADD R3,R2,#8
SUB R3,R3,R1
LABLE:
SUB R1,R2,#8
② 跳转到绝对地址 0x1234 处。
B 0x1234
③ 跳转到子程序 func 处执行,同时将当前 PC 值保存到 LR 中。
BL func
④ 条件跳转:当 CPSR 寄存器中的 C 条件标志位为 1 时,程序跳转到标号 LABLE 处执行。
BCC LABLE
⑤ 通过跳转指令建立一个无限循环。
LOOP:
ADD R1,R2,#4
ADD R3,R2,#8
SUB R3,R3,R1
B LOOP
⑥ 通过使用跳转使程序体循环 10 次。
MOV R0,#10
LOOP:
SUBS R0,#1
BNE LOOP
⑦ 条件子程序调用示例。
…
CMP R0,#5 ;如果 R0<5
BLLT SUB1 ;则调用
BLGE SUB2 ;否则调用 SUB2
03. 带状态切换的跳转指令 BX
带状态切换的跳转指令(BX)使程序跳转到指令中指定的参数 Rm 指定的地址执行程序,Rm 的第 0 位复制到 CPSR 中 T 位,bit[31∶1]移入 PC。若 Rm 的 bit[0]为 1,则跳转时自动将CPSR中的标志位T置位,即把目标地址的代码解释为Thumb代码;若Rm的位bit[0]为 0,则跳转时自动将 CPSR 中的标志位 T 复位,即把目标地址代码解释为 ARM 代码。
3.1 指令格式
BX{<cond>} <Rm>
① 当 Rm[1∶0]=0b10 时,指令的执行结果不可预知。因为在 ARM 状态下,指令是 4字节对齐的。
② PC 可以作为 Rm 寄存器使用,但这种用法不推荐使用。当 PC 作为使用时,指令“BX PC”将程序跳转到当前指令下面第二条指令处执行。虽然这样跳转可以实现,但最好使用下面的指令完成这种跳转。
MOV PC, PC
# 或
ADD PC, PC, #0
3.2 指令应用示例
① 转移到 R0 中的地址,如果 R0[0]=1,则进入 Thumb 状态。
BX R0;
② 跳转到 R0 指定的地址,并根据 R0 的最低位来切换处理器状态。
ADRL R0,ThumbFun+1 ;
BX R0;
04. 带连接和状态切换的连接跳转指令 BLX
带连接和状态切换的跳转指令(Branch with Link eXchange,BLX)使用标号,用于使程序跳转到 Thumb 状态或从 Thumb 状态返回。该指令为无条件执行指令,并用分支寄存器的最低位来更新 CPSR 中的 T 位,将返回地址写入到连接寄存器 LR 中。
4.1 指令格式
BLX <target_add>
其中,<target_add>为指令的跳转目标地址。该地址根据以下规则计算。
① 将指令中指定的 24 位偏移量进行符号扩展,形成 32 位立即数。
② 将结果左移两位。
③ 位 H(bit[24])加到结果地址的第一位(bit[1])。
④ 将结果累加进程序计数器(PC)中。
计算偏移量的工作一般由 ARM 汇编器来完成。这种形式的跳转指令只能实现−32~32MB 空间的跳转。左移两位形成字偏移量,然后将其累加进程序计数器(PC)中。这时,程序计数器的内容为 BX 指令地址加 8 字节。位 H(bit[24])也加到结果地址的第一(bit[1]),使目标地址成为半字地址,以执行接下来的 Thumb 指令。计算偏移量的工作一般由 ARM 汇编器来完成。这种形式的跳转指令只能实现−32~32MB 空间的跳转。
4.2 应用示例
① 从 Thumb 状态返回到 ARM 状态,使用 BX 指令。
BX R14
② 可以在子程序的入口和出口增加栈操作指令。
PUSH {<registers>,R14}
POP {<registers>,PC}
05. 附录
11.1 ARM Architecture Reference Manual