保护模式 学习笔记--LDT
来源:互联网 发布:端口映射软件哪个好 编辑:程序博客网 时间:2024/05/07 12:52
LDT(Local Descriptor Table)它和GDT差不多,都是描述符表(Descriptor Table)区别仅仅在于全局(Global)和局部(Local)的不同。局部描述符表可以有若干张,每个任务可以有一张。
LDT和GDT从本质上说是相同的,只是LDT嵌套在GDT之中。LDTR记录局部描述符表的起始位置,与GDTR不同LDTR的内容是一个段选择子。由于LDT本身同样是一段内存,也是一个段,所以它也有个描述符描述它,这个描述符就存储在GDT中,对应这个表述符也会有一个选择子,LDTR装载的就是这样一个选择子。LDTR可以在程序中随时改变,通过使用lldt指令。
- ; ==========================================
- ; pmtest3.asm
- ; 编译方法:nasm pmtest3.asm -o pmtest3.com
- ; ==========================================
- ;常量, 宏, 以及一些说明
- DA_32 EQU 4000h ; 32 位段
- DA_C EQU 98h ; 存在的只执行代码段属性值
- DA_LDT EQU 82h ; 局部描述符表段类型值
- DA_DRW EQU 92h ; 存在的可读写数据段属性值
- DA_DRWA EQU 93h ; 存在的已访问可读写数据段类型值
- ATCE32 EQU 4098h ;存在的只执行32代码段属性值
- DA_DPL1 EQU 20h ; DPL = 1
- SA_TIG EQU 0 ;将TI位置0
- SA_TIL EQU 4 ;将TI位置1
- ;下面是宏定义
- ; 有三个参数:段界限,段基址,段属性其中宏定义中的%1代表参数1,%2代表参数2,%3代表参数3
- %macro Descriptor 3
- dw %2 & 0FFFFh ; 段界限1(参数2的低16位)
- dw %1 & 0FFFFh ; 段基址1(参数1的低16位)
- db (%1 >> 16) & 0FFh ; 段基址2(参数1的16-23位)
- dw ((%2 >> 8) & 0F00h) | (%3 & 0F000h)| (%3 & 000FFh) ; 属性1(高4位) + 段界限2(高4位) + 属性2(低8位)
- db (%1 >> 24) & 0FFh ; 段基址3(参数1的24-31位)
- %endmacro ; 共 8 字节
- ;段界限共20位,段基地址30位,段属性共16位(含段界限高4位)
- org 0100h
- jmp 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_C + DA_32 ; 非一致代码段, 32
- LABEL_DESC_CODE16: Descriptor 0, 0ffffh, DA_C ; 非一致代码段, 16
- LABEL_DESC_DATA: Descriptor 0, DataLen - 1, DA_DRW+DA_DPL1; 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 ; 显存首地址
- ; GDT 结束
- GdtLen equ $ - LABEL_GDT ; GDT长度
- GdtPtr dw GdtLen - 1 ; GDT界限
- dd 0 ; GDT基地址
- ; GDT 选择子
- SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
- SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
- SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
- SelectorData equ LABEL_DESC_DATA - LABEL_GDT
- SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
- SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT
- SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
- ; END of [SECTION .gdt]
- [SECTION .data1] ; 数据段
- ALIGN 32
- [BITS 32]
- LABEL_DATA:
- SPValueInRealMode dw 0
- ; 字符串
- PMMessage: db "In Protect Mode now. ^-^", 0 ; 进入保护模式后显示此字符串
- OffsetPMMessage equ PMMessage - $$ ;PMMessage起始地址偏移
- PMMessage2: db "hello world!"
- PMMessage2Len equ $ - PMMessage2
- OffsetPMMessage2 equ PMMessage2 - $$
- DataLen equ $ - LABEL_DATA
- ; END of [SECTION .data1]
- ; 全局堆栈段
- [SECTION .gs]
- ALIGN 32
- [BITS 32]
- LABEL_STACK:
- times 512 db 0 ;栈大小
- TopOfStack equ $ - LABEL_STACK - 1 ;栈顶指针
- ; END of [SECTION .gs]
- [SECTION .s16]
- [BITS 16]
- LABEL_BEGIN:
- mov ax, cs
- mov ds, ax
- mov es, ax
- mov ss, ax
- mov sp, 0100h
- mov [LABEL_GO_BACK_TO_REAL+3], ax;如果不懂请看前面文章分析
- mov [SPValueInRealMode], sp
- ; 初始化 16 位代码段描述符
- mov ax, cs
- movzx eax, ax ;零扩展指令
- shl eax, 4 ;段值*16
- add eax, LABEL_SEG_CODE16 ;段值*16+偏移=16位代码段基地址
- mov word [LABEL_DESC_CODE16 + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_DESC_CODE16 + 4], al ;基地址2
- mov byte [LABEL_DESC_CODE16 + 7], ah ;基地址3
- ; 初始化 32 位代码段描述符
- xor eax, eax
- mov ax, cs
- shl eax, 4 ;段值*16
- add eax, LABEL_SEG_CODE32 ;段值*16+偏移=16位代码段基地址
- mov word [LABEL_DESC_CODE32 + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_DESC_CODE32 + 4], al ;基地址2
- mov byte [LABEL_DESC_CODE32 + 7], ah ;基地址3
- ; 初始化数据段描述符
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;段值*16
- add eax, LABEL_DATA ;段值*16+偏移=16位代码段基地址
- mov word [LABEL_DESC_DATA + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_DESC_DATA + 4], al ;基地址2
- mov byte [LABEL_DESC_DATA + 7], ah ;基地址3
- ; 初始化堆栈段描述符
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;段值*16
- add eax, LABEL_STACK ;段值*16+偏移=16位代码段基地址
- mov word [LABEL_DESC_STACK + 2], ax
- shr eax, 16
- mov byte [LABEL_DESC_STACK + 4], al
- mov byte [LABEL_DESC_STACK + 7], ah
- ; 初始化 LDT 在 GDT 中的描述符
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;段值*16
- add eax, LABEL_LDT ;段值*16+偏移=16位代码段基地址 (LDT表基地址)
- mov word [LABEL_DESC_LDT + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_DESC_LDT + 4], al ;基地址2
- mov byte [LABEL_DESC_LDT + 7], ah ;基地址3
- ; 初始化 LDT 中的描述符
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;段值*16
- add eax, LABEL_CODE_A ;段值*16+偏移=16位代码段基地址 (LDT表对应的代码段的基地址)
- mov word [LABEL_LDT_DESC_CODEA + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_LDT_DESC_CODEA + 4], al ;基地址2
- mov byte [LABEL_LDT_DESC_CODEA + 7], ah ;基地址3
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;段值*16
- add eax, LABEL_CODE_B ;段值*16+偏移=16位代码段基地址 (LDT表对应的代码段的基地址)
- mov word [LABEL_LDT_DESC_CODEB + 2], ax ;基地址1
- shr eax, 16
- mov byte [LABEL_LDT_DESC_CODEB + 4], al ;基地址2
- mov byte [LABEL_LDT_DESC_CODEB + 7], ah ;基地址3
- ; 为加载 GDTR 作准备
- xor eax, eax
- mov ax, ds
- shl eax, 4 ;基地址2
- add eax, LABEL_GDT ; eax <- gdt 基地址
- mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
- ; 加载 GDTR
- lgdt [GdtPtr]
- ; 关中断
- cli
- ; 打开地址线A20
- in al, 92h
- or al, 00000010b
- out 92h, al
- ; 准备切换到保护模式
- mov eax, cr0
- or eax, 1
- mov cr0, eax
- ; 真正进入保护模式
- jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 处
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里
- mov ax, cs
- mov ds, ax
- mov es, ax
- mov ss, ax
- mov sp, [SPValueInRealMode]
- in al, 92h ; ┓
- and al, 11111101b ; ┣ 关闭 A20 地址线
- out 92h, al ; ┛
- sti ; 开中断
- mov ax, 4c00h ; ┓
- int 21h ; ┛回到 DOS
- ; END of [SECTION .s16]
- [SECTION .s32]; 32 位代码段. 由实模式跳入.
- [BITS 32]
- LABEL_SEG_CODE32:
- mov ax, SelectorData
- mov ds, ax ; 数据段选择子
- mov ax, SelectorVideo
- mov gs, ax ; 视频段选择子
- mov ax, SelectorStack
- mov ss, ax ; 堆栈段选择子
- mov esp, TopOfStack
- ; 下面显示一个字符串
- mov ah, 0Ch ; 0000: 黑底 1100: 红字
- xor esi, esi
- xor edi, edi
- mov esi, OffsetPMMessage ; 源数据偏移
- mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。
- cld ;设置数据传输方向
- .1:
- lodsb ;从[ds:esi]中去一个字符送入al
- test al, al ;判断是否到字符串末尾(以0结尾)
- jz .2 ;是->跳转
- mov [gs:edi], ax ;否->输入到显存
- add edi, 2 ;指针加2(一个字符占两个字节)
- jmp .1
- .2: ; 显示完毕
- call DispReturn ;换行
- ; Load LDT
- mov ax, SelectorLDT
- lldt ax ;加载LDT在GDT中的描述符
- call SelectorLDTCodeB:0 ; 跳入局部任务
- push SelectorLDTCodeA
- xor eax,eax
- push eax
- retf ; 跳入局部任务
- ;jmp SelectorLDTCodeA:0
- ; ------------------------------------------------------------------------
- DispReturn:
- push eax
- push ebx
- mov eax, edi ;获取当前光标的显存偏移
- mov bl, 160 ;每行80字符,每个字符占两个字节(字符ASCII码+字符属性),所以一行共80*2=160个字节
- div bl ;获取当前行数(在显存中行数从0开始编号的)
- and eax, 0FFh ;取低8位(在当前页,否则有可能输出到其它页了,显示器不会显示的)
- inc eax ;下一行
- mov bl, 160
- mul bl ;确定下一行开始的字节数
- mov edi, eax ;更新edi寄存器
- pop ebx
- pop eax
- ret
- ; DispReturn 结束---------------------------------------------------------
- SegCode32Len equ $ - LABEL_SEG_CODE32
- ; END of [SECTION .s32]
- ; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式
- [SECTION .s16code]
- ALIGN 32
- [BITS 16]
- LABEL_SEG_CODE16:
- ; 跳回实模式:
- mov ax, SelectorNormal ;设置实模式下的数据段
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
- mov ss, ax
- mov eax, cr0
- and al, 11111110b;设置cr0的0位(PE位,PE=0准备进入实模式)
- mov cr0, eax ;更新cr0
- LABEL_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 位
- LABEL_LDT_DESC_CODEB: Descriptor 0, CodeBLen - 1, DA_C + DA_32 ; Code, 32 位
- LDTLen equ $ - LABEL_LDT ;LDT表长度
- ; LDT 选择子
- SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
- SelectorLDTCodeB equ LABEL_LDT_DESC_CODEB - LABEL_LDT + SA_TIL
- ; END of [SECTION .ldt]
- ; CodeA (LDT, 32 位代码段)
- [SECTION .la]
- ALIGN 32
- [BITS 32]
- LABEL_CODE_A:
- mov ax, SelectorVideo
- mov gs, ax ; 视频段选择子(目的)
- mov edi, (80 * 12 + 0) * 2 ; 屏幕第 12 行, 第 0 列。
- mov ah, 0Ch ; 0000: 黑底 1100: 红字
- mov al, 'L'
- mov [gs:edi], ax
- ; 准备经由16位代码段跳回实模式
- jmp SelectorCode16:0
- CodeALen equ $ - LABEL_CODE_A
- ; END of [SECTION .la]
- ; CodeB (LDT, 32 位代码段)
- [SECTION .lb]
- ALIGN 32
- [BITS 32]
- LABEL_CODE_B:
- mov ax, SelectorVideo
- mov gs, ax ; 视频段选择子(目的)
- mov ax,SelectorData;
- mov ds,ax
- mov esi,OffsetPMMessage2 ;mov esi,PMMessage2注意不能这样写
- mov ecx,PMMessage2Len
- mov edi, (80 * 11 + 0) * 2 ; 屏幕第 11 行, 第 0 列。
- mov ah, 0Ch ; 0000: 黑底 1100: 红字
- .loop mov al,[ds:esi]
- mov [gs:edi], ax
- add edi,2
- inc esi
- loop .loop
- retf
- CodeBLen equ $ - LABEL_CODE_B
- ; END of [SECTION .lb]
在这里有两个局部任务,分别对应两个ldt表,一个局部任务是输出字符‘L’,一个任务是输出‘hello world!’,当然还有一个全局任务,输入字符‘In Protect Mode now.’程序先在实模式下初始化GDT,LDT表,设置相关寄存器,进入保护模式,输出一个字符串,然后加载局部描述表LDT,进入局部任务B,执行后返回,然后执行任务A,任务A完成后跳入16位代码段,设置相关寄存器值,回到实模式,结束回到DOS.
在进入保护模式前,我们需要初始化GDT,LDT表,因为在保护模式下需要根据相应段的表,找到代码或者数据的位置,当有局部任务时,GDT中应该包含LDT表存放的位置,这样当处理器在段描述符表中找到LDT描述表后发现是局部任务,这样就可以通过其记录的LDT表的位置,找到LDT表,然后在LDT表中找到相应的段描述符,如下图所示:
段描述符表=全局任务(GDT+LDT)GDTR寄存器中用于存放全局描述符表GDT的32位线性基地址和16位的表的长度值。LDTR寄存器中用于存放局部描述符表LDT的32位线性基地址和16位的表的长度值。通过系统指令,lgdt将GDT的线性基址和长度值加载到GDTR寄存器中,lldt将LDT的线性基址和长度值加载到LDTR寄存器中。
下面解释部分代码:
- call SelectorLDTCodeB:0 ; 跳入局部任务
- LABEL_CODE_B:
- mov ax, SelectorVideo
- mov gs, ax ; 视频段选择子(目的)
- mov ax,SelectorData;
- mov ds,ax
- mov esi,OffsetPMMessage2 ;mov esi,PMMessage2注意不能这样写
- mov ecx,PMMessage2Len
- mov edi, (80 * 11 + 0) * 2 ; 屏幕第 11 行, 第 0 列。
- mov ah, 0Ch ; 0000: 黑底 1100: 红字
- .loop mov al,[ds:esi]
- mov [gs:edi], ax
- add edi,2
- inc esi
- loop .loop
- retf
- mov esi,OffsetPMMessage2 ;mov esi,PMMessage2注意不能这样写
任务B完成后通过retf返回(还原段选择子和偏移)。接下来准备进入任务A
- push SelectorLDTCodeA
- xor eax,eax
- push eax
- retf ; 跳入局部任务
- ;jmp SelectorLDTCodeA:0</span>
下面这段代码是在LDT表中"声明"任务A,B,分别指向相应代码段,然后设置相应选择子:
- ; LDT
- [SECTION .ldt]
- ALIGN 32
- LABEL_LDT:
- ; 段基址 段界限 属性
- LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
- LABEL_LDT_DESC_CODEB: Descriptor 0, CodeBLen - 1, DA_C + DA_32 ; Code, 32 位
- LDTLen equ $ - LABEL_LDT ;LDT表长度
- ; LDT 选择子
- SelectorLDTCodeA equ LABEL_LDT_DESC_CODEA - LABEL_LDT + SA_TIL
- SelectorLDTCodeB equ LABEL_LDT_DESC_CODEB - LABEL_LDT + SA_TIL
- ; END of [SECTION .ldt]
- 保护模式学习笔记:LDT
- 保护模式 学习笔记--LDT
- 保护模式下ldt使用
- 保护模式下ldt使用
- 保护模式学习笔记:GDT
- 保护模式学习笔记:IDT
- 实模式/保护模式,GDT/LDT的含义
- 3.保护模式4----LDT(Local Descriptor Table)
- 操作系统学习笔记(15)--保护模式
- 学习笔记--实践认识保护模式
- 汇编学习笔记之实模式/保护模式内存寻址
- 汇编学习笔记之实模式/保护模式区别
- 操作系统实验四:保护模式之局部任务(LDT)初探
- 保护模式下三个重要的系统表——GDT、LDT和IDT
- 保护模式下三个重要的系统表——GDT、LDT和IDT
- 保护模式下三个重要的系统表——GDT、LDT和IDT
- 80386保护模式--GDT,LDT,TSS,调用门,特权级转移,附pmtest5代码详解
- 《Orange’s 一个操作系统的实现》3.保护模式4----LDT(Local Descriptor Table)
- javascript中的callee和caller
- Bitmap Options解析
- spacemacs创建layer
- 【Linux】用户及文件权限管理
- 1836:Alignment
- 保护模式 学习笔记--LDT
- 关于如何启动多个tomcat
- 命令行启动mysql时“服务名无效”
- codeforces 446B(优先队列)
- Qt5.7不能加载MySql驱动问题.(需要重新编译驱动)
- unity 用Box Collider为物体添加碰撞范围
- 输入框显示提示文字
- Material Design设计规范的几种控件:Snackbar
- 监听Hierachy、Project等视图结构变化的事件