zoukankan      html  css  js  c++  java
  • ARM LDR/STR, LDM/STM 指令

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

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

    1LDRL表示LOADLOAD的含义应该理解为:Load from memory into register。下面这条语句就说明的很清楚:

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

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

    2STRS表示STORESTORE的含义应该理解为:Store from a register into memory。下面这条语句表示的很清楚:

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

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

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

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

    3LDML的含义仍然是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个寄存器中去

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

    4STMS的含义仍然是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的顺序任意)

  • 相关阅读:
    解决绘图中闪烁的问题(C#)
    创建XML文件以及XML中的节点和更新Xml文件中的节点的值
    在C#中SendMessage和PostMessage的参数传递
    [置顶]在C#中SendMessage和PostMessage的参数传递
    C#中使用DOS命令关闭当前正在运行的程序并重新启动
    Winform中扩展Panel使之具备双缓存,防止闪屏
    用C#调用Windows API向指定窗口发送
    界面控件
    观察站模式
    利用dataview为datatable排序
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4643224.html
Copyright © 2011-2022 走看看