ARM的指令系統中關於棧指令的內容比較容易引起迷惑,這是因為準確描述一個棧的特點需要兩個參數: 棧地址的增長方向 :ARM將向高地址增長的棧稱為 遞增棧 (Descendent Stack),將向低地址增長的棧稱為 遞減棧 (Acendant Stack) 棧指針的指向位置 :ARM將棧指針指向棧頂
ARM的指令系統中關於棧指令的內容比較容易引起迷惑,這是因為準確描述一個棧的特點需要兩個參數:
- 棧地址的增長方向:ARM將向高地址增長的棧稱為遞增棧(Descendent Stack),將向低地址增長的棧稱為遞減棧(Acendant Stack)
- 棧指針的指向位置:ARM將棧指針指向棧頂元素位置的棧稱為滿棧(Full Stack),講棧指針指向即將入棧的元素位置的棧稱為空棧(Empty Stack)
1. 棧類型
根據棧地址增長方向雨棧指針指向位置的不同,自然可以將棧分為四類:
遞增棧 | 遞減棧 | |
---|---|---|
空棧 | EA棧 | ED棧 |
滿棧 | FA棧 | FD棧 |
圖1描述了四種不同類型的棧,其中虛線部分表示即將入棧的元素。
圖1 棧類型
2. 棧指令
棧的操作指令無非兩種:入棧和出棧,由於ARM描述了四種不同類型的棧,因此對應的棧指令一共有8條。
入棧 | 出棧 | |
---|---|---|
EA棧 | STMEA | LDMEA |
ED棧 | STMED | LDMED |
FA棧 | STMFA | LDMFA |
FD棧 | STMFD | LDMFD |
這些指令具有相似的首碼:
- STM:(STore Multiple data)表示存儲數據,即入棧。
- LDM:(LoaD Multiple data)表示載入數據,即出棧。
一般情況下,可以將棧操作指令分解為兩步微指令:數據存取和棧指針移動。這兩步操作的先後順序和棧指針的移動方式由棧的類型決定。
第一步 | 第二步 | 等價指令 | |
---|---|---|---|
STMEA | 寫[SP] | SP增加 | STMIA |
LDMEA | SP減少 | 讀[SP] | LDMDB |
STMED | 寫[SP] | SP減少 | STMDA |
LDMED | SP增加 | 讀[SP] | LDMIB |
STMFA | SP增加 | 寫[SP] | STMIB |
LDMFA | 讀[SP] | SP減少 | LDMDA |
STMFD | SP減少 | 寫[SP] | STMDB |
LDMFD | 讀[SP] | SP增加 | LDMIA |
ARM中存在一組緩衝區操作指令和棧指令是一一對應的,他們完成相同的功能。這些指令含義的區別來源於對存取操作的緩衝區指針地址增長方向,以及存取操作和緩衝區指針移動的先後順序決定的。這個和前面描述的棧類型的分類原則十分相似。
指針遞增(Increase) | 指針遞減(Decrease) | |
---|---|---|
存取前移動指針(Before) | IB | DB |
存取後移動指針(After) | IA | DA |
3. 使用舉例
雖然ARM的棧類型和相關的操作指令比較繁瑣,但是實際上最常用的還是和x86指令集相同的棧類型:棧向低地址方向增長,且棧指針指向棧頂元素的位置,即ARM的FD棧。因此最常見的ARM棧指令操作是STMFD和LDMFD。
x86 | ARM | |
---|---|---|
入棧 | PUSH | STMFD/STMDB |
出棧 | POP | LDMFD/LDMIA |
例如入棧指令:
STMFD SP,{R0-R3}
實際的微指令操作為:
[SP-4] <= R3
[SP-8] <= R2
[SP-12] <= R1
[SP-16] <= R0
在ARM的指令系統中,遞減棧入棧操作的參數入棧順序是從右到左依次入棧,而參數的出棧順序則是從左到右的逆操作。對於遞增棧,相應的操作則全部取反。
例如出棧指令:
LDMFD SP,{R4-R7}
實際的微指令操作為:
[SP] => R4
[SP+4] => R5
[SP+8] => R6
[SP+12] => R7
上述的入棧和出棧指令其實僅僅對棧做了存取操作,並未真正改變SP指針的值。正常情況下,我們希望對棧操作後能自動修改棧指針SP的值,使用如下指令可以達到該目的。
STMFD SP!,{R0-R3}
對應的微指令操作為:
[SP-4] <= R3
[SP-8] <= R2
[SP-12] <= R1
[SP-16] <= R0
SP = SP - 16
同樣的:
LDMFD SP!,{R4-R7}
對應的微指令操作為:
[SP] => R4
[SP+4] => R5
[SP+8] => R6
[SP+12] => R7
SP = SP + 16
希望通過本文對你理解ARM的棧指令有所幫助。