文章目录
- 一、ldr
- 1.地址偏移模式
- 2.变基模式
- 3.标签
- 3.1 访问宏定义
- 3.2 访问一个字符串
- 3.3 访问一个data
- 二、ldp和stp
- 1.双字节加载
- 2.双字节存储
- 3.双字节存储的后变基模式
- 三、位操作
- 1. 移位
- 2. 按位操作
- 3. 位段插入
- 4.位段提取
- 5.零计数指令
- 四、跳转指令
- 1. cmp比较两个数
- 2. cmn负向比较
- 五、 条件选择指令
- 1. csel:条件选择指令
- 2. cset:条件置位指令
- 3. csinc:条件选择并增加指令
一、ldr
1.地址偏移模式
/* 读取0x80000地址的值到x0寄存器*/
ldr x0, [x1]/* 读取0x80008地址的值*/
ldr x2, [x1, #8]/* 读取x1+x3 地址的值*/
ldr x4, [x1, x3]/* 读取(x1+ x3<<3) 地址的值*/
ldr x5, [x1, x3, lsl #3]
2.变基模式
/* 前变基模式:先更新偏移地址再访问内存 */
/* 先更新x1的值为X1+8,然后以新的X1值为地址,加载内存的值到x0 */
ldr x6, [x1, #8]!/* 后变基模式:先访问内存地址再更新偏移地址 */
/* 以X1的值为地址,加载该内存地址的值到X0,然后再更新X1寄存器为X1+8*/
ldr x7, [x1], #8
3.标签
3.1 访问宏定义
#define my_label 0x30
ldr x0, =my_label /*把宏的值加载到x0寄存器*/
ldr x1, my_label /* PC值 + 宏的值,然后加载这个地址的值到x1寄存器*/
3.2 访问一个字符串
.globl string1
string1:.string "Boot at EL"ldr x0, string1 /*加载string1的ASCII码的值到x0,加载8个字节的数据*/
ldr x1, =string1 /*加载string1的地址到x1寄存器。若读取地址的值,可以得到string1的ascii*/
3.3 访问一个data
.align 3
.globl my_data
my_data:.word 0x44ldr x0, my_data /*加载mydata的值到x0*/
ldr x1, =my_data /*加载mydata的地址到x1*/
二、ldp和stp
1.双字节加载
//以X0的值为地址,加载此地址的值到x3寄存器,以x0+8为地址,加载此地址的值到X7寄存器
ldp x3,x7,[x0]
2.双字节存储
//存储X1的值到地址为X4的内存中,然后存储x2的值到地址为X4+8的内存中。
STP X1,X2,[X4]
3.双字节存储的后变基模式
将寄存器 x1 的值存储到由 x0 指向的内存地址开始的位置。紧接着将寄存器 x2 的值存储到紧接着 x1 存储位置之后的内存地址。存储完成后,更新 x0 寄存器的值,使其增加 16 个字节。
stp x1, x2, [x0], #16
三、位操作
1. 移位
指令 | 名字 | 含义 |
---|---|---|
lsl | 逻辑左移 | 将寄存器中的每一位向左移动指定的位数,左边空出的位用 0 填充。 |
lsr | 逻辑右移 | 将寄存器中的每一位向右移动指定的位数,右边空出的位用 0 填充。 |
asr | 算术右移 | 将寄存器中的每一位向右移动,但会保留被移出的最高位(符号位),并用它来填充空出的位 |
ror | 循环右移 | 将寄存器中的每一位向右移动,右边移出的数据用来回填最左边的空位 |
逻辑右移和算术右移的区别?
2. 按位操作
- AND: 执行逻辑与操作。
and <destination>, <source1>, <source2>
- EOR (Exclusive OR): 执行逻辑异或操作。
eor <destination>, <source1>, <source2>
- ORR (Bitwise OR): 执行逻辑或操作。
orr <destination>, <source1>, <source2>
- BIC (Bit Clear): 执行逻辑非操作后与另一个操作数进行与操作,用于清除特定位。
bic <destination>, <source1>, <source2>
3. 位段插入
BFI Xd,Xn,#lsb,#width
BFI:位段插入指令。用Xn中的bit[0:width-1]替换Xd中从lsb开始的width位,Xd其他位不变。
例子:使用bfi指令把0x345中的低4位插入到x0寄存器的第八位开始的4位中
mov x1, 0x345
mov x0, 0
bfi x0, x1, 8, 4
4.位段提取
UBFX Xd,Xn,#lsb,#widthSBFX Xd,Xn,#lsb,#width
UBFX:无符号数的位段提取指令
SBFX:有符号数的位段提取指令
从Xn寄存器提取位段,位段从第lsb位开始,位宽为width,然后结果写入到Xd寄存器的最低比特位中。UBFX指令不做符号位的扩展,其他比特位是填充0;SBFX会对有符号位进行扩展,即当提取的位段中,最高位为1时,那么其他比特位会填充为1。
例子:
/*提取x2,从第4个bit开始,提取8bit。x3其他位都是0,最终:0xbc*/
ldr x2, =0x5678abcd
ubfx x3, x2, #4, #8/*提取x2,从第4个bit开始,提取8bit。x4的其他比特位都是f, 最终:0xffffffffffffffbc*/
sbfx x4, x2, #4, #8
5.零计数指令
clz Xd,Xn
CLZ指令会扫描Xn寄存器中的位,从最高位开始计数,直到遇到第一个非零位。计数的结果(即零的数量)会被存储在Xd寄存器中。如果在最高位就遇到非零位,CLZ 指令会返回 0,因为没有任何零位。
例子:
ldr x1, =0x0fffffffffffffff
clz x2, x1
x2的结果为4
四、跳转指令
1. cmp比较两个数
/*相当于x1-x2*/
cmp x1,x2
2. cmn负向比较
/*相当于x1+x2*/
cmn x1,x2
然后查看NZCV位判断结果:
条件后缀 | 含义 | 标志 | 条件码 |
---|---|---|---|
EQ | 相等 | Z=1 | 0b0000 |
NE | 不相等 | Z=0 | 0b0001 |
CS/HS | 无符号数大于或者等于 | C=1 | 0b0010 |
CC/LO | 无符号数小于 | C=0 | 0b0011 |
MI | 负数 | N=1 | 0b0100 |
PL | 正数或零 | N=0 | 0b0101 |
VS | 溢出 | V=1 | 0b0110 |
VC | 未溢出 | V=0 | 0b0111 |
HI | 无符号数大于 | (C=1)&&(Z=0) | 0b1000 |
LS | 无符号数小于或等于 | (C=0)||(Z=1) | 0b1001 |
GE | 带符号数大手或等于 | N=V | 0b1010 |
LT | 带符号数小于 | N!=V | 0b1011 |
GT | 带符号数大于 | (Z=0)&&(N=V) | 0b1100 |
LE | 带符号数小于或等千 | (Z=1)||(N!=V) | 0b1101 |
AL | 无条件执行 | - | 0b1110 |
NV | 无条件执行 | - | 0b1111 |
例子:
1:cmn x1, x2add x2, x2, 1/*查看NZCV操作后缀*/mrs x0, nzcv/*mi: 负数*/b.mi 1b/*测试CMP指令*/mov x2, 3
2:cmp x2, x1add x1, x1, 1/*查看NZCV操作后缀*/mrs x0, nzcv/*cs: 无符号数大于等于*/b.cs 2b
五、 条件选择指令
1. csel:条件选择指令
csel Xd,Xn,Xm,cond
如果cond为真,Xd=Xn,否则Xd=Xm。
2. cset:条件置位指令
cset Xd,cond
如果cond为真,Xd=1,否则Xd=0。
3. csinc:条件选择并增加指令
csinc Xd,Xn,Xm,cond
如果cond为真,Xd=Xn,否则Xd=(Xm+1)。