这篇博客躺在我的草稿箱里都快发霉了,续命篇,哈哈
这一篇主要就总结一下ARM汇编中一些指令相关的知识点,指令相关的东西还是挺多的,所以只能挑一些重点来记录。在上一篇中有说指令集相关的内容,这里的话主要是讨论arm指令集,也就是4字节的。
首先,先来看一下指令的一般编码格式,固定占用四字节
对于上图的符号以及参数说明如下:
opcode : 指令操作符编码
cond : 指令执行的条件编码
S : 决定指令的操作是否影响CPSR的值(是否影响标志寄存器)
Rd : 目标寄存器编码
Rn : 包含第1个操作数的寄存器编码
shifter_operand : 表示第2个操作数
也可以看出来,ARM是三地址的指令语法格式,指令的基本格式如下
<opcode>{<cond>}{S} <Rd>,<Rn>,<shifter_operand>
这里的符号说明其实和上面差不多的,因为其指令语法格式和对应的二进制编码并不是顺序对应的
<opcode> : 指令助记符,如ADD表示算术加操作指令
{<code>} : 表示指令执行的条件
{S} : 决定指令的操作是否影响标志寄存器
<Rd> : 表示目标寄存器
<Rn> : 表示包含第一个操作数的寄存器
<shifter_operand> : 表示第2个操作数
对于第二个操作数而言,通常有下面三种格式
1.立即数方式
2.寄存器方式
3.寄存器移位方式
先来看立即数方式,每一个立即数由一个8位的常数循环右移得到,而循环右移多少次是由一个4位的二进制数的2倍来表示
如果立即数记作<immediate>,8位常数记作immed_8,4位的循环右移值记作rotate_imm,那么有如下公式
<immediate> = immed_8 >-> (rotate_imm * 2) //>->表示循环右移,自定义,方便一下书写而已
那么也就是说如果一个立即数可以构造出上面的表达式,那么就是一个合格的立即数,否则就不是合法的,这里也体现出来ARM定长指令的弊端了,比较指令就占4字节,所以其立即数表示的范围有限。
如下就是一些合格的立即数
0xFF = 0xFF >-> (0*2)
0x104 = 0x41 >-> (0xF*2) //这里循环右移30为相当于左移2位即可
0xFF0 = 0xFF >-> (0xE*2) //相当于左移4位
如下一些操作数不是合法的
0x101,0x102,0xFF1
在上面,其实对于这个常数和循环的次数如何决定是编译器做的事,我们只需明白在编写汇编代码时出现一些错误心中有数即可。
注意,在某些时候,我们会认为一些不合法的操作数但是编译通过了,这里并不是说上面的公式有误,而是有可能编译器做了指令的等价替换,简单说不适用上面的规则了,毕竟某些指令我们可以将整个第二操作数都拿来当立即数(12位),只是此时操作符编码会不一样(指令不一致)。
下面再来看寄存器的方式,这种比较好理解,在寄存器方式下,操作数即为寄存器的值
ADD r0,r1,r2 @r0 = r1 + r2
再来看最后一种,寄存器移位方式,寄存器移位方式的操作数为寄存器的数值做相应的移位(或循环移位)得到,具体的移位方式有如下几种
ASR : 算术右移
LSL : 逻辑左移
LSR : 逻辑右移
ROR : 循环右移
RRX : 扩展的循环右移
移位的位数可以用立即数方式或者寄存器的方式进行表示
MOV R0,R1,LSL #3 @R0 = R1 * 2^3 这里mov未使用第一操作数
ADD R0,R1,R1,LSL #3 @R0 = R1 + R1 * 2^3
SUB R0,R1,R2,LSR #4 @R0 = R1 - R2 / 2^4
MOV R0,R1,ROR R2 @R0 = R1 循环右移R2位
下面再来看{<code>}域,这里表示ARM指令的条件码域,大多数ARM指令都可以有条件的执行,也就是根据CPSR中的标志位决定是否执行该指令。当条件满足时执行该指令,条件不满足时该指令被当作一条NOP指令。从最上面的编码格式图中可以看出,其在编码格式中在最高的四位,那么也就是说可以表示16种情况
这里在ARM5之前的版本中,所有的指令都是由条件执行的,从ARMv5版本开始,引入了一些必须无条件执行的指令。
既然在指令里面就有执行的条件,那么说明在一