|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
一、定义:栈(Stack)是限定仅在一端进行插入或删除操作的线性表。% T" T9 r' L- k, V% u
因此,对栈来说,可以进行插入或删除操作的一端端称为栈顶(top),相应地,另一端称为栈底(bottom)。不含元素的空表称为空栈。由于堆栈只允许在一端进行操作,因而按照后进先出(LIFO-Last In First Out)的原理运作。从栈顶的定义来看,栈顶的位置是可变的。空栈时,栈顶和栈底重合;满栈时,栈顶离栈底最远。ARM为堆栈提供了硬件支持,它使用一个专门的寄存器(堆栈指针)指向堆栈的栈顶。而且7种模式都有各自独立的堆栈指针,也就是有各自独立的堆栈空间。
* n5 E! P+ L# @* S8 r二、如何描述一个栈$ A7 [$ s4 W/ [" W& G z: {
准确描述一个栈的特点需要两个参数
" j' X+ N# _6 _8 ?* d$ \! t6 p* Y栈地址的增长方向:ARM将向高地址增长(也叫做向上增长)的栈称为递增栈(ascendant Stack),将向低地址增长(也叫做向下增长)的栈称为递减栈(descendantStack)
. D& K0 P( I4 o4 X7 \5 P栈指针的指向位置:ARM将栈指针指向栈顶元素位置的栈称为满栈(Full Stack),讲栈指针指向即将入栈的元素位置的栈称为空栈(Empty Stack)% N1 D- }+ s9 n6 Y' p% a ~2 N
根据栈地址增长方向雨栈指针指向位置的不同,自然可以将栈分为四类:
2 M" M5 t" s4 M+ k3 w! H% R% A! e: M/ @) z- m) \0 T: k
下图描述了四种不同类型的栈,其中虚线部分表示即将入栈的元素。 l$ E% n# D) l3 f, L) B
9 F% K7 \/ k' B; Q) K. m
三、栈指令
2 S$ X- G; v. l5 L: r栈的操作指令无非两种:入栈和出栈,由于ARM描述了四种不同类型的栈,因此对应的栈指令一共有8条。 , E' G! \8 Z& H- |/ v; Q
STM:(STore Multiple data)表示存储数据,即入栈。; h8 r: \& N1 w& W# X
LDM:(LoaD Multiple data)表示加载数据,即出栈。
/ F# j" z3 L: b- c9 F. O1 G/ j一般情况下,可以将栈操作指令分解为两步微指令:数据存取和栈指针移动。这两步操作的先后顺序和栈指针的移动方式由栈的类型决定。
8 G; l) h/ }: Q/ O7 N
9 W! @8 z o2 Z8 O" BARM中存在一组缓冲区操作指令和栈指令是一一对应的,他们完成相同的功能。这些指令含义的区别来源于对存取操作的缓冲区指针地址增长方向,以及存取操作和缓冲区指针移动的先后顺序决定的。这个和前面描述的栈类型的分类原则十分相似。- i: y; M; y5 S' W8 @7 G
, R" z( I5 r" T* x. H; c$ K
四、实例" L A- X/ o4 B) q" k4 Z
虽然ARM的栈类型和相关的操作指令比较繁琐,但是实际上最常用的还是和x86指令集相同的栈类型:栈向低地址方向增长,且栈指针指向栈顶元素的位置,即ARM的FD栈。因此最常见的ARM栈指令操作是STMFD和LDMFD。
2 f1 |7 m- [5 V* U! G Q7 \( }例如入栈指令:3 i2 B* Z V; W
STMFD SP,{R0-R3}& g) _' N8 [5 B
实际的微指令操作为:; J: l5 Q4 H; }, n, W# y* l. u% n
[SP-4] <= R3# [* x2 x* S8 Q: T2 r+ v
[SP-8] <= R2
% X, k0 J+ {+ e) x. K$ B- o6 W[SP-12] <= R1
0 t, \) ]1 Z: L3 O }9 |[SP-16] <= R08 C4 R; ~9 a! A0 U+ h" @+ h
在ARM的指令系统中,递减栈入栈操作的参数入栈顺序是从右到左依次入栈,而参数的出栈顺序则是从左到右的逆操作。对于递增栈,相应的操作则全部取反。
, {& b- i) u) R, M( K" x例如出栈指令:. E( G0 J$ N; O; h( F/ N2 {' B- H$ M6 s0 D
LDMFD SP,{R4-R7}
# j0 Y2 J' E1 P' b j实际的微指令操作为:
; m! R# h8 s' C[SP] => R4% S- f/ \# a. n' X: l) X" j" K0 ]
[SP+4] => R59 P% C$ F# S" B/ ^% i
[SP+8] => R6
7 K( B; K" T6 {; _1 Y) V- i[SP+12] => R7
( t. E( f) L4 ^. O7 }上述的入栈和出栈指令其实仅仅对栈做了存取操作,并未真正改变SP指针的值。正常情况下,我们希望对栈操作后能自动修改栈指针SP的值,使用如下指令可以达到该目的。; U7 q q# ?# |# A3 s2 ^
STMFD SP!,{R0-R3}' E" g, w3 I& x* Y) u. K
对应的微指令操作为:
1 s/ p. J% _' s8 q ][SP-4] <= R3/ C) G1 a2 |+ b. V0 i" U0 c) }
[SP-8] <= R2
9 E! L# p( R0 p8 g$ b[SP-12] <= R1: K- ^' p, V" Z8 t
[SP-16] <= R0/ _6 d* `5 ?+ U1 U$ ~! A
SP = SP - 16* z4 k; Q, N: R3 F5 p
同样的:
' q/ u W8 [/ l) _) \" SLDMFD SP!,{R4-R7}
% O% K$ j, q5 V8 v: H对应的微指令操作为:% [1 ^0 v/ a. F% J
[SP] => R46 G# J5 R& F J; t$ s
[SP+4] => R5
* R9 C- Z8 L! s& M! X" m2 _* }6 v! v[SP+8] => R6
, ~ t6 o$ z2 [' `$ C[SP+12] => R74 s( g5 M/ v! y3 R$ ~# t0 @' Y5 m
SP = SP + 16
: z8 r& {6 q4 Q
3 Y- r x6 [0 f# X% ^+ p1 O# L- s* q0 U. A0 ^( s- [; [: m
|
|