也谈栈和栈帧(四)
這次來看看PowerPC體系架構CPU的棧幀布局和操作方法。PowerPC用得不多,有不對的地方大家拍磚啊~~
1.? PowerPC的棧幀
??? 先來看看PowerPC的棧幀布局圖:
????
??? 上圖描述的是PowerPC的棧幀布局方式,PowerPC的棧生長方向也是由高到低,caller是調用者,current是被調用者。壓棧的順序依次是FPR、GPR、CR、Local Variable、Function Parameters、Padding、LR和Back Chain Word。具體涵義如下:
? (1)函數參數域FPR(Function Parameter Register):這個區域的大小是變化的,當調用者傳遞給被調用者的參數少于8個時,用GPR3-GPR10這8個寄存器就行,被調用者的棧幀中就可不要這個區域;但如果傳遞的參數多于8個時就需要這個區域。
? (2)通用寄存器GPR(General Parameter Register):當需要保存GPR寄存器中的一個寄存器GPRx時,就需要把從GPRx-GPR31的值都保存到堆棧幀中。
? (3)CR寄存器:即使修改了CR寄存器的某一個段CRx(x=0至7),都要保存這個CR寄存器的內容。
? (4)局部變量域(Local Variables Area):同上FPR所示,如果臨時寄存器的數量不足以提供給被調用者的臨時變量使用時,就會使用這個區域。
? (5)Function Parameters:跟第一個FPR重復了?暫時不知。
? (6)Padding:是補齊字節數,讓當前棧幀的長度保持8Bytes的倍數。
? (7)LR:也就是ra寄存器,是指返回時的函數指針。
? (8)Back Chain Word:是調用者函數幀的棧頂esp,即上一個棧幀的低地址,當前函數棧幀的基址ebp。
??? 跟x86和ARM一樣,壓棧的順序有一定的規律,一個??臻g內的地址前面,必然有一個代碼地址明確標示著調用函數位置內的某個地址。而且很容易發現,跟x86一樣(如果x86中ebp算是調用者棧幀的話),棧幀的最后兩個位置存儲的也是ra和ebp。所以可以考慮向x86學習,根據當前ebp的值回溯出整個任務的調用棧,如圖中藍箭頭所示,具體操作后面再專門講述。 ? 2.? PowerPC的寄存器
??? PowerPC的ABI規定的寄存器的使用規則如下:
? (1)GPR0:屬于易失性寄存器,ABI規定普通用戶不能使用此寄存器。GCC編譯器用此寄存器來保存LR寄存器,Linux PowerPC用此寄存器來傳遞系統調用號碼。
? (2)GPR1:屬于專用寄存器,ABI規定用次寄存器來保存堆棧的棧頂指針。注:PowerPC構架沒有獨立的棧頂指針,這一點和X86體系結構是不同的!
? (3)GPR2:屬于專用寄存器,ABI規定普通用戶不使用才寄存器,Linux PowerPC用此寄存器來保存當前進程的進程描述符地址。
? (4)GPR3-GPR4:屬于易失性寄存器,ABI使用這兩個寄存器來保存函數的返回值,或者用來傳遞參數。
? (5)GPR5-GPR10:也屬于易失性寄存器,加上GPR3和GPR4共8個寄存器用來傳遞函數的參數。當函數的參數超過八個時使用堆棧來傳遞。
? (6)GPR11-GPR12:屬于易失性寄存器,ABI規定普通用戶不使用該寄存器,Linux PowerPC有時用這兩個寄存器來存放臨時變量,但是GCC編譯器沒有使用這兩個寄存器。
? (7)GPR13:屬于專用寄存器,ABI規定該寄存器sdata段的基地址指針。Linux PowerPC在系統初始化時使用該寄存器來存放臨時變量。GCC有時會根據某些規則將一些常用的數據放入sdata或者sbss段中。應用程序對sdata或者sbss段數據的訪問與對data和bss段數據的訪問機制不同,訪問sdata段的數據速度更快。
? (8)GPR14-GPR31:屬于非易失性寄存器。ABI使用這些寄存器來存放一些臨時變量,在應用程序中可以自由使用這些變量。 ? 3.? PowerPC的匯編指令和棧操作
??? PowerPC寄存器沒有專用的push和pop指令來執行堆棧操作,所以PowerPC構架使用存儲器訪問指令stwu、lwzu來代替push和pop指令。
??? 下面我們通過一個例子來說明堆棧幀的建立、使用和移除過程:
??? func1中開始幾行匯編會為自己建立棧幀:
func1:??? mflr %r0??????????????? ;Get link register
????????? stwu %r1,-88(%r1)?????? ;Save back chain?then move?sp
????????? stw %r0,+92(%r1)??????? ;Save link register
????????? stmw %r28,+72(%r1)????? ;Save 4 non-volatiles r28-r31
??? func1的結尾幾行,會移除前面建立的棧幀,并使得SP(即GPR1)寄存器指向上一個棧幀的棧頂(即棧幀的最低地址處,也就是back chair)
??? 如下所示:
????????? lwz %r0,+92(%r1)?????? ;Get saved link register
????????? mtlr %r0?????????????? ;Restore link register
????????? lmw %r28,+72(%r1)????? ;Restore non-volatiles
????????? addi %r1,%r1,88??????? ;Remove frame from stack
????????? blr??????????????????? ;Return to caller function
1.? PowerPC的棧幀
??? 先來看看PowerPC的棧幀布局圖:
????
??? 上圖描述的是PowerPC的棧幀布局方式,PowerPC的棧生長方向也是由高到低,caller是調用者,current是被調用者。壓棧的順序依次是FPR、GPR、CR、Local Variable、Function Parameters、Padding、LR和Back Chain Word。具體涵義如下:
? (1)函數參數域FPR(Function Parameter Register):這個區域的大小是變化的,當調用者傳遞給被調用者的參數少于8個時,用GPR3-GPR10這8個寄存器就行,被調用者的棧幀中就可不要這個區域;但如果傳遞的參數多于8個時就需要這個區域。
? (2)通用寄存器GPR(General Parameter Register):當需要保存GPR寄存器中的一個寄存器GPRx時,就需要把從GPRx-GPR31的值都保存到堆棧幀中。
? (3)CR寄存器:即使修改了CR寄存器的某一個段CRx(x=0至7),都要保存這個CR寄存器的內容。
? (4)局部變量域(Local Variables Area):同上FPR所示,如果臨時寄存器的數量不足以提供給被調用者的臨時變量使用時,就會使用這個區域。
? (5)Function Parameters:跟第一個FPR重復了?暫時不知。
? (6)Padding:是補齊字節數,讓當前棧幀的長度保持8Bytes的倍數。
? (7)LR:也就是ra寄存器,是指返回時的函數指針。
? (8)Back Chain Word:是調用者函數幀的棧頂esp,即上一個棧幀的低地址,當前函數棧幀的基址ebp。
??? 跟x86和ARM一樣,壓棧的順序有一定的規律,一個??臻g內的地址前面,必然有一個代碼地址明確標示著調用函數位置內的某個地址。而且很容易發現,跟x86一樣(如果x86中ebp算是調用者棧幀的話),棧幀的最后兩個位置存儲的也是ra和ebp。所以可以考慮向x86學習,根據當前ebp的值回溯出整個任務的調用棧,如圖中藍箭頭所示,具體操作后面再專門講述。 ? 2.? PowerPC的寄存器
??? PowerPC的ABI規定的寄存器的使用規則如下:
? (1)GPR0:屬于易失性寄存器,ABI規定普通用戶不能使用此寄存器。GCC編譯器用此寄存器來保存LR寄存器,Linux PowerPC用此寄存器來傳遞系統調用號碼。
? (2)GPR1:屬于專用寄存器,ABI規定用次寄存器來保存堆棧的棧頂指針。注:PowerPC構架沒有獨立的棧頂指針,這一點和X86體系結構是不同的!
? (3)GPR2:屬于專用寄存器,ABI規定普通用戶不使用才寄存器,Linux PowerPC用此寄存器來保存當前進程的進程描述符地址。
? (4)GPR3-GPR4:屬于易失性寄存器,ABI使用這兩個寄存器來保存函數的返回值,或者用來傳遞參數。
? (5)GPR5-GPR10:也屬于易失性寄存器,加上GPR3和GPR4共8個寄存器用來傳遞函數的參數。當函數的參數超過八個時使用堆棧來傳遞。
? (6)GPR11-GPR12:屬于易失性寄存器,ABI規定普通用戶不使用該寄存器,Linux PowerPC有時用這兩個寄存器來存放臨時變量,但是GCC編譯器沒有使用這兩個寄存器。
? (7)GPR13:屬于專用寄存器,ABI規定該寄存器sdata段的基地址指針。Linux PowerPC在系統初始化時使用該寄存器來存放臨時變量。GCC有時會根據某些規則將一些常用的數據放入sdata或者sbss段中。應用程序對sdata或者sbss段數據的訪問與對data和bss段數據的訪問機制不同,訪問sdata段的數據速度更快。
? (8)GPR14-GPR31:屬于非易失性寄存器。ABI使用這些寄存器來存放一些臨時變量,在應用程序中可以自由使用這些變量。 ? 3.? PowerPC的匯編指令和棧操作
??? PowerPC寄存器沒有專用的push和pop指令來執行堆棧操作,所以PowerPC構架使用存儲器訪問指令stwu、lwzu來代替push和pop指令。
??? 下面我們通過一個例子來說明堆棧幀的建立、使用和移除過程:
??? func1中開始幾行匯編會為自己建立棧幀:
func1:??? mflr %r0??????????????? ;Get link register
????????? stwu %r1,-88(%r1)?????? ;Save back chain?then move?sp
????????? stw %r0,+92(%r1)??????? ;Save link register
????????? stmw %r28,+72(%r1)????? ;Save 4 non-volatiles r28-r31
??? func1的結尾幾行,會移除前面建立的棧幀,并使得SP(即GPR1)寄存器指向上一個棧幀的棧頂(即棧幀的最低地址處,也就是back chair)
??? 如下所示:
????????? lwz %r0,+92(%r1)?????? ;Get saved link register
????????? mtlr %r0?????????????? ;Restore link register
????????? lmw %r28,+72(%r1)????? ;Restore non-volatiles
????????? addi %r1,%r1,88??????? ;Remove frame from stack
????????? blr??????????????????? ;Return to caller function
總結
- 上一篇: 也谈栈和栈帧(三)
- 下一篇: 前松后紧和前紧后松——想起PM的点滴