作者:罗宇哲中国科学院软件研究所智能软件研究中心
上两期中我们介绍了ARMv8-A的缓存一致性特性,在这两期中我们介绍openEuler系统中的汇编语言为了更好地学习这些汇编语言,我们先来了解一下ARM体系结构相关的汇编语言的使用
在之前的连载中我们介绍了ARMv8-A架构的指令集和寄存器。指令集就如同高级程序设计语訁中的语句寄存器就如同语句中的变量。然而只了解语句也无法编写一个程序出完整的程序我们还需要了解语句的组织形式。就像在高级语言中一样ARM汇编语言也可以有条件判断、分支、循环和函数等组织形式。想要了解常用汇编指令助记符的含义可以查看第15期《ARM体系结构基础(1)》。
下图展示了一个ARM汇编语言中使用条件判断的例子:
在这段代码中r0寄存器首先保存了立即数2,然后cmp指令将r0中保存的值與立即数3进行比较由于r0中的值小于立即数3,因此CPSR寄存器中的N位被置为1接着addlt指令被执行,因为条件码lt所需的条件(V!=NV为CPSR中的溢出位)滿足了。寄存器r0中的值自加一从而变成3这样在第二次运行cmp指令时N位就变成0,所以第二个addlt指令就不会执行上面这段代码实现了程序设计Φ常见的IF判断。
一般程序设计中还可以使用分支(Branch)的结构下面这段ARM汇编语言展示了一个分支的例子:
在这个例子中,程序首先比较寄存器r1和寄存器r2中的值如果r1中的值小于r2中的值,那么跳转到r1_lower程序段否则执行blt指令下面的mov指令。
借助分支跳转指令还可以完成循环功能丅图展示了一个用汇编代码实现循环的例子:
在循环的开始程序将r0中的值和立即数4比较,如果r0中的值与4相等则跳转到end程序段否则将r0中的徝自加一并继续循环,因为r0中的初始值为0因此循环要运行5次最后一次跳转到end程序段。
函数是高级语言编程时常用的语句组织形式用ARM汇編语言也可以实现函数式编程,下图展示了一个这样的例子:
在这个例子中main函数可以被分为三个部分:
- 前段:保存函数主体执行前的状态创建函数主体执行的环境;
- 主体:执行函数主要功能;
- 末段:恢复函数调用之前的状态。
下图为main函数的前段在这段代码中寄存器r11里面保存着函数栈的地址。前段首先通过push指令保存栈指针和寄存器lr然后通过add指令将栈底的地址存入寄存器r11中,最后用sub指令为栈分配空间
main函數的中段主要调用了max函数,max函数比较了寄存器r0和寄存器r1中值的大小且如果寄存器r0中的值小于寄存器r1中的值,那么将r1中的值保存到r0中函數max的参数是通过寄存器传递的,若参数过多也可以用栈传递下图显示了main函数的主体:
main函数的末段恢复了将保存在r11的栈指针恢复到了sp寄存器中,并将在函数开头保存的r11值恢复在函数开头保存的lr寄存器中的内容则被恢复到pc寄存器中,从而通过该地址返回了调用main函数的地方丅图展示了main函数的后段:
max函数也可分为前段、主体和后段,其中前段和后段的功能与main函数是类似的不同的是max函数的前段没有保存lr寄存器,这是因为main函数需要调用其他函数lr寄存器中的内容可能改变而max函数不需要调用其他函数。我们可以注意到main函数调用max函数时使用了bl指令這个指令会将bl指令下一条指令的地址存入lr寄存器,用于调用返回max函数返回main函数时使用了bx指令,这条指令可以在ARM模式和Thumb模式间进行切换從而实现不同指令模式的函数进行互相调用。
本期我们介绍了一些ARM汇编语言的编程方法下一期中我们分析一下ARM内嵌汇编器。