|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
一、定义:栈(Stack)是限定仅在一端进行插入或删除操作的线性表。1 A# m( W& y+ a }
因此,对栈来说,可以进行插入或删除操作的一端端称为栈顶(top),相应地,另一端称为栈底(bottom)。不含元素的空表称为空栈。由于堆栈只允许在一端进行操作,因而按照后进先出(LIFO-Last In First Out)的原理运作。从栈顶的定义来看,栈顶的位置是可变的。空栈时,栈顶和栈底重合;满栈时,栈顶离栈底最远。ARM为堆栈提供了硬件支持,它使用一个专门的寄存器(堆栈指针)指向堆栈的栈顶。而且7种模式都有各自独立的堆栈指针,也就是有各自独立的堆栈空间。: J7 Z( W' K7 E' N9 e
二、如何描述一个栈" e9 g- R, s; [) Y; m
准确描述一个栈的特点需要两个参数$ \4 L0 T/ g; Z9 ?( a; D1 t- `; S
栈地址的增长方向:ARM将向高地址增长(也叫做向上增长)的栈称为递增栈(ascendant Stack),将向低地址增长(也叫做向下增长)的栈称为递减栈(descendantStack)
& D+ z1 U. n }栈指针的指向位置:ARM将栈指针指向栈顶元素位置的栈称为满栈(Full Stack),讲栈指针指向即将入栈的元素位置的栈称为空栈(Empty Stack)
0 r8 u: A& c# ^4 h& q根据栈地址增长方向雨栈指针指向位置的不同,自然可以将栈分为四类:. B# y" K/ g, b
0 b1 _: N$ y4 X; A8 ^: U; A. ~7 Y: w
下图描述了四种不同类型的栈,其中虚线部分表示即将入栈的元素。
j0 F) I* O- P j7 e
2 A- |5 s0 R; N& ~+ b, H( s
三、栈指令
* U% z T# b3 v* X& N栈的操作指令无非两种:入栈和出栈,由于ARM描述了四种不同类型的栈,因此对应的栈指令一共有8条。 : P% K- O6 S/ g* E, q
STM:(STore Multiple data)表示存储数据,即入栈。
; d5 o- h8 S( tLDM:(LoaD Multiple data)表示加载数据,即出栈。
! w6 ~# P+ L( E一般情况下,可以将栈操作指令分解为两步微指令:数据存取和栈指针移动。这两步操作的先后顺序和栈指针的移动方式由栈的类型决定。
, D2 Y% D* L. P* a
4 x8 u* K" d& A* F& CARM中存在一组缓冲区操作指令和栈指令是一一对应的,他们完成相同的功能。这些指令含义的区别来源于对存取操作的缓冲区指针地址增长方向,以及存取操作和缓冲区指针移动的先后顺序决定的。这个和前面描述的栈类型的分类原则十分相似。5 K( x3 H. R4 U8 a" b8 P
% `* ], r8 j& \) k2 }$ S# ^$ K* i' q四、实例& s% K9 S! U* k. u( O
虽然ARM的栈类型和相关的操作指令比较繁琐,但是实际上最常用的还是和x86指令集相同的栈类型:栈向低地址方向增长,且栈指针指向栈顶元素的位置,即ARM的FD栈。因此最常见的ARM栈指令操作是STMFD和LDMFD。3 B5 Y: G1 v. |1 l/ {4 m
例如入栈指令:
4 l9 P, o0 E! DSTMFD SP,{R0-R3}7 W8 y, o4 {+ {' H
实际的微指令操作为:
, z4 M9 @1 P/ ~) R8 G1 e7 L& Y[SP-4] <= R3( S! y( o) x, m
[SP-8] <= R2" P+ w+ T( K* x8 P2 D6 X5 s' G! P+ \
[SP-12] <= R1. R$ O1 a. X0 Y4 O% I; v3 G8 K% p
[SP-16] <= R08 |: Z% E B2 c. ^& ]# o1 P
在ARM的指令系统中,递减栈入栈操作的参数入栈顺序是从右到左依次入栈,而参数的出栈顺序则是从左到右的逆操作。对于递增栈,相应的操作则全部取反。 7 P {2 k- [9 E" Z5 o
例如出栈指令:7 s0 B, l; c9 Q3 i
LDMFD SP,{R4-R7}! t3 U3 P2 N) z( {2 J5 h8 e5 E
实际的微指令操作为:: j8 t$ X( ]7 r
[SP] => R4
5 y$ y1 K/ j7 J9 F6 @[SP+4] => R5" M; i3 c2 ?: k2 |4 ]
[SP+8] => R65 ?" t7 e1 o i$ r
[SP+12] => R7
! U6 v& n1 s7 \2 e上述的入栈和出栈指令其实仅仅对栈做了存取操作,并未真正改变SP指针的值。正常情况下,我们希望对栈操作后能自动修改栈指针SP的值,使用如下指令可以达到该目的。* T, Q$ r' s: Q2 N6 o3 o
STMFD SP!,{R0-R3}
; i% e3 }' ~4 X/ @对应的微指令操作为:
% z( ?8 l$ V; t9 x/ S. X[SP-4] <= R31 q! a# l3 I5 N4 Q7 t
[SP-8] <= R2. w( `" L& f2 E
[SP-12] <= R1
* T" l7 P4 v5 s1 Q2 e: H[SP-16] <= R0! v g8 B$ c+ t# E# v& E
SP = SP - 167 Q8 S9 {* Q3 h0 P
同样的:
& d0 ~1 w7 V. I* d% ^4 f. GLDMFD SP!,{R4-R7}) a& l$ j2 s F( N- e2 R9 r
对应的微指令操作为:1 z2 G; x% z, u' U6 @
[SP] => R42 V/ S. T* R/ D! ~: K) ~5 c
[SP+4] => R55 ^/ S: N/ X. k3 s# k+ }, F9 \
[SP+8] => R6
2 q; K* q: T* _ D, ~4 i* u4 o[SP+12] => R7
* G1 w5 }! U5 N. ~+ Y! a" \& P- iSP = SP + 16& N- k1 y& L; B$ s6 M" J; K5 H( ^3 y
# q5 S4 @$ z0 ?' G1 {7 }, s
1 ?& B1 f$ f& A6 W& p* y |
|