不同特权级间代码段的跳转{ 门 + 跳转(jmp + call) + 返回(ret) }
【0】寫在前面
- 0.1)我們講 CPU的保護機制,它是可靠的多任務運行環境所必須的;
- 0.2) CPU保護機制:分為段級保護 + 頁級保護;
- 0.2.1)段級保護分為:段限長 limit 檢查、段類型 type 檢查、特權級檢查、等等……
- 0.3)我們著重講 段特權級檢查(bit 6~5): 特權級檢查又分為:訪問數據段時的特權級檢查 + 代碼段之間轉移控制時的特權級檢查;(這里,我們著重講 代碼段間轉移控制時的特權級檢查)
- 0.4)版權聲明:本文部分內容圖片總結于李炯的“Linux內核完全剖析“;
【1】進入代碼段間轉移控制時的特權級檢查(引入門的概念)
1.0)使用jmp 或 call 指令可以實現以下4 種轉移:
- 1)目標操作數包含目標代碼段的段選擇子;
- 2)目標操作數指向一個包含目標代碼段選擇子的調用門描述符;
- 3)目標操作數指向一個包含目標代碼段選擇子的TSS;
- 3)目標操作數指向一個任務門, 這個任務門指向一個包含目標代碼段選擇子的TSS;
1.1)直接調用或跳轉到代碼段
(Attention): JMP、CALl 和 RET指令的近轉移只是在當前代碼段中執行程序控制轉移,因此不會執行特權級檢查;JMP、CALL和 RET 指令的遠轉移 會把 控制轉移到 另一個代碼段中,因此處理器會進行特權級檢查;
- 1.1.1)當不通過調用門把程序控制權轉移到另一個代碼段時,處理器會驗證4種特權級和類型信息:
- (驗證?如何驗證? 拿 CPL和 選擇子中的RPL 去和目的段描述符中的DPL 進行比較,驗證)
- 1. 當前特權級 CPL;
- 2. 含有被調用過程的目的代碼段描述符中的描述符特權級 DPL;
- 3. 目的代碼段的段選擇子中的請求特權級 RPL;
- 4. 目的代碼段描述符中的一致性標記 C, 它確定了一個 代碼段是非一致代碼段(C=0)還是 一致代碼段(C=1);
1.1.2)如何驗證?-Validation
- V1)當訪問非一致代碼段(C=0):CPL 必須等于 目標代碼段的DPL, 同時要求 RPL 小于 DPL (即RPL的特權級大于DPL),才能使得轉移成功;
當非一致代碼段的段選擇子 被加載進 CS寄存器中, 特權級字段不會改變,即它仍然是 調用者的CPL; V2)當訪問一致代碼段時(C=1): 調用者的CPL 在數值上大于或等于目的代碼段的 DPL (即DPL 的特權級要比 CPL大), 對于一致代碼段的訪問,處理器忽略對 RPL 的檢查;
當程序控制被轉移到一個 一致代碼段中, CPL并不改變, 即使目的代碼段的DPL在數值上小于CPL;由于 CPL 沒有改變, 因此堆棧也不會發生切換;最后, 大多數代碼段都是非一致代碼段, 對于非一致代碼段, 程序的控制權只能轉移到 具有 相同特權級的代碼段中, 除非轉移時通過一個調用門進行的;
最后(這就是調用門存在的意義所在了,即調用門可以實現不同特權級間的非一致代碼段的跳轉)
1.2)門描述符
1.2.1)為了對具有不同特權級的代碼段提供受控的訪問,處理器提供了稱為門描述符的特殊描述符集,有4種門描述符:
- 1. 調用門(call gate), 類型TYPE=12: 用于在不同特權級間實現受控的程序控制轉移;(訪問調用門要求CPL和RPL,必須小于或等于調用門的DPL)(干貨)
- 2. 陷阱門(trap gate),類型TYPE=15:用于調用異常和中斷的處理程序;
- 3. 中斷門(interrupt gate),類型TYPE=14:用于調用異常和中斷的處理程序;
- 4. 任務門(task gate),類型TYPE=5:用于任務切換;
1.2.2)調用門的功能:
- 1. 指定要訪問的代碼段;
- 2. 在指定代碼段中定義程序的一個入口點;
- 3. 指定訪問過程的調用者需要具備的特權級;
- 4. 若會發生堆棧切換, 它會指定在堆棧間需要復制的可選參數的個數;
5. 指明調用門描述符是否有效;
; 門的定義,緊跟在描述符定義之后 ; 門 目標選擇子,偏移,DCount, 屬性 LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0 ;(8Ch + 00h)
1.3)通過調用門訪問代碼段
1.3.1) 當處理器訪問調用門時, 它會使用調用門中的段選擇符來定位目的代碼段的段描述符。然后, CPU 會把代碼段描述符的基地址與調用門中的偏移地址進行組合,形成代碼段中指定程序入口點的線性地址(這里生成了線性地址,注意要和分頁機制聯系起來,如果開啟分頁機制的話)
SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDTLABEL_CALL_GATE_TEST: GateSelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0 ;(8Ch + 00h)SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT1.3.2)通過調用門進行程序控制轉移時, CPU會對4種 不同特權級進行檢查;
- 1. 當前特權級 CPL;(CS 和 SS 中的 bit1~0)
- 2. 調用門選擇子中的請求特權級RPL;(選擇子數據結構 bit1~0)
- 3. 調用門描述符中的描述符特權級 DPL;(段描述符數據結構,低4字節 bit6~5)
- 4. 目標代碼段描述符的 DPL;(同上)
- 5. 目的代碼段描述符中的一致性標志C 也要檢查;(段描述符數據結構 的 bit10)
(Attention)訪問調用門的條件:(干貨)
為了訪問調用門, 調用者程序的特權級CPL 必須小于或等于 調用門的 DPL, 而且門段選擇子RPL 也必須小于或者等于調用門的DPL;
1.3.3)如何驗證?-Validation(通過call 或 jmp 訪問調用門的特權級檢查)
V1)第一步,是檢查調用者的特權級 與 調用門的特權級 是否符合特權級訪問規則;
V2)如果第一步成功, 則CPU 才會把 調用者的 CPL 與 調用門目的代碼段的DPL特權級進行比較檢查:
- CALL指令):只有 CALL 指令 可以通過調用門把程序控制轉移到特權級更高的非一致性代碼段中,
- JMP指令): JMP指令 只能通過調用門吧控制轉移到 DPL == CPL 的非一致性代碼段中;
- CALL指令 + JMP指令): 這兩條指令都可以把控制轉移到 更高特權級的一致性代碼段中,即轉移到 DPL數值 小于或等于CPL的一致性代碼段中;
1.3.4)轉移之后,CPU都干了什么?
- 1)目標代碼段是更高特權級的非一致性代碼段:如果一個調用吧控制轉移到更高特權級的非一致性代碼段中, 那么CPL 就會設置 成 目的代碼段中的DPL值, 堆棧也會發生切換;
- 2)目標代碼段是更高特權級的一致性代碼段:如果一個調用吧控制轉移到更高特權級的一致性代碼段中, 那么CPL 不會發生改變, 堆棧也不會發生切換;
1.4)調用門的作用
- 1.4.1) 調用門可以讓一個代碼段中的過程 被不同特權級的程序訪問, 例如,位于一個代碼段中的os 代碼可能含有os 自身和 應用軟件都允許訪問的代碼,故 可以為這些代碼設置一個所有特權級代碼都能訪問的調用門;
- 1.4.2)另外,可以專門為僅用于os 的代碼設置一些更高特權級的調用門;
【2】堆棧切換 + 從被調用過程返回
- (如“轉移之后,CPU都干了什么?”模塊中提到: 如果一個調用吧控制轉移到更高特權級的非一致性代碼段中, 那么CPL 就會設置 成 目的代碼段中的DPL值, 堆棧也會發生切換)
2.1)堆棧切換的目的:
- 1)為了防止高特權級程序由于棧空間不足而引起崩潰;
- 2)同時也為了防止低特權級程序通過共享的堆棧有意或無意地干擾高特權級的程序;
2.2)堆棧切換帶來的問題:
- 1)出現的問題: call 指令 執行前后的堆棧已經不再是同一個堆棧 了,那么我們在堆棧A中壓入參數和返回地址, 需要出棧(ret or retf)時,堆棧卻變成了堆棧B, 這該怎么辦呢?
- 2)解決方法: Intel提供一種機制, 將堆棧A的內容復制到 堆棧B中, 如下圖;
2.3)從被調用過程返回:
總結
以上是生活随笔為你收集整理的不同特权级间代码段的跳转{ 门 + 跳转(jmp + call) + 返回(ret) }的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的QQ邮箱怎么没有域名(我的qq邮箱怎
- 下一篇: 从备案到开机要多久(从备案到开机)