上文介绍了ARM的数据处理指令,本文将主要介绍ARM中的跳转指令。
【跳转指令】
无条件跳转
ARM中的基础跳转指令就一个字母"B",代表Branch,相比起x86中和它功能基本相同的"jmp"指令,意思显得稍微隐晦了点。"B"属于无条件跳转,就是不管三七二十一,跳就对了,如果跳转的目标地址不是由立即数直接给出,而是通过寄存器给出,那就应该使用"BX"。
B label ;jump to the address given by the label
BX reg ;jump to the address given by the register
目标地址是否由寄存器给出只是表象,真正的区别在于,由于"B label"这条指令整个是占4个bytes,也就是32个bits,而这32个bit不可能全给"label"这个操作数用,所以如果用"label"表示绝对地址的话,是无法寻址整个32位地址空间的。这也不碍事,把"B label"作为相对跳转指令好了,"label"在这里就是基于当前PC的相对地址。(如果想查看像下图这样的某个指令的编码格式,可以上这个网站)。
无条件指令没有"Cond"部分,所以留给"label"用的有28个bits,由于相对跳转可以是朝前或者朝后,所以还需要留一个bit表示方向,因此ARMv8中"B label"的跳转范围是前后128MiB(ARMv7是前后32MiB)。
"BX"就没有这个烦恼,因为寄存器的位宽是32位/64位,直接用寄存器给出的绝对地址就可以跳转到任何一个地址单元。前文讲过,ARMv8将通用寄存器的名称由"R"改成了"X",神奇的是,ARMv7中"BX"在ARMv8中居然变成了"BR",整个反过来了。
有的时候,"B"后面还会跟上一个"L","L"代表记录函数返回地址的link register(R14/X30),暗示接下来的跳转其实是一个子函数调用,类似于x86中的"call"指令。
有条件跳转
更多的时候,跳转是结合着一定的条件进行的,对应我们的高级语言就是"if", "else"这样的。比如"BEQ"就是相等(equal)的时候才跳,而是否相等则是由前序的指令,比如比较指令"CMP"执行后的结果(Zero)决定的。
BEQ后面跟的地址也是相对地址,而且这个地址范围不再是前后128MiB,而是前后1MiB。汇编指令的数目越少,形成的二进制镜像所占的代码段空间就越小,执行效率也可能更高。
为此,还有一些二合一的指令,相当于把两条有相关性的指令压缩在了一起,比如"CBZ"就等同于"CMP"加上"BEQ",这也是前文提到的"RISC和CISC之间相互融合"的一个例证,毕竟,占用代码空间小,执行效率高的优点谁不想要呢。
虽然普通的条件跳转指令就可以表达"if", "else"这样的分支语句,但如果分支嵌套层次较多,直接使用条件跳转指令就显得不够高效了。为此,ARMv7专门推出了长的和高级语言的关键字很像的"IF‐THEN(IT)",这已经不是一条单独的指令了,而是一个指令块(IT blocks)。它的格式是这样的:
IT <x> <y> <z> <cond>
<x>,<y>,<z>的总数从0到3个不等,其取值可以是"T"或者"E"(顺序没有要求),其中"T"(Then)对应条件(cond)成立时执行的语句,"E"(Else)对应条件不成立时执行的语句。比如这样一段C语言代码:
if (R0==R1) { R3 = R4 + R5; R3 = R3 / 2; }
else { R3 = R6 + R7; R3 = R3 / 2; }
使用IT指令块汇编的结果是这样的:
CMP R0, R1 ; compare R0 and R1
ITTEEEQ ; if R0 == R1, Then-Then-Else-Else
ADDEQ R3, R4, R5 ; R3 = R4 + R5
ASREQ R3, R3, #1 ; R3 = R3 / 2
ADDNE R3, R6, R7 ; R3 = R6 + R7
ASRNE R3, R3, #1 ; R3 = R3 / 2
是不是非常紧凑,代码行数跟其对应的高级语言都不相上下。这种指令对软件来说是相当友好的,但鱼和熊掌不可兼得,为软件层面提供更大的便利通常意味着需要在硬件层面做更多更复杂的工作,而且可能造成效率的损失。这也不难理解,像python这种语言开发更快捷,但执行效率就比不上C语言。所以啊,ARM的工程师权衡利弊,最终在ARMv8中移除了这个指令块。
替代方案是使用一组新的指令,包括CSEL(Conditional Select), CINC(Conditional Increase)和CSET(Conditional Set)等,以CSEL为例,它的用法是这样的:
CSEL <Xd>, <Xn>, <Xm>, <cond>
意思是如果条件(cond)满足,就选择(sel)Xn作为Xd,否则选择Xm作为Xd。比如下面这条语句:
CSEL X0, X0, X1, ge
表示的是如果X0>=X1(ge - greater or equal),那么X0=X0(保持不变),否则X0=X1。虽然比IT指令块的语法看起来要直观一些,但比起IT指令块能表达的层级关系,还是稍微弱了一点。
参考:
https://azeria-labs.com/arm-conditional-execution-and-branching-part-6/
原创文章,转载请注明出处。