现在的位置: 首页 > 综合 > 正文

一个操作系统的实现实验之3.2.2

2013年12月03日 ⁄ 综合 ⁄ 共 3995字 ⁄ 字号 评论关闭

目标:LDT(Local Descriptor Table)学习和使用;

代码:pmtest3.asm

原理:构造LDT,然后通过LDT描述符的信息跳入新的代码段执行

先来复习一下如果通过LDT寻址
如何通过GDT、LDT寻址

实模式下,以XXXX:YYYY(16位:16位)格式表示虚拟地址,它对应的物理地址为 XXXX*10h+YYYYYYYY。

保护模式下,以XXXX:YYYYYYYY(16位:32位)格式表示一个虚拟地址。XXXX现在存放的是段选择子,显然无法反映出段的基址在那。对于这个地址,需要采取如下步骤进行寻找:

1)看XXXX中的T1位是否为0,如果是,表示段描述符在GDT中,跳转到步骤2;如果为1,表示段描述符在LDT中,跳转到步骤5;

2)从GDTR中获得GDT的基址;

3)以XXXX中高13位当做位置索引得到段描述符;

4)从段描述符中就可以得到段的起始地址,这样就能得到XXXX:YYYYYYYY对应的线性地址了;

5)从GDTR中获得GDT的基址,从LDTR中获取LDT在GDT中的索引值;

6)根据索引值得到LDT在内存中的位置,即LDT段的位置;

7)以XXXX中高13位当做索引得到段描述符;

8)从段描述符中就可以得到段的起始地址。


下面来分析代码

1.GDT中如何定义LDT的表项

LABEL_DESC_LDT:    Descriptor       0,        LDTLen - 1, DA_LDT    ; LDT

定义了表项,接下来就需要定义它的选择子了
SelectorLDT        equ    LABEL_DESC_LDT        - LABEL_GDT

2.构造内存中的LDT
GDT中的LDT表项会告诉你LDT在内存中的位置,下面是构造LDT的代码
[SECTION .ldt]
ALIGN    32
LABEL_LDT:
    ;                                       段基址       段界限      属性
    LABEL_LDT_DESC_CODEA: Descriptor 0, CodeALen - 1, DA_C + DA_32 ; Code, 32 位
代码中只给LDT表中定义了一个表项,即LABEL_LDT_DESC_CODEA。
LDTLen        equ    $ - LABEL_LDT    ;计算LDT的长度

同GDT一样,定义了表项,接下来就需要定义它的选择子了
SelectorLDTCodeA    equ    LABEL_LDT_DESC_CODEA  - LABEL_LDT + SA_TIL
其实equ后面的内容用加括号的形式更好,即(LABEL_LDT_DESC_CODEA  - LABEL_LDT)+ SA_TIL,前半部分表示相对于LDT起始位置的偏移,后半部分表示选择子的TI位为1。TI位是区分GDT和LDT的关键。

3.最后是LABEL_LDT_DESC_CODEA表项对应的代码的定义
; CodeA (LDT, 32 位代码段)
[SECTION .la]
ALIGN    32
[BITS    32]
LABEL_CODE_A:
    mov    ax, SelectorVideo
    mov    gs, ax            ; 视频段选择子(目的)
    mov    edi, (80 * 12 + 0) * 2    ; 屏幕第 10 行, 第 0 列。
    mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
    mov    al, 'L'
    mov    [gs:edi], ax
    ; 准备经由16位代码段跳回实模式
    jmp    SelectorCode16:0
CodeALen    equ    $ - LABEL_CODE_A
功能很简单打印字符“L”。

