ARM LDR/STR, LDM/STM 指令

这里比较下容易混淆的四条指令,已经在这4条指令的混淆上花费了很多精力,现在做个小结,LDR,STR,LDM,STM这四条指令,

关于LDM和STM的说明,见另外一个说明文件,说明了这两个文件用于栈操作时的注意事项。

(1)LDR:L表示LOAD,LOAD的含义应该理解为:Load from memory into register。下面这条语句就说明的很清楚:

LDR   R1,     [R2] ; R1<——[R2]

就是把R2所指向的存储单元的内容的值(一个memory地址内的值),读取到R1中(一个register)

(2)STR:S表示STORE,STORE的含义应该理解为:Store from a register into memory。下面这条语句表示的很清楚:

STR    R1,     [R2] ; R1——>[R2]

就是把寄存器R1中的内容“保存”到R2所指向的存储的单元中(一个memory地址)。

显然,这两条语句都有个特点,就是寄存器写在前面(左边)而内存地址写在后面(右边),数据传送的方向则是恰好相反的。

下面对LDM和STM介绍,使用sp来介绍,因为实际使用中,和sp一起使用更多。

(3)LDM:L的含义仍然是LOAD,即是Load from memory into register。

虽然貌似是LDR的升级,但是,千万要注意,这个指令运行的方向和LDR是不一样的,是从左到右运行的。

该指令是将内存中堆栈内的数据,批量的赋值给寄存器,即是出栈操作;

其中堆栈指针一般对应于SP,注意SP是寄存器R13,实际用到的却是R13中的内存地址,只是该指令没有写为[R13],

同时,LDM指令中寄存器和内存地址的位置相对于前面两条指令改变了,下面的例子:

LDMFD     SP! ,   {R0, R1, R2} ; 实际上可以理解为:    LDMFD     [SP]!,    {R0, R1, R2}

意思为:把sp指向的3个连续地址段(应该是3*4=12字节(因为为r0,r1,r2都是32位))中的数据拷贝到r0,r1,r2这3个寄存器中去

(如果这个地方还不懂的话,可以参看我文章开头提到的链接,里面有详细的图解)

(4)STM:S的含义仍然是STORE,与LDM是配对使用的,其指令格式上也相似,即区别于STR,是将堆栈指针写在左边,而把寄存器组写在右边。

STMFD      SP!,   {R0} ; 同样的,该指令也可理解为:  STMFD      [SP]!,   {R0}

意思是:把R0保存到堆栈(sp指向的地址)中。

显然,这两个堆栈操作指令也有个特点,就是寄存器组写在后面(右边)而堆栈指针写在前面(左边),

而且实际上使用的是堆栈指针中的内存地址,这一点与前面两条指令是有区别的。

(补充:sp后面的!,作用是指命令执行完后,对应的地址值赋给sp,对于例程的SDM,是说最后sp的值应该是sp+3*4=sp+12)

这四条指令中,前面两条和后面两条其实联系不多,反而是差别很大,因此,可以直接把这两组指令区分开来,认为它们之间没有联系,这样避免误解。

STM和LDM的主要用途是现场保护、数据复制、参数传递等,其模式有8种,如下:

注:前面4种用于数据块的传输,后面4种用于堆栈操作

(1)IA  每次传送后地址加4 -- Inc After

(2)IB  每次传送前地址加4 -- Inc Before

(3)DA  每次传送后地址减4 -- Dec After

(4)DB  每次传送前地址减4 -- Dec Before

(5)FD  满递减堆栈

(6)FA  满递增堆栈

(7)ED  空递减堆栈

(8)EA  空递增堆栈

下面的讲述对于空递减堆栈和空递增堆栈同样适用.

在堆栈操作时,经常错误以为使用STMFD满递减将寄存器压入堆栈后,在弹出数据的时候应该使用LDMFA。

但是FD和FA仅用于指示目前操作的堆栈是何种模式(堆栈共有四种模式),FD指明目前的堆栈是满递减堆栈,

则数据入栈时的指令为STMFD,那么数据出栈时的指令对应的为LDMFD,而不是LDMFA。

我们可以这样认为STMFD等价于STMDB,LDMFD等价于STMIA

那么,数据传输的顺序和数据入栈的顺序又是如何呢

先来看STMFD SP!,{R1-R3}  执行的结果图(操作之后SP指向SP‘)

                 SP------->
                           |R3|
                           |R2|
                 SP‘------>|R1|

那么STMFD SP!,{R3,R2,R1}执行后的堆栈顺序是不是刚好和上面的堆栈顺序相反,实际情况时这两个指令执行后的堆栈数据顺序一样,

因为ARM编译器会自动将STMFD SP!,{R3,R2,R1}转换为STMFD SP!,{R0-R3}指令,也就是说,ARM编译器默认高寄存器优先存入堆栈。

即便你在指令STMFD SP!,{R3,R2,R1}中刻意“安排”了寄存器入栈顺序,而在编译时编译器又重新做了处理,打乱了你期望的数据入栈顺序。

同理STMDB R0!,{R1-R3}和STMDB R0!,{R3,R2,R1}指令执行后数据在堆栈中的顺序完全一致。

