调用门的定义+调用
【0】寫在前面
- 0.1)本代碼,添加了門描述符的相關代碼,旨在說明 怎樣 對門轉移的目標段 進行定義,調用;
- 0.2)本文 只對 與 門相關的 代碼進行簡要注釋,言簡意賅;
- 0.3)文末總結是干貨(from orange’s implemention of a os),前面代碼僅供參考的,且source code from orange’s implemention of a os.
; ========================================== ; pmtest2.asm ; 編譯方法:nasm pmtest2.asm -o pmtest2.com ; ==========================================%include "pm.inc" ; 常量, 宏, 以及一些說明org 0100hjmp LABEL_BEGIN
;全局描述符表定義
[SECTION .gdt]
; 調用門目標段的描述符定義
LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_C+DA_32; 非一致代碼段,32LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW ; Data LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32;Stack, 32 位 LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT ; LDT LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 顯存首地址
; 門的定義,緊跟在描述符定義之后
; 門: 目標選擇子,偏移,DCount, 屬性
;GDT 選擇子定義 ......
;門目標段描述符的選擇子定義
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT; 門自身選擇子的定義(門也當做一個描述符)
; 這里的干貨是,調用門如何與調用門目標段聯系起來(調用門描述符中的數據結構有選擇子,該選擇子存儲的就是調用門目標段的選擇子)
; END of [SECTION .gdt]
;數據段定義 + 全局堆棧段定義 ......;16位代碼段, CPU運行在實模式下,為什么只有在16位代碼段下才能修改GDT中的值
[SECTION .s16] ; Mine【為從實模式跳轉到保護模式所做的準備工作】
; 初始化測試調用門的代碼段(目標段)描述符
xor eax, eaxmov ax, csshl eax, 4add eax, LABEL_SEG_CODE_DESTmov word [LABEL_DESC_CODE_DEST + 2], axshr eax, 16mov byte [LABEL_DESC_CODE_DEST + 4], almov byte [LABEL_DESC_CODE_DEST + 7], ah......;初始化 LDT 在 GDT 中的描述符 ;Mine【 LABEL_DESC_LDT 作為GDT的表項】xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_LDTmov word [LABEL_DESC_LDT + 2], axshr eax, 16mov byte [LABEL_DESC_LDT + 4], almov byte [LABEL_DESC_LDT + 7], ah; 初始化 LDT 中的描述符 ; Mine【初始化LDT的基地址所指向的具體的多任務代碼段】xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_CODE_Amov word [LABEL_LDT_DESC_CODEA + 2], axshr eax, 16mov byte [LABEL_LDT_DESC_CODEA + 4], almov byte [LABEL_LDT_DESC_CODEA + 7], ah;為加載 GDTR 作準備,填充GDT基地址的數據結構xor eax, eaxmov ax, dsshl eax, 4add eax, LABEL_GDT ; eax <- gdt 基地址mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址; 加載 GDTRlgdt [GdtPtr]; 關中斷cli; 打開地址線A20in al, 92hor al, 00000010bout 92h, al; 準備切換到保護模式, PE位置1mov eax, cr0or eax, 1mov cr0, eax; 真正進入保護模式jmp dword SelectorCode32:0 ; 執行這一句會把 SelectorCode32 裝入 cs, 并跳轉到 Code32Selector:0 處; 從保護模式跳回到實模式就到了這里 (注意:從保護模式跳轉到實模式,即本標識符下,本標識符是存在于 初始化描述符的16位代碼段的末尾的) LABEL_REAL_ENTRY: mov ax, csmov ds, axmov es, axmov ss, axmov sp, [SPValueInRealMode]; 關閉 A20 地址線in al, 92h ; and al, 11111101b out 92h, al ; /sti ; 開中斷mov ax, 4c00h ; `.int 21h ; / 回到 DOS
; END of [SECTION .s16]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32 位代碼段,即保護模式. 由實模式跳入
[SECTION .s32]
; 測試調用門(無特權級變換),將打印字母 ‘C’
call SelectorCallGateTest:0; call SelectorCodeDest:0; Mine【這里的LDT選擇子索引的是LDT中記錄的描述符表項的基地址值,即具體任務的執行代碼】; Load LDTmov ax, SelectorLDT ; lldt ax ; Mine【lldt 負責 加載ldtr, 它的操作數是一個選擇子,這個選擇子對應的就是用來描述LDT的那個描述符LABEL_DESC_LDT】; 跳入局部任務jmp SelectorLDTCodeA:0 SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]
; 調用門目標段
[SECTION .sdest]
; END of [SECTION .sdest]
; 16 位代碼段. 由 32 位代碼段跳入, 本段跳出后到實模式
[SECTION .s16code]
; END of [SECTION .s16code]
; LDT 的定義
[SECTION .ldt]
; END of [SECTION .ldt]
; CodeA (LDT, 32 位代碼段),通過索引選擇子SelectorLDTCodeA跳入
[SECTION .la]
; END of [SECTION .la]
總結: (關于門描述符的定義+調用)
- 1)call指令調用門目標段:這個call指令 在調用門目標段的時候, 被放在進入局部任務之前, 由于我們新加的調用門目標段是以 指令retf 結尾,所以最終代碼將會調回到call 指令的下面繼續執行, 下面就執行局部任務了;(段間 call == [ push ip, push cs, jmp far ptr 標號] , retf == [ pop cs, pop ip ]; 而段內 call == [ push ip, jmp near ptr 標號 ], ret == pop ip )
- 2)調用門——入口地址: 其實調用門這種聽起來很可怕的東西本質上只不過是一個入口地址而已,只是增加了若干屬性而已。在我們的例子中,完全可以用調用門進行跳轉的指令修改為跳轉到調用門內指定的地址的指令:即 將 call SelectorCallGateTest:0 改為 call SelectorCodeDest:0 ,效果完全一樣。(注:SelectorCallGateTest 是 調用門選擇子, 而SelectorCodeDest 是 調用門目標段選擇子)
- 3)那么問題 來了: 既然,把跳轉地址從調用門選擇子 改為 調用門目標段選擇子,執行效果相同,那為什么我們還需要調用門呢?
- 3.1)我們需要用門來實現不同特權級的代碼間的轉移, 因為單純地通過CPL、RPL和RPL進行比較 來進行不同特權級代碼段間的轉移的話,有諸多限制;
- 3.2)有特權級變換的轉移的復雜之處, 不但在于嚴格的特權級檢驗,還在于特權級變換的時候,堆棧也要發生變化;處理器利用調用門的機制避免了高特權級的過程由于棧空間不足而崩潰;
- Attention)
- A1)引入門(調用門)后, 多出了兩個描述符,即門目標段描述符 + 門自身的描述符;
- A2)引入門(調用門)后,多出了兩個選擇子,即門目標段描述符的選擇子 + 門描述符的選擇子;
A3)門目標段描述符的選擇子 + 門描述符的選擇子的作用:
- A3.1)門目標段描述符的選擇子: 用于索引門目標代碼段,存儲在門描述符數據結構中的選擇子這個數據項,;
- A3.2)門描述符的選擇子: 用于索引(定位)門(調用門), 為數據段(目標和代碼段)的特權級轉移 提供入口地址而已,
A4)(調用)門如何與 門目標段 聯系起來:
; 門的定義,緊跟在描述符定義之后 ; 門 目標選擇子,偏移,DCount, 屬性 LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0在 門的定義代碼中, 門描述符中的目標選擇子存儲著 門目標段的選擇子,這樣來建立聯系的;
A5) 也就是說, 通過調用門和call指令, 可以實現從低特權級到高特權級的轉移,無論目標代碼段是一致的還是非一致的;
在GDT的定義中,有以下代碼:LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32; 非一致代碼段,32(98h + 4000h)
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGate+DA_DPL0 ;(8Ch + 00h)
從中可以發現,32位 代碼段 描述符LABEL_DESC_CODE32 的屬性 是0100, 0000, 1001, 1000 ; 而(調用)門描述符 LABEL_CALL_GATE_TEST 的屬性是 1000, 1100 ;
通過描述符的數據結構和 門的數據結構,得到 LABEL_DESC_CODE32
總結
- 上一篇: 没备案怎么访问(没备案怎么访问域名)
- 下一篇: ssh无密码登陆权威指南