4.所有有关LDT的定义都完成了,现在需要将代码和表项关联起来,其实也就是为表项中的段基址赋值
; 初始化 LDT 在 GDT 中的描述符
    xor    eax, eax
    mov    ax, ds
    shl    eax, 4
    add    eax, LABEL_LDT    ;内存中LDT的地址
    mov    word [LABEL_DESC_LDT + 2], ax    ;写入GDT中的LDT表项中
    shr    eax, 16
    mov    byte [LABEL_DESC_LDT + 4], al
    mov    byte [LABEL_DESC_LDT + 7], ah

    ; 初始化 LDT 中的描述符
    xor    eax, eax
    mov    ax, ds
    shl    eax, 4
    add    eax, LABEL_CODE_A    ;内存中代码CODE_A地址
    mov    word [LABEL_LDT_DESC_CODEA + 2], ax    ;写入LDT中LABEL_LDT_DESC_CODEA 表项中
    shr    eax, 16
    mov    byte [LABEL_LDT_DESC_CODEA + 4], al
    mov    byte [LABEL_LDT_DESC_CODEA + 7], ah

有关LDT的代码调试
1.lldt命令加载ldtr
(0) [0x0000000000032712] 0010:0000003e (unk. ctxt): mov ax, 0x0030            ; 66b83000   0x30是LDT表项在GDT中偏移
(0) [0x0000000000032716] 0010:00000042 (unk. ctxt): lldt ax                   ; 0f00d0
执行前
cs:0x0010, dh=0x00409903, dl=0x26d40062, valid=1
        Code segment, base=0x000326d4, limit=0x00000062, Execute-Only, Accessed, 32-bit
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
gdtr:base=0x00032348, limit=0x3f
执行后
ldtr:0x0030, dh=0x00008203, dl=0x27540007, valid=1
此处是保护模式的代码,顺便看看0010:00000042的寻址过程:
(1)0x10表示TI位为0,所以找GDT中的表项,应该是第3个,即LABEL_DESC_CODE32;
(2)GDT的地址由gdtr:base=0x00032348得到;
(3)表项LABEL_DESC_CODE32中存储的段基址值为0x000326d4;
(4)0010:00000042对应的线性地址为0x000326d4:0042;
(5)0x000326d4+0x42=0x0000000000032716

2.jmp    SelectorLDTCodeA:0    ; 跳入局部任务
(0) [0x0000000000032719] 0010:00000045 (unk. ctxt): jmp far 0004:00000000     ; ea000000000400
执行前
cs:0x0010, dh=0x00409903, dl=0x26d40062, valid=1
        Code segment, base=0x000326d4, limit=0x00000062, Execute-Only, Accessed, 32-bit
eip: 0x00000045
执行后
cs:0x0004, dh=0x00409903, dl=0x275c0019, valid=1
        Code segment, base=0x0003275c, limit=0x00000019, Execute-Only, Accessed, 32-bit
eip: 0x00000000

3.通过LDT寻址
选择LDT代码断中的语句mov    [gs:edi], ax
(0) [0x000000000003276b] 0004:0000000f (unk. ctxt): mov word ptr gs:[edi], ax ; 65668907
cs:0x0004, dh=0x00409903, dl=0x275c0019, valid=1
        Code segment, base=0x0003275c, limit=0x00000019, Execute-Only, Accessed, 32-bit
gs:0x0038, dh=0x0000930b, dl=0x8000ffff, valid=1
        Data segment, base=0x000b8000, limit=0x0000ffff, Read/Write, Accessed
edi: 0x00000780 1920
现在来看0004:0000000f的寻址过程,也就是通过LDT寻址的过程:
(1)0x04表示TI位为1,表示段描述符在LDT中;
(2)在GDT中查找表示LDT的表项,索引值来自于ldtr:0x0030,GDT的地址由gdtr:base=0x00032348得到;
(3)根据(2)中的值,检索出表项为第7个LABEL_DESC_LDT,其中存储的段基址值为0x00032754,也就是LDT内存地址;
(4)根据选择子0x04的高13位为0,也就是说该段在LDT中的偏移为0,所以要找的表项是LDT中的第1个;
(5)从LDT的第1个表项中读出的段基址为0x0003275c;
(5)0004:0000000f对应的线性地址为0x0003275c:0f;
(5)0x0003275c+0x0f=0x000000000003276b

LDT的用法我们基本了解了,但是为什么要引入LDT呢
可以把一个单独的任务所用到的所有东西封装在一个LDT中,这种思想就是多任务处理的一个雏形。

【上篇】
【下篇】

抱歉!评论已关闭.