原來看第3.2.3節的時候,感覺很難的。爲什麼會感覺難呢? 因爲這一節談到的特權級別關係比較複雜,不容易弄清楚。這次重看一次這一節後,進行了一點小結,這才感覺比較清楚了。
這一節的主要內容可以用下面這個表格來描述。
目標代碼段 |
Jmp指令 |
Call指令 |
|
直接調用 |
通過調用門 |
||
一致碼段 |
CPL>=DPL,不檢查RPL 可以跳轉到相同或者更高特權級別執行 |
CPL<=DPL_G,RPL<=DPL_G CPL>=DPL 訪問調用門的規則同訪問數據段,即調用門只能被特權級別不低於其DPL(DPL_G)的代碼訪問。可以跳轉到相同或者更高特權級別執行。 |
|
非一致碼段 |
RPL<=CPL=DPL 只能跳轉到同特權級別的代碼段 |
1. 三種特權級別
CPL:當前特權級別。當前正在運行的代碼所處的特權級別,保存在CS和SS的低2位中。
DPL:描述符特權級別,即段描述符中DPL字段的值,是與描述符相關的特權級別。
RPL:請求特權級別,即用於訪問代碼、數據或者堆棧的段選擇子低2位的值。
注意特權級別的表示:有0至3這4個特權級別,0級最高,3級最低,即數字大則特權級別低。表中CPL、RPL、DPL等都是代表數字的。
2. 一致碼段和非一致碼段
(1)一致碼段:無論採用哪種方式跳轉到一致碼段,CPL都不改變(不變化爲目標代碼段的DPL),也即在加載目標代碼段選擇子時,只加載高14位,表示CPL的低2位保持不變。
(2)非一致碼段:無論採用哪種方式跳轉到非一致碼段,CPL都發生改變,也即在加載目標代碼段選擇子時,將整個選擇子放入到CS中。
“一致”的意思就是:代碼段被調用執行時不使用自己的描述符的DPL,而採用調用者特權級別,CS的低2位保持不變,與調用者特權級別保持一致。
是不是一致碼段由描述符中的相應位標誌確定(參看47到49頁的表格)。
3. Jmp與Call
Jmp指令僅僅進行執行流程的跳轉,不會保存返回地址。
Call指令在進行流程跳轉前會保存返回地址,以便在跳轉目標代碼中可以使用ret指令返回到call指令的下一條指令處繼續執行。執行段內跳轉時,只保存EIP;如果是段間跳轉,還保存CS。
對於使用Call指令(無論是直接調用還是通過調用門)進行的跳轉,如果跳轉後特權級別將發生改變(總是從低到高,從上述第2點知道,只有跳轉到非一致碼段時纔會發生特權級別變化),則執行call指令前必須準備好任務狀態段TSS。跳轉過程是:(1)保存調用者的SS和ESP到被調用者堆棧中(2)調用參數先保存在調用者堆棧中,然後被複制到被調用者堆棧中(3)當前CS和EIP被保存到被調用者堆棧中。在通過call進行的有特權級別變化的跳轉中,堆棧會發生切換,這時要保存當前堆棧指針(SS:ESP),而當前指令指針(CS:EIP)保存到新的堆棧(被調用者堆棧)中,這是與沒有特權級別變化的跳轉不同的。沒有特權級別變化時,不需要保存SS:ESP,不存在調用參數的複製,不存在堆棧切換。
4. ret和retf
這兩個指令的功能都是調用返回。
(1) ret在返回時只從堆棧中取得EIP;retf中的字母f表示far,即段間轉移返回,要從堆棧中取得EIP和CS。
(2)兩個指令都可以帶參數,表示發生過程調用時參數的個數,返回時需要從堆棧中退出相應個數的參數
(3)恢復CS時,如果發現將發生特權級別變化(當前CS的低2位不等於從堆棧中取得的新的CS值的低2位。從上述第2點知道,只有跳轉到非一致碼段時纔會發生特權級別變化,那麼,也只有從非一致碼段返回時纔會發生特權級別返回),則還要從調用者堆棧中取得ESP和SS恢復到相應寄存器中,也即恢復調用者堆棧。
5. 任務狀態段TSS
爲避免相互干擾,要求不同特權級別的代碼運行時使用不同的堆棧,也就是在特權級別發生改變時必須切換堆棧段。0、1、2特權級別的堆棧指針保存在TSS中,在跳轉到相應級別時從TSS中取出相應的堆棧指針進行堆棧切換。因爲只有從低特權級別跳轉到高特權級別時才需要從TSS中取得新的堆棧指針,所以TSS中不存在最低特權級別3的堆棧指針。
綜上所述,所有的複雜只有一點:僅僅在通過調用門從低特權級別跳轉到高特權級別的非一致碼段時,纔會發生CPL改變,才需要先準備好TSS,纔會發生堆棧切換(在調用前從TSS中取得新的堆棧指針;調用返回時從被調用者堆棧中取得原堆棧指針進行恢復)。
CPL、RPL、DPL的區別
CPL(Current Privilege Level) 當前(代碼)特權級。在保護模式下,CS寄存器、SS寄存器中分別存放着代碼段、堆棧段的選擇子。CPL在CS、SS的第0、1位(第0位到15位)中。CPL一般情下等於所裝載的段的特權級。對於一致代碼段來說,CPL不會隨着所裝載的段的特權級而改變。
DPL(Descriptor Privilege Level) 描述符特權級,在每個存儲段(數據段、代碼段、堆棧段)描述符、門(調用門、任務門、中斷門、陷阱門)描述符、任務狀態段(TSS)描述符的第5個字節(第0字節到第7字節)的第5、6位(第0位到第7位)中。DPL主要用來與CPL比較,來確定當前代碼是否能夠訪問相應的段。
RPL(Request Privilege Level) 選擇子特權級,在每個選擇子的第0、1位(第0位到15位)中。RPL主要用來改寫CPL,當進行段訪問的時候,取CPL和RPL中數值大的一個(即取權限小的一個)。如:CPL爲0,要訪問的調用門DPL爲2,但是選擇子的RPL爲3,此時不可以訪問調用門。