微處理器中的棧由棧指針指向存儲器中的棧頂來實現,當數據項入棧時,棧
指針向上移動,當數據項出棧時,棧指針向下移動。
實現棧時需要做出兩個決定:一是當數據項進棧時是向低位地址方向向上生
長(圖a和圖b)還是向高位地址方向向下生長(圖c和圖d),另一個決定是
棧指針時指向當前位置棧頂的數據項(圖a和圖c)還是指向棧頂上的第一個
空白位置(圖b和圖d)
術語TOS表示棧頂(top of stack)指明了棧中的下一個數據項,用棧來保存子程序調用后的返回地址
下圖描述了一個棧指針指向棧頂項的棧。當一個項被進棧,棧指針遞減,當
一個項出棧,棧指針遞增:
用棧指針SP來定義入棧和出棧操作:
注意棧指針按照4個字節遞增或遞減,因為存儲器按照字節編址,棧的數據項長為一個字(4個字節)。
子程序調用和返回
可以通過先將返回地址入棧,然后跳轉到分支目標地址處來實現子程序調用。
該操作在CISC處理器中由JSR target或BSR target指令來實現。ARM沒有實現這
一操作,需通過下述指令來實現:
; 假設棧朝低地址方向生長且SP指向棧的下一個數據項 SUB r13,r13,#4 ; 棧指針先遞減STR r15,[r13] ; 返回地址入棧B Target ; 跳轉到目標地址… ; 在這里返回
一旦執行完子程序中的代碼,就會執行子程序返回指令RTS,且PC將恢復到指令BSR Proc_A被取出來之后的那個點。RTS指令的作用是:
RTS: [PC] <- [[Sp]] ; 把棧中的返回地址復制到PC
[SP] <- [SP] + 4 ; 調整棧指針
棧將向上移動4個字節,因為每個地址都是4個字節。ARM不支持基于棧的子
程序返回機制,則代碼應寫為:
LDR r12,[r13],#+4 ; 取出保存的PC,棧指針后遞增
SUB r15,r12,#4 ; 修正PC并將其加載到r15中以返回
注意:必須修改保存的PC,因為它指向實際返回地址之后4字節的位置(由于
ARM的整數流水線),然后將PC加載到r15,強制從子程序中返回。
盡管上面子程序調用的方法可以工作,但有一個更好的使用ARM塊移動指令的機制:
STMIA sp!,{r6,lr} ; r6與鏈接寄存器入棧
... ; 這里是子程序代碼
LDMDB sp!,{r6,pc} ; r6出棧并取出PC,返回地址出棧,送到PC以返回