3.8.2 分支跳转指令
如果一个处理器不能跳转执行指令,那么程序的判断、循环结构以及函数调用将不能实现。这样的处理器是不是糟透了,我想肯定是的。庆幸的是,大部分处理器都支持跳转执行指令,ARM920T也不例外。
ARM920T支持如下几条分支跳转指令,来实现程序的跳转执行。
□b。
□bl。
□bx。
□blx。
1.b、bl指令
指令在汇编程序中的用法:
b{l}{cond} <lable_offset>|<Rn>
□{}中的表示可选项。
□<>中的表示必需项。
□|表示多选一。
□cond表示条件码,如EQ、NE、CS。
□l为链接位,如果在“b”后面写上“l”表示在执行跳转动作的同时,将原来的PC值写入当前模式下的R14寄存器中。
□lable_offset表示跳转标号即跳转地址。
□Rn表示一个合法的寄存器,一般通用寄存器都行。
分支跳转指令中包含了一个有符号补码的24位偏移量。该值左移两位后并将其有符号位扩展到32位,因为有效位数为25位加1位符号位,所以最多能表示32MB,然后加入R15中。因此该指令可以指定±32MB的分支跳转。分支跳转偏移还必须考虑预取操作,因为PC超前于当前指令的2个字。分支跳转地址如果超过了±32MB,必须将这个地址事先装载到某一通用寄存器中。例如,将这个地址先装入R0中,再执行“bl r0”。
例如:
main: ;标号,汇编器和程序链接器最后会把它转换成地址 mov r0,#2 ;r0=2 mov r1,#3 ;r1=3 bl addfunc1 ;r14=pc;pc=pc+offset(addfunc1)。保存pc至r14并跳转到addfunc1 ;地址上运行。注意offset(addfunc1)是编译工具处理的,表示当前pc和addfunc1 ;的绝对地址之间的差值 lable: ;标号 b lable ;PC=offset(lable)死循环。注意offset(lable)是编译工具处理的, ;表示当前pc和lable的绝对地址之间的差值 addfunc1: ;标号 add r0,r0,r1 ;r0=r0+r1 b r14 ;pc=r14实现子程序返回
这段程序非常简单,看代码注释就能明白它是干什么的,但我们主要是为了解b、bl指令的使用方式,当然没有写条件码,所以默认情况下指令总是会执行。
2.bx指令
bx指令是将一个寄存器中的内容(通常这个内容是一个程序的地址),放进PC寄存器中,导致程序的跳转执行并且它还改变处理器的状态:ARM状态到Thumb状态或者Thumb状态到ARM状态。bx指令用Rn寄存器中的数据和0xFFFFFFFE进行与操作,把结果写到PC寄存器中,然后根据Rn寄存器第0位的值决定处理器的运行状态,即用这个值设置CPSR寄存器的T位,也就是处理器的状态位。
汇编程序中的用法:
bx{cond} <Rn>
□{}中的表示可选项。
□<>中的表示必需项。
□cond表示条件码。
□Rn表示一个合法的寄存器。
例如:
.code32 ;32位的ARM状态指令 main: adr r0,thumb_ins+1 ;r0=thumb_ins+1 bx r0 ;pc=r0,并进行处理器状态切换 .code16 ;16位的thumb状态指令 thumb_ins: adr r0,main ;r0=main, main的地址 bx r0 ;pc=r0,并进行处理器状态切换
3.blx指令
blx指令有两种情况,一种是无条件执行,只能跳转到Thumb指令的地址并切换处理器状态为Thumb状态;另一种是有条件执行的,可以在ARM状态和Thumb状态之间互相切换和跳转。这两种情况都会在跳转的同时先保存PC至R14中。
在汇编中的用法:
第1种为blx<lable_offset>。
□<>中的表示必需项。
□lable_offset表示跳转标号即跳转地址。使用规则和bl指令一样。
第2种为blx{cond}<Rn>。
□{}中的表示可选项。
□<>中的表示必需项。
□cond表示条件码。
□Rn表示一个合法的寄存器。
例如:
.code32 ;32位的ARM状态指令 main: adr r0,thumb_ins+1 ;r0=thumb_ins+1 blx r0 ;r14=pc,pc=r0并且进行处理器状态切换 .code16 ;16位的thumb状态指令 thumb_ins: adr r1,main ;r1=main,r1=main的地址 blx r1 ;r14=pc,pc=r1,并进行处理器状态切换