STMFD SP!,{R1-R3}指令对应的出栈指令是LDMFD SP!,{R1-R3}(R1,R2,R3的顺序任意)

时间: 2024-10-11 01:23:16

ARM LDR/STR, LDM/STM 指令的相关文章

arm汇编:ldr,str,ldm,stm,伪指令ldr

ldr,str,ldm,stm的命名规律: 这几个指令命名看起来不易记住,现在找找规律. 指令 样本 效果 归纳名称解释 ldr Rd,addressing ldr r1,[r0] addressing to Rd [mem to reg] load to register str Rd,addressing str r1,[r0] Rd ro addressing [reg to mem] store register ldm Rn,reglist ldmfd sp!,{r0-r7,pc} *

ARM汇编中的LDR/STR

在ARM架构下,  数据从内存到CPU之间的移动只能通过LDR/STR指令来完成.而MOV只能在寄存器之间移动数据,或者把立即数移动到寄存器中,并且数据的长度不能超过8位 LDR,STR 的第一操作数是目标寄存器,第二操作数是内存地址, LDR 内存 --> 寄存器; STR 寄存器 --> 内存 内存的表示方式有:立即数,寄存器,或寄存器加偏移,立即数:内存的物理位置,前面加个#,如0x56000050 寄存器,加个[],如[r1],偏移的话[r1,r2],或者[r1,#4],[r1,LSL

ARM LDR 汇编命令

ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令.想把数据从内存中某处读取到寄存器中,只能使用ldr.比如: ldr r0, 0x12345678 就是把0x12345678这个地址中的值存放到r0中. 而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方. x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中. 另外还有一个就是ldr伪

ARM LDR伪指令用法详解

LDR伪指令 10.45 LDR pseudo-instruction   功能:把一个32位立即数或一个32位的内存地址加载到一个寄存器中. 注意:这里描述的是LDR伪指令,而不是LDR指令   语法:               LDR{cond}{.W} Rt, =expr LDR{cond}{.W} Rt, =label_expr *   cond是一个可选的条件码 *  .W是可选的指令宽度说明符 *   Rt是要加载的寄存器 *   expr是一个数字表达式 *   label_ex

ARMv7 ldr/str指令详解

因为ARM的算术运算不支持直接操作内存地址,所以要把内存里的数据先加载进寄存器.ldr指令就是干这事的,称为间接取址模式. 一共有3*3九种模式,先是直接偏移,先偏移,后偏移三大类,指的是如何对源操作数操作,是直接使用,还是在加载前对源操作数操作(比如地址加个数值),还是在加载后对操作数操作 每个大类里分三个小类,分别指源操作数是立即数,寄存器,还是标量寄存器(比如对寄存器里的数向左偏移两位,即乘4) 汇编指令和对应的C代码如下 1 Immediate offset: 2 3 LDR R0, [

ARM汇编-str指令

STR指令的格式为:STR{条件}  源寄存器,<存储器地址>STR指令用亍从源寄存器中将一个32位的字数据传送到存储器中.该指令在程序设计中比较常用,丏寻址方式灵活多样,使用方式可参考指令LDR. 指令示例:STR R0,[R1],#8             :将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1.STR R0,[R1,#8]             :将R0中的字数据写入以R1+8为地址的存储器中.” STR     r1, [r0]          

【汇编指令】ARM指令集之PSR传送指令

ARM指令集提供了两条指令,可直接控制程序状态寄存器(PSR,Program State Register).MRS指令用于把CPSR或SPSR的值传送到一个寄存器:MSR与之相反,把一个寄存器的内容传送到CPSR或SPSR.这两条指令结合,可用于对CPSR和SPSR进行读/写操作. cpsr_c代表的是这32位中的低8位,也就是控制位 CPSR有4个8位区域:标志域(F).状态域(S).扩展域(X).控制域(C) 通过一般示例如下观察PSR指令的相关操作: 1 > [切换到IRQ模式] 2 >

ARM处理器架构的Thumb指令集中关于IT指令的使用

在ARMv6T2以及ARMv7架构扩展了Thumb指令集,其中加入了IT指令,进一步增强了代码的紧凑性. Thumb中有一个比较有意思的指令--IT,这条指令用于根据指定的条件来执行后面相继的四条指令.当然,Thumb-2中大部分算术逻辑指令都含有带条件执行的特征,不过Thumb-2是32位的.如果你需要更紧凑的指令,那么使用Thumb结合ThumbEE来做带条件的指令执行还是不错的选择.Thumb本身不具备带条件指令执行的特性. IT指令的描述为:IT{<x>{<y>{<z

7.arm汇编 bic和orr指令

1. bic BIC指令的格式为: BIC{条件}{S}  目的寄存器,操作数1,操作数2 BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中. 操作数1应是一个寄存器, 操作数2可以是一个寄存器.被移位的寄存器.或一个立即数. 操作数2为32位的掩码,如果在 掩码中置了某一位1,则清除这一位.未设置的掩码位保持不变. bic r0,r0,#0x1f 0x1f=11111b 其含义:清除r0的bit[4:0]位. 2. orr ORR指令的格式为: ORR{条件}{S}  目的寄存器