3.4 ARM堆棧保護/恢復現場分析
3.4.1 堆棧的分類
根據堆棧的生成方式,又可以分爲遞增堆棧(Ascending Stack)和遞減堆棧(DecendingStack),當堆棧由低地址向高地址生成時,稱爲遞增堆棧,當堆棧由高地址向低地址生成時,稱爲遞減堆棧。這樣就有四種類型的堆棧工作方式,ARM 微處理器支持這四種類型的堆棧工作方式,即:
(1) Full descending 滿遞減堆棧
堆棧首部是高地址,堆棧向低地址增長。棧指針總是指向堆棧最後一個元素(最後一個元素是最後壓入的數據)。
ARM-Thumb過程調用標準和ARM、Thumb C/C++編譯器總是使用Full descending 類型堆棧。
(2) Full ascending 滿遞增堆棧
堆棧首部是低地址,堆棧向高地址增長。棧指針總是指向堆棧最後一個元素(最後一個元素是最後壓入的數據)。
(3) Empty descending 空遞減堆棧
堆棧首部是低地址,堆棧向高地址增長。棧指針總是指向下一個將要放入數據的空位置。
(4) Empty ascending 空遞增堆棧
堆棧首部是高地址,堆棧向低地址增長。棧指針總是指向下一個將要放入數據的空位置。
在ARM中,一般是滿堆棧,堆棧生長方向是從上向下遞減的(51相反爲遞增)。
3.4.2 堆棧保護/恢復現場代碼分析
在寫ARM裸板我們會經常寫如下代碼:
保護現場:
mov ip,sp
stmfdsp!,{fp,ip,lr,pc} 等價於 push {fp, ip, lr, pc}
sub fp,ip,#4
恢復現場
sub sp,fp,#12
ldmfd sp,{fp,sp,pc}
mov ip,sp 將sp棧指針寄存器保存在ip寄存器中,stmfd sp!(fp,ip,lr,pc)將fp ip lr pc依次入棧,這樣注意高編號對應高地址入棧,!表示sp也依次偏移(減),sub fp,ip,#4 ip是入棧前sp指向位置的地址,減4是向低地址偏移4個字節的位置的地址,保存在fp寄存器中,也就是fp保存堆棧的頭部的地址。
sub sp,fp,#12保護現場後sp可能發生變化,通過fp-12可以準確找到保存現場時sp指向的位置保存到sp中,ldmfdsp,{fp,sp,pc},從sp指向的位置出棧,fp保存到fp寄存器中(依然是堆棧的頭部的地址),ip(入棧前sp指向位置的地址)保存到sp中,相當於恢復了sp的值,lr(下下條指令的地址)保存到pc中,然後程序從pc指向的位置執行。圖示分析如下: