说明
- 存储器读写指令是用来读写内存/SRAM/外设寄存器等存储器的汇编指令。
- ARM指令集属于RISC指令集,RISC指令集采用典型的加载/存储体系结构,CPU无法对内存里的数据直接操作,只能通过Load/Store指令来实现,当我们需要对内存中的数据进行操作时,要首先将这个数据从内存加载到寄存器,然后在寄存器中对数据进行处理,再将结果重新存储到内存中,如下:
- Load/Store 示例:
char c = 6;
* 对应的汇编代码
mov w0, 6 //先将6保存到通用寄存器w0中
strb w0, [sp, 31] //再将w0数据store到内存栈([sp, 31])中。
int c = a + b;
* 对应汇编代码
ldr w1, [sp, 12] //从栈上将a load到通用寄存器w1
ldr w0, [sp, 8] //从栈上将b load到通用寄存器w0
add w0, w1, w0 //将寄存器w0和w1中的数据相加,在保存到w0
str w0, [sp, 28] //将w0中的数据保存到栈上
对应汇编指令
- aarch64通过str系列指令实现:将寄存器中的数据保存(store)到内存中,以及通过ldr系列指令实现:将内存中数据读取(load)到寄存器中。
数据类型
- 与高级编程语言类似,ARM汇编支持load/store不同的数据类型,可以是有符号或无符号的字、半字或字节, 对应的汇编指令如下:
ldr = Load Word
ldrh = Load unsigned Half Word
ldrsh = Load signed Half Word
ldrb = Load unsigned Byte
ldrsb = Load signed Bytes
str = Store Word
strh = Store unsigned Half Word
strsh = Store signed Half Word
strb = Store unsigned Byte
strsb = Store signed Byte
- 默认(ldr/str)支持无符号的word(4字节)或者8字节,带h表示支持半字(2字节),带b表示支持1个字节,带s表示有符号,
str(store register)/ldr(load register)系列指令
- str/ldr指令
- 操作对象:一个寄存器,操作数据size:和使用的寄存器相关。
str x0, [sp] //将通用寄存器x0中的值(64bits)存储到栈顶指针sp指向的存储地址
str w0, [sp] //将通用寄存器w0中的值(32bits)存储到栈顶指针sp指向的存储地址
ldr x0, [sp, 8] //将栈顶指针sp+8指向地址的数据保存到通用寄存器x0中(64bits)
ldr w0, [sp, 8] //将栈顶指针sp+8指向地址的数据保存到通用寄存器w0中(32bits)
- stp/ldp指令
- 能够同时操作两个寄存器,p表示pair,数据size和str指令一致,常用来做出入栈操作。
stp x29, x30, [sp, -16]!
//将通用寄存器x29和x30的值存储到栈顶指针sp和sp+64指向的存储地址
ldp x29, x30, [sp], 16 //将栈顶指针sp和sp+64指向地址的数据分别保存到通用寄存器x29和x30中
- strb/ldrb指令
- 操作对象:一个寄存器,操作数据size:一个字节(8位)。
strb w0, [sp, 31] //将通用寄存器w0的低8位的字节数据存储到sp+31指向的存储地址
ldrb w1, [sp, 31] //将栈顶指针sp+31指向地址的数据保存到通用寄存器w1的低8位,w1的高24位会被清零
- strh/ldrh指令
- 操作对象:一个寄存器,操作数据size:两个字节(16位)。
strh w0, [sp, 30] //将通用寄存器w0的低16位的两个字节数据存储到sp+30指向的存储地址
ldrh w1, [sp, 31] //将栈顶指针sp+31指向地址的数据保存到通用寄存器w1的低16位,w1的高16位会被清零
- stur/ldur指令
- 功能和str/ldr一样, 但是stur/ldur后面的立即数通常是负数。
ldur x1,[x0,#-1] //负数立即数
ldr x1,[x0,#1] //正数立即数
伪指令
- ldr既是一个汇编指令,也是一个伪指令的助记符,作为伪指令,其用于加载一个立即数或地址值到寄存器。
- 语法
LDR{condition} register,=[expression | label-expression]
汇编指令/伪指令区分
- 使用"[]“的是指令,使用”="的是伪指令,如下:
ldr x0, [sp, 8] //汇编指令
ldr x4, =0x04140000 //伪指令,将数据0x04140000 保存(load)到x4中。
和mov指令区别
- 伪指令ldr作用和mov指令比较类似,但是有些立即数,mov指令无法支持,如果mov能表示,替换成mov指令也是可以。
变址寻址方式
- 自身不变化
ldr x5, [x6, #0x8] //等同于 *x5 = *(x6 + 0x8),x6中的数据不变化
- 返回后变化
ldr x5, [x6], #0x8 //等同于 *x5 = *x6, x6 += 0x8,将x6指向地址的数据保存到x5,x6中的地址数据偏移8字节(+8)
- 返回前变化
ldr x5, [x6, #0x8]! //等同于 x6 += 0x8,*x5 = *x6,先将x6中的地址数据偏移8字节(+8),再取出其指向的数据到x5中