代码段间转移控制时的特权级检查(JMP/CALL)——《x86汇编语言:从实模式到保护模式》读书笔记28
代碼段間轉移控制時的特權級檢查(JMP或者CALL指令)
在保護模式下,JMP或CALL指令可以用以下四種方法之一來引用另外一個代碼段: 
 1. 目標操作數含有目標代碼段的段選擇子和偏移 
 2. 目標操作數指向一個調用門描述符 
 3. 目標操作數指向一個TSS 
 4. 目標操作數指向一個任務門
后兩種涉及任務的切換。本文僅對前兩種進行討論。
1. 直接調用或跳轉到另一個代碼段
JMP、CALL、RET指令的近轉移只是在當前代碼段中執行程序的控制轉移,因此不會執行特權級檢查。JMP、CALL、RET指令的遠轉移形式會把控制轉移到另外一個代碼段中,因此處理器一定會執行特權級檢查。
當目標代碼段的描述符中的C字段為1時,表示這是一個一致代碼段;為0時,表示這是一個非一致代碼段。
1.1 轉移到一致代碼段(C=1)
要求調用者的CPL在數值上大于等于目標代碼段的DPL。僅當CPL的數值小于DPL時,處理器才會產生一般保護異常。處理器忽略對RPL的檢查。
CPL并不改變,由于CPL沒有改變,因此堆棧也不會切換。
1.2 轉移到非一致代碼段(C=0)
要求調用者的CPL的數值必須等于目標代碼段的DPL,RPL在數值上小于等于目標代碼段的DPL; 
 當目標代碼段的段選擇子被加載進CS寄存器中時,CS的RPL字段在數值上等于調用者的CPL. 
 下圖摘自《Intel Architecture Software Developer’s Manual Volume 2: Instruction Set Reference》中的CALL指令,對于我們理解這個過程很有幫助。
注意畫紅框的部分:第一行表示把目標代碼段的選擇子傳到CS寄存器;第三行表示用當前特權級(不改變)修正CS寄存器的RPL字段。
1.3. 總結
我把以上檢查規則總結為下面的表格: 
 
大多數代碼段都是非一致代碼段。對于這些代碼段,程序的控制權只能轉移到具有相同特權級的代碼段中,除非轉移是通過一個調用門進行,見下文。
2. 通過調用門進行控制轉移
2.1. 調用門描述符的格式
調用門用在不同特權級之間實現受控的程序控制轉移,通常僅用于使用特權級保護機制的操作系統中。本質上,它只是一個描述符,一個不同于代碼段和數據段的描述符,可以安裝在GDT或者LGT中,但是不能安裝在IDT(中斷描述符表)中。 
 注意:Linux Kernel 0.12 中并沒有用到調用門。
上圖就是調用門描述符的格式(圖片來自趙炯的《Linux內核完全剖析》)。
為了訪問調用門,我們需要為CALL或者JMP指令的操作數提供一個遠指針。該指針中的選擇子用于指定調用門,而指針中的偏移值雖然需要,但是CPU不會使用它。該偏移值可以設置為任意值。當處理器訪問調用門時,它會使用調用門中的段選擇子來定位目標代碼段的段描述符。然后CPU會把代碼段描述符中的基地址和調用門中的偏移值進行組合,形成代碼段中指定程序入口點的線性地址。
2.2. 通過調用門訪問代碼段時的特權級檢查
通過調用門進行控制轉移時,CPU會檢查以下字段: 
 1. 當前特權級CPL 
 2. 調用指令中的調用門選擇子的RPL 
 3. 調用門描述符中的DPL 
 4. 目標代碼段描述符中的DPL 
 5. 目標代碼段描述符中的一致性標志C
不再啰嗦,一張圖看懂。 
  
 需要說明的是:如果通過調用門把控制轉移到了更高特權級的非一致代碼段中,那么CPL就會被設置為目標代碼段的DPL值,并且會引起堆棧切換。
關于堆棧的切換過程,我會在下篇博文中總結,敬請關注……
總結
以上是生活随笔為你收集整理的代码段间转移控制时的特权级检查(JMP/CALL)——《x86汇编语言:从实模式到保护模式》读书笔记28的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: python字符串类库_Python开发
- 下一篇: 编写一个可以打印不同长度数组内容的函数模
