ARM的STM和LDM指令详解

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

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

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

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

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

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

(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的顺序任意)


PS:
实际上是编译器进行了处理:
LDM/LDMIA/LDMFD  同一条指令
STM (STMIA, STMEA)  同一条指令

 

转自:http://blog.chinaunix.net/uid-9185047-id-3754184.html

展开阅读全文

请教ARM中的LDMSTM的用法

11-20

按照我的理解ldm/stm应该是这样的:rnldmia r1!, r5-r11 ///从r1开始的地址读取7x4共28个字节分别付给r5--r11rn stmia r0!, r5-r11 ///把r5--r11中的7x4共28个字节 付给r0开始的地址。rnrn可是我做的测试函数如下,发现根本不是这样的,好像r5--r11每个寄存器中只保存了2个字节,请问下为什么。rnrn我的测试程序如下:rn[code=c].textrn .global sno_memcpy32Bytesrn .type sno_memcpy32Bytes,%functionrn .align 4rn rnsno_memcpy32Bytes: rn .fnstartrn .save r0, r4, lrrn stmfd sp!, r0, r4, lrrn rn .pad #28 rn sub sp, sp, #28 rn stmea sp, r5-r11 rn rn rn1: ldmia r1!, r5-r11 rn stmia r0!, r5-r11rn rn subs r2, r2, #32 rn bhs 1b rnrn ldmfd sp, r5-r11rn add sp, sp, #28rn ldmfd sp!, r0, r4, lrrn bx lr ///return ;rn .fnendrn[/code]rn下面是C语言的调用,我特意把他32字节对齐了rn[code=c]#include rnrnextern int sno_memcpy32Bytes(int *dst,int *src,int len);rnint main()rnrn int __attribute__ ((aligned (32))) srcBuf[32];rn int __attribute__ ((aligned (32))) dstBuf[32];rn rn int i;rn rn for(i=0;i<32;i++)rn rn srcBuf[i]=i+1; rn dstBuf[i]=1111;rn rn rn sno_memcpy32Bytes(dstBuf,srcBuf,32);rn rn printf("-----%s------\n",__TIME__);rn for(i=0;i<32;i++)rn rn printf(" %d",dstBuf[i]); rn rn printf("\n");rn return 0;rn rn[/code]rnrn我的编译条件是:rn arm-none-linux-gnueabi-gcc test_memcpy32Byte.c sno_memcpy32Bytes2.S -o test_memcpy32Byte -static rnrn可是打印条件确实这样的:rn 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111rnrn运行环境是C8650手机的俺卓2.3.3,指令集是armv6lrnrn请高手帮帮,谢谢了!!!!!!!!!!rn 论坛

向各位大哥请教对加载/存储指令 LDMSTM

01-21

请教:rnLDMIA R0!,R3-R9 ;加载 R0 指向的地址上的多字节数据,保存到 R3-R9 中,R0 值更新rnSTMIA R1!,R3-R9 ;将 R3-R9 的值存储到 R1 指向的地址上,R1 值更新rnSTMFD SP!,R0-R7,LR ;现场保护,将 R0-R7,LR 入栈rnLDMFD SP!,R0-R7,PC^ ;恢复现场,异常处理返回 rnrn这里有几个问题向各位大哥请教:rnrn问题一:rnLDMIA R0!,R3-R9 ;加载 R0 指向的地址上的多字节数据,保存到 R3-R9 中,R0 值更新rnrn小问题1:rn假设 R0 的初值是 0x11,R0 又不是指针,怎么能说 R0 指向的地址呢?rn还有又怎么知道 R0 指向的地址值是多少呢?rnrn小问题2:rn假设 R0 的初值是 0x11 ,是不是给 R3-R9 中的每个寄存器都赋值 0x11 啊?rnrn小问题3:rn假设 R0 的初值是 0x11 ,那么 R0 值更新后,R0 值是多少啊?rnrnrn问题二:rnrnSTMFD SP!,R0-R7,LR ;现场保护,将 R0-R7,LR 入栈rnrn小问题1:rn这句话的意思能不能理解为:将 R0-R7,LR 的数据存储到 SP 指向的地址上?rnrn小问题2:SP 的值要不要更新,如果会更新的话,那么和原来的值相比,是rn 增加多少?或者减少多少?rn小问题3:rn 现场保护 为什么要把 LR 也入栈呢?rnrn问题三:rn LDMFD SP!,R0-R7,PC^ ;恢复现场,异常处理返回rn rn小问题1:rn PC 得到的值,是 STMFD SP!,R0-R7,LR 的rn LR 的值吗?rnrn SP 的值要不要更新,如果会更新的话,那么和原来的值相比,是rn 增加多少?或者减少多少?rn 论坛

没有更多推荐了,返回首页