關鍵詞: arm堆棧操作,堆棧嚴格來說應該叫做棧,棧(stack)是限定僅在一端進行插入或刪除操作的線性表。因此,對棧來說,可以進行插入或刪除操作的一端稱為棧頂(top),相應地,另一端稱為棧底(bottom)。不含元素的空表稱為空棧。由于堆棧只允許一端進行操作,因而按照后進先出(LIFO-last in first out)的原理運作。
- 根據堆棧指針指向位置的不同,堆棧可分為兩種:滿棧和空棧。
- 滿棧(full):當堆棧指針指向棧頂元素 ,即指向 最后一個入棧的元素時,稱為滿棧;
- 空棧(empty):當堆棧指針指向與棧頂元素相鄰的一個可用數據單元時,稱為空棧。
- 根據數據棧增長方向的不同也可分為遞增堆棧和遞減堆棧2種。
- 遞減堆棧(descending):數據棧向內存地址減小的方向增長;
- 遞增堆棧(ascending):數據棧向內存地址增加的方向增長。
綜合這兩種特點則可有以下4種規則:
縮寫 | 名稱 | 指令 | 含義 |
---|---|---|---|
FD | 滿遞減 | stmfd/ldmfd | 堆棧通過減小存儲器的地址向下增長,堆棧指針指向內含有效數據項的最低地址 |
ED | 空遞減 | stmed/ldmed | 堆棧通過減小存儲器的地址向下增長,堆棧指針指向堆棧下的第一個空位置 |
FA | 滿遞增 | stmfa/ldmfa | 堆棧通過增大存儲器的地址向上增長,堆棧指針指向內含有效數據項的最高地址 |
EA | 空遞增 | stmea/ldmea | 堆棧通過增大村吃器的地址向上增長,堆棧指針指向堆棧上的第一個空位置 |
有一點是需要注意的,雖然ARM處理器核對于兩種生長方式的堆棧均支持,但ads的C語言編程只支持一種方式,即從上往下生長,并且必須是滿遞減堆棧。所以stmfd等指令用的最多。
ARMv7 cortex-A9架構下,APCS規定數據棧為滿遞減的。
ARM對于堆棧的操作一般采用ldmfd(pop)和stmfd(push)兩個命令,以前困惑的是stmfd對于操作數是按照什么順序壓棧的,比如:stmfd sp! {r0-r5, lr} 的進棧順序是:
a.
高地址
lr
r5
r4
……
r0 <--sp
低地址
b.
高地址
r0
r1
r2
……
lr <--sp
低地址
現在通過下表就可以輕松解決這個問題:
尋址方式 | 說明 | pop | =ldm | push | =stm |
---|---|---|---|---|---|
fa | 滿遞增 | ldmfa | ldmda | stmfa | stmib |
fd | 滿遞減 | ldmfd | ldmia | stmfd | stmdb |
ea | 空遞增 | ldmea | ldmdb | stmea | stmia |
ed | 空遞減 | ldmed | ldmib | stmed | stmda |
說明:
a : after(后偏移指針)
b : before(先偏移指針)
i : increase(遞增 )
d : decrease(遞減)
根據圖表,可知stmfd對應的是stmdb,根據arm指令手冊,可知stmdb入棧順序是方式a,而 ldmfd對應的是ldmia,這樣這兩個操作就可以成功配對。
- 相關名詞:
數據棧指針: 最后一個寫入棧的數據的內存地址;
數據棧的基地址: 數據棧的最高地址,由于APCS中的數據棧是FD類型的,多以最早入棧的數據所占的內存單元的基地址的下一個內存單元。
數據棧界限: 數據棧中可使用的最低的內存單元地址;
已用的數據棧: 數據棧的基地址和數據棧的棧指針之間內存區域,包括棧指針對應的內存單元,但不包括基地址對應的內存單元。