《Orange’s 一個操作系統的實現》3.保護模式7-特權級轉移(通過調用門轉移目標段-有特權級轉換-理論)
A.關於堆棧
jmp指令:不影響堆棧
call指令:影響堆棧,對於短調用來說,call指令執行時會將下一條指令的eip壓棧,到ret指令時,這個eip會被從堆棧中彈出。
對於長轉移;還會將cs壓棧
B.call指令堆棧示意圖
假設函數foo(param1,param2,param3)
1.短調用時堆棧示意圖
2.短調用返回時堆棧示意圖
3.長調用時堆棧示意圖
4.長調用返回時堆棧示意圖(通過帶參數的ret指令)
5.有特權級變換的轉移及返回時的堆棧變化
轉移時示意圖
返回時示意圖
由於堆棧可能會發生變化,所以intel提供了將堆棧A的諸多內容複製到堆棧b中。這裏我們只涉及到連個堆棧,而事實上,由於每個任務
最多在都可能在4個特權級之間轉移,所以每個任務實際上需要4個堆棧。原有的ss和一個esp就不能滿足我們的需要,這是就要使用到
TSS(Task-State Stack),一個數據結構,包含多個字段
6.32位TSS結構如下
TSS字段偏移4到27的3個ss和3個esp,當發生堆棧切換時,內層的ss和esp就是從TSS裏面取得.
C.轉移過程概述
call過程(低特權->高特權)
1.根據目標代碼段的DPL(新的CPL)從TSS中選擇應該切換至哪個ss和esp
2.從TSS中取得新的ss和esp.在這個過程中如果發現ss、esp或者TSS界限錯誤都會導致無效TSS異常(#TS)
3.對ss描述符進行檢驗,如果發生錯誤同樣產生#TS異常
4.暫時性地保存當前ss和esp的值
5.加載新的ss和esp
6.將剛剛保存的ss和esp的值壓入堆棧
7.從調用者堆棧中將參數複製到被調用者堆棧(新堆棧)中,複製參數的數目有調用門中Param Count(最多31個參數,大於31可以使用結構指針)
一項來決定。如果Param Count 爲0的話,將不復制參數
8.將當前的cs和eip壓棧
9.加載調用門中指定的新的cs和eip,開始執行被調用的過程
ret過程(高特權->低特權)
1.檢查保存的cs中的RPL以判斷返回時是否要交換特權等級
2.加載被調用者堆棧上的cs和eip(此時會進行代碼段描述符和選擇子類型和特權級檢驗)
3.如果ret指令含有參數,則增加esp的值以跳過參數,然後esp將指向被保存過的ss和esp.注意,ret的參數必須對應調用門中的param count
4.加載ss和esp,切換到調用者堆棧,被調用者的ss和esp被丟棄。這裏會進行你個ss描述符、esp以及ss段描述的檢驗
5.如果ret指令含有參數,增加esp的值以跳過參數(此時已經在調用者堆棧中)
6.檢查ds、es、fs、gs的值,如果其中哪一個寄存器指向的段的DPL小於CPL(此規則不使用與一致代碼段),那麼一個空描述符會被加載到該寄存器