重庆知名网站建设公司,123房产网,公司logo设计免费生成软件,住房和建设厅官方网站【0】写在前面
0.1#xff09;本代码#xff0c;添加了门描述符的相关代码#xff0c;旨在说明 怎样 对门转移的目标段 进行定义#xff0c;调用#xff1b;0.2#xff09;本文 只对 与 门相关的 代码进行简要注释#xff0c;言简意赅#xff1b;0.3#xff09;文末总…【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]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_CDA_32; 非一致代码段,32
LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段,16; 调用门目标段的描述符定义
LABEL_DESC_CODE_DEST: Descriptor 0,SegCodeDestLen-1, DA_CDA_32; 非一致代码段,32 LABEL_DESC_DATA: Descriptor 0, DataLen-1, DA_DRW ; Data
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWADA_32;Stack, 32 位
LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT ; LDT
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 显存首地址; 门的定义紧跟在描述符定义之后 ; 门: 目标选择子,偏移,DCount, 属性
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGateDA_DPL0 GDT 选择子定义......;门目标段描述符的选择子定义
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT; 门自身选择子的定义门也当做一个描述符 ; 这里的干货是调用门如何与调用门目标段联系起来调用门描述符中的数据结构有选择子该选择子存储的就是调用门目标段的选择子
SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT; END of [SECTION .gdt]
数据段定义 全局堆栈段定义
......16位代码段 CPU运行在实模式下为什么只有在16位代码段下才能修改GDT中的值 [SECTION .s16] ; Mine【为从实模式跳转到保护模式所做的准备工作】
[BITS 16]
LABEL_BEGIN:......; 初始化测试调用门的代码段目标段描述符 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]
[BITS 32]LABEL_SEG_CODE32:
......; 下面显示一个字符串此处代码有省略; 测试调用门无特权级变换将打印字母 ‘C’ call SelectorCallGateTest:0; call SelectorCodeDest:0Mine【这里的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]
[BITS 32]LABEL_SEG_CODE_DEST:;jmp $mov ax, SelectorVideomov gs, ax ; 视频段选择子(目的)mov edi, (80 * 12 0) * 2 ; 屏幕第 12 行, 第 0 列。mov ah, 0Ch ; 0000: 黑底 1100: 红字mov al, Cmov [gs:edi], axretfSegCodeDestLen equ $ - LABEL_SEG_CODE_DEST; END of [SECTION .sdest]
; 16 位代码段. 由 32 位代码段跳入, 本段跳出后到实模式 [SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:; 跳回实模式:mov ax, SelectorNormal ; Mine【 选择子 SelectorNormal 是对描述符 LABEL_DESC_NORMAL 的索引 】mov ds, axmov es, axmov fs, axmov gs, axmov ss, axmov eax, cr0and al, 11111110b ; Mine【cr0的最后一位PE位置为0进入实模式】mov cr0, eaxLABEL_GO_BACK_TO_REAL:jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值
Code16Len equ $ - LABEL_SEG_CODE16; END of [SECTION .s16code]
; LDT 的定义 [SECTION .ldt]
ALIGN 32
LABEL_LDT:
; 段基址 段界限 属性
LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C DA_32 ; Code, 32 位LDTLen equ $ - LABEL_LDT; LDT 选择子的定义
SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT SA_TIL; END of [SECTION .ldt]
; CodeA (LDT, 32 位代码段)通过索引选择子SelectorLDTCodeA跳入 [SECTION .la]
ALIGN 32
[BITS 32]
LABEL_CODE_A:mov ax, SelectorVideomov gs, ax ; 视频段选择子(目的)mov edi, (80 * 12 0) * 2 ; 屏幕第 10 行, 第 0 列。mov ah, 0Ch ; 0000: 黑底 1100: 红字mov al, Lmov [gs:edi], ax; 准备经由16位代码段跳回实模式jmp SelectorCode16:0
CodeALen equ $ - LABEL_CODE_A; END of [SECTION .la] 总结 关于门描述符的定义调用
1call指令调用门目标段这个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 调用门——入口地址 其实调用门这种听起来很可怕的东西本质上只不过是一个入口地址而已只是增加了若干属性而已。在我们的例子中完全可以用调用门进行跳转的指令修改为跳转到调用门内指定的地址的指令即 将 call SelectorCallGateTest:0 改为 call SelectorCodeDest:0 效果完全一样。注SelectorCallGateTest 是 调用门选择子 而SelectorCodeDest 是 调用门目标段选择子3那么问题 来了 既然把跳转地址从调用门选择子 改为 调用门目标段选择子执行效果相同那为什么我们还需要调用门呢 3.1我们需要用门来实现不同特权级的代码间的转移 因为单纯地通过CPL、RPL和RPL进行比较 来进行不同特权级代码段间的转移的话有诸多限制3.2有特权级变换的转移的复杂之处 不但在于严格的特权级检验还在于特权级变换的时候堆栈也要发生变化处理器利用调用门的机制避免了高特权级的过程由于栈空间不足而崩溃AttentionA1引入门调用门后 多出了两个描述符即门目标段描述符 门自身的描述符A2引入门调用门后多出了两个选择子即门目标段描述符的选择子 门描述符的选择子A3门目标段描述符的选择子 门描述符的选择子的作用 A3.1门目标段描述符的选择子 用于索引门目标代码段存储在门描述符数据结构中的选择子这个数据项A3.2门描述符的选择子 用于索引定位门调用门 为数据段目标和代码段的特权级转移 提供入口地址而已A4调用门如何与 门目标段 联系起来 ; 门的定义紧跟在描述符定义之后
; 门 目标选择子,偏移,DCount, 属性
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGateDA_DPL0在 门的定义代码中 门描述符中的目标选择子存储着 门目标段的选择子这样来建立联系的A5 也就是说 通过调用门和call指令 可以实现从低特权级到高特权级的转移无论目标代码段是一致的还是非一致的 在GDT的定义中有以下代码 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_CDA_32; 非一致代码段,32(98h 4000h) LABEL_CALL_GATE_TEST: Gate SelectorCodeDest, 0, 0, DA_386CGateDA_DPL0 ;(8Ch 00h)
从中可以发现32位 代码段 描述符LABEL_DESC_CODE32 的属性 是0100, 0000, 1001, 1000 而调用门描述符 LABEL_CALL_GATE_TEST 的属性是 1000 1100 通过描述符的数据结构和 门的数据结构得到 LABEL_DESC_CODE32