arm堆栈操作(DOC)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
arm堆栈操作
arm堆栈的组织结构是满栈降的形式,满栈即sp是要停留在最后一个进栈元素,降:就是堆栈的增长方向是从高地址向低地址发展。
arm对于堆栈的操作一般采用LDMFD (pop)和STMFD (push) 两个命令。
以前困惑的就是STMFD 命令对于操作数是按照什么顺序压栈的
比如:STMFD sp!{R0-R5,LR} 进栈顺序是:
高地址(1方式)
LR
R5
R4
```````
R0 <-sp
低地址
还是:
高地址(2方式)
R0
R1
```
R5
LR <-sp
低地址
现在通过下表,可以轻松的解决这个问题:
按照图表,可知STMFD对应的是STMDB,根据arm指令手册,可知STMDB入栈顺序是(1方式)
而LDMFD对应的是LDMIA,这样这两个操作就可以成功配对:
以下是我在学习ARM指令中记录的关于堆栈方面的知识
1、寄存器R13 在ARM 指令中常用作堆栈指针
2、对于R13 寄存器来说,它对应6
个不同的物理寄存器,其中的一个是用户模式与系统模式共用,另外5个物理寄存器对应于其他5种不同的运行模式。采用以下的
记号来区分不同的物理寄存器:
R13_
3、寄存器R13在ARM指令中常用作堆栈指针,但这只是一种习惯用法,用户也可使用其他的寄存器作为堆栈指针。而在Thumb指令集中,某些指令强制性的要求使用R13作为堆栈指针。由于处理器的每种运行模式均有自己独立的物理寄存器R13,在用户应用程序的初始化部分,一般都要初始化每种模式下的R13,使其指向该运行模式的栈空间,这样,当程序的运行进入异常模式时,可以将需要保护的寄存器放入R13所指向的堆栈,而当程序从异常模式返回时,则从对应的堆栈中恢复,采用这种方式可以保证异常发生后程序的正常执行。
4、有四种类型的堆栈:
堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使
用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。
同时,根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(DecendingStack),当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工作方式,ARM 微处理器支持这四种类型的堆栈工作方式,即:◎Full descending 满递减堆栈堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。ARM-Thumb过程调用标准和ARM、Thumb C/C++ 编译器总是使用Full descending 类型堆栈。<这是什么原因呢?>
◎Full ascending 满递增堆栈堆栈首部是低地址,堆栈向高地址增长。栈指针总是指向堆栈最后一个元素(最后一个元素是最后压入的数据)。
◎Empty descending 空递减堆栈堆栈首部是低(这里是不是错了,应该是高地址吧)地址,堆栈向高地址增长。栈指针总是指向下一个将要放入数据的空位置。
◎Empty ascending 空递增堆栈堆栈首部是高地址,堆栈向低地址增长。栈指针总是指向下一个将要放入数据的空位置。
5、操作堆栈的汇编指令堆栈类型入栈指令出栈指令Full descending STMFD (STMDB) LDMFD (LDMIA) Full ascending STMFA (STMIB) LDMFA (LDMDA) Empty descending STMED (STMDA) LDMED (LDMIB) Empty ascending STMEA (STMIA) LDMEA (LDMDB)
例子:STMFD r13!, {r0-r5} ; Push onto a Full Descending Stack LDMFD r13!, {r0-r5} ; Pop from a Full Descending Stack.
例子
1)保护现场参数,不影响PC,嵌汇编的时候对之前的存参数的寄存器R0~R12保存
STMFD r13!, {r0-r7,LR}
LDMFD r13!, {r0-r7,PC}
2) ARM汇编中lr(r14)寄存器的作用
lr(r14)的作用问题,这个lr一般来说有两个作用:
1.当使用bl或者blx跳转到子过程的时候,r14保存了返回地址,可以在调用过程结尾恢复。
2.异常中断发生时,这个异常模式特定的物理R14被设置成该异常模式将要返回的地址。
另外注意pc,在调试的时候显示的是当前指令地址,而用mov lr,pc的时候lr保存的是此指令向后数两条指令的地址,大家可以试一下用mov pc,pc,结果得到的是跳转两条指令,这个原因是由于arm的流水线造成的,预取两条指令的结果.
3.我们看到的LR值是上一个子程序调用保存的子程序返回地址,这个LR是要赋给PC 的。
嵌入式汇编要手动保存返回地址,进行现场保护。
PC记录当前运行的地址。下一条回自己+4
进入子程序,LR才自动更新为返回地址值,PC为程序运行地址
ARM汇编嵌套子程序
几个星期前阅读了(加)Carl Hamacher、Zvonko Vranesic、Safwat Zaky编写的《计算机组成》第五版中的ARM子程序调用的一些知识,启发很大,顺便将它整理了一下并加入了自己的理解。
子程序
1 通过寄存器传递参数
BL指令通常用于调用一个子程序。它和B 指令的区别在于它将返回地址装载到R14中。由于子程序可能是嵌套的,因此LR的内容必须保存在子程序所使用的堆栈中。下面的例子使用寄存器传递参数。调用者通过寄存器R1和R2分别将数组的大小和数组的首地址传递给子程序;子程序利用寄存器R0将和传递给调用者。该子程序使用了寄存器R3,必须将它和LR推入堆栈。
调用程序
LDR R1, N
LDR R2, POINTER
BL LISTADD
STR R0, SUM