ARM Assembly(02)-Load and Store
在介绍寄存器的文章中,已经介绍过了MOV指令的用法,可以将一个立即数#k拷贝到通用寄存器GPRs中。但是MOV指令对立即数的范围限制到0~255,如果想对一个寄存器赋值较大数值,该怎么办呢?另外,如何对RAM进行读写操作呢?本文将对ARM汇编的内存访问指令LDR和STR进行介绍
LDR
LDR指令格式如下
1 | LDR Rd,[Rx] |
LDR指令告诉CPU从Rx所指向的一个地址中加载一个字到Rd中。在ARM处理器中,地址是32位的,每个地址对应一个字节的数据宽度,因此LDR会一次性从Rx指向的内存地址连续读取4个字节数据。请看以下例子
1 | LDR R7,[R5] |
假设R5的值为0x48000000,内存0x48000000、0x48000001、0x48000002、0x48000003位置的值分别为0xA2、0x45、0x88、0xC3,执行完这条指令后,R7的值将会是0xC38845A2,内存数据和寄存器R7的关系如下图
LDR还有另外一个用法,给一个寄存器赋值立即数,可以解决MOV指令赋值数值范围限制的问题
1 | LDR Rd,=k |
该指令将Rd赋值为立即数k,这里的k可以是0x00000000-0xFFFFFFFF的任意值
STR
STR指令格式如下
1 | STR Rx,[Rd] |
STR指令告诉CPU将Rx寄存器的内容拷贝到Rd寄存器指向的地址空间。注意STR指令和LDR指令的不同,STR指令操作源在前,目的在后。请看以下例子
1 | STR R3,[R6] |
假设R6的值为0x48000200,R3的值为0x41526374,执行完指令后,内存0x48000200、0x48000201、0x48000202、0x48000203位置的值分别为0x41、0x52、0x63、0x74,内存数据和寄存器R7的关系如下图
Example
这里以一个例子结合LDR的内存加载和立即数赋值用法以及STR指令,使用qemu-system-arm和gdb调试的方式,展示LDR和STR的用法
代码如下
gdb连接程序后,单步运行到第8行位置,查看R0和R1寄存器值,以及内存0x48000000内容
可以看到R0值为0x12345678,R1值为0x48000000,内存0x48000000-0x48000003的值都为0
执行第8行指令后,再次查看0x48000000内容
可以看到,内存0x48000000-0x48000003内容变为了0x12345678
单步执行到第13行位置,查看R2的值
R2为0
执行第13行指令后,再次查看R2的值
可以看到,R2的值确实是从0x48000000读取出来的
LDRB
LDR的变种指令
1 | LDRB Rd,[Rx] |
LDRB指令告诉CPU从Rx指向的地址拷贝一个字节到Rd寄存器中。指令执行后,Rd寄存器的低字节改变,高24bit清零,如下图所示
STRB
LDR有操作单字节的指令变种,STR同样也有
1 | STRB Rx,[Rd] |
STRB指令告诉CPU将Rx寄存器低字节内容拷贝到Rd指向内存位置,高24bit内存数值不变
LDRH
除了操作1个字节外,ARM还提供了一次操作2字节的指令LDRH
1 | LDRH Rd,[Rx] |
LDRH指令告诉CPU从Rx指向的内存拷贝2个字节到Rd的低16位,Rd高16位被清零
STRH
1 | STRH Rx,[Rd] |
STRH指令告诉CPU存储Rx寄存器的低16位到Rd指向的内存