根据调用规则ATPCS,程序一般都使用FD(FullDescending)类型的数据栈(满栈),那么对立的就由空栈类型的数据栈。空栈是指SP操作完后指向的地址空间是未使用的,反之满栈就是SP指向的地址已经使用了。所以对应到压栈出站时的操作就有一点点不一样。如果是满栈模型则会先执行栈指针的操作后在向栈指针指向的位置写入,反之就是先写入在移动栈指针。这里先要明确数据传输语法的基本语法格式。
数据传输指令语法格式:
CMD{cond} Rn{!}, reglist{^}
CMD 为命令有LDM*/STM*
cond 为条件码(可选)
Rn 为基址寄存器
{!} 可选后缀,选用后缀后表示请求回写,即当数据传输完成后将最后的地址写入到基址寄存器Rn中,不选用则基址寄存器内容不改变
{^} 该后缀表示后面的寄存器都是用户模式下的寄存器;其次当CMD为LDM且寄存器列表中包含R5(PC)时,除正常传输数据还需要将SPSR复制到CPSR
LDM和STM还分为两种情况,一种是普通数据传送,还有一个是用于堆栈的操作时。
普通数据传输过程中使用IA IB DA DB区别基址的移动方向,其中A和B分别表示befor和after,I和D分别表示Increment和Decrement。
xxxIA 传送后地址增加4
xxxIB 传送前地址增加4
xxxDA 传送后地址减少4
xxxDB 传送前地址减少4
用于堆栈时用FD,ED,FA,EA来区别栈操作的方式其实就是区别一下方式是相同的。F表示Full (满栈)而E表示Empty(空栈)。A表示Ascenging(递增),D表示Descending(递减)。组合起来就是:
xxxFD 满栈递减栈(ARM核通常时这种)
xxxFA 满栈递增栈
xxxED 满栈递减栈
xxxEA 空栈递增栈
总结一下就是如下:
LD : load 加载,出栈操作 ST : store 存储,入栈操作 M : multi 多次 F: full 满栈,SP指向最后一个数据 E: empty 空栈,SP指向与最后一个数据相邻的下一个可写入存储单元 D: descending 递减,代表栈的增长方向 A: ascending 递增,代表栈的增长方向
STMFD/LDMFD指令详解
STMFD SP,{R0-R3} ;执行伪指令大致是: ;SP-4 = R3 ;SP-8 = R2 ;SP-12 = R1 ;SP-16 = R0 ;SP 的值未修改。 LDMFD SP,{R0-R3} ;执行伪指令大致是: ;R3 = SP-4 ;R2 = SP-8 ;R1 = SP-12 ;R0 = SP-16 ;SP 的值未修改。 STMFD SP!,{R0-R3} ;执行伪指令大致是: ;SP-=4 ;SP = R3 ;SP-=4 ;SP= R2 ;SP-=4 ;SP= R1 ;SP-=4 ;SP = R0 ;SP-=4 ;SP 的值已修改。 STMED SP!,{R0-R3} ;执行伪指令大致是: ;SP = R3 ;SP-=4 ;SP= R2 ;SP-=4 ;SP= R1 ;SP-=4 ;SP = R0 ;SP-=4 ;SP 的值已修改。
参考:
http://blog.chinaunix.net/uid-28458801-id-3791987.html
https://blog.csdn.net/stephenbruce/article/details/51151147
https://www.jianshu.com/p/aa4695b6bc26
https://blog.csdn.net/weiwei_xiaoyu/article/details/20563479