• 段选择子与段描述符结构(转)


    段描述符和段选择子
    我想 C 语言你应该是学了很久了,那么我来定义一个数组。

    // 一个 QWORD 是一个 8 字节的整数
    QWORD gdt[1024];
    很明显,这是一个能容纳 1024 个元素的数组。现在我来定义:

    gdt 数组中的每个元素都是一个段描述符
    数组的索引号是段选择子
    这个 gdt 数组被称为 gdt 表
    只不过……,只不过这个段选择子,可能不会直接就表示成你想要的索引号,0就是0,5就是5,它稍微有些区别。

    另外,段描述符,就是一个 8 字节的整数,可是这个整数,包含的信息量有点大。后面我们要做的,就是破译这个整数。

    既然如此,后文自然是重点解析段选择子和段描述符,打通通往操作系统之路。

    段描述符与段选择子的结构
    段选择子结构
    段选择子就是一个数字,一共有16位,结构如下:

    | 1 | 0 | 字节
    |7654321076543 2 10| 比特
    |-------------|-|--| 占位
    | INDEX |T|R | 含义
    | |I|P |
    | | |L |

    INDEX:在GDT数组或LDT数组的索引号
    TI:Table Indicator,这个值为0表示查找GDT,1则查找LDT
    RPL:请求特权级。以什么样的权限去访问段。
    段描述符结构
    | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 字节
    |76543210|7 6 5 4 3210 |7 65 4 3210|76543210|76543210|76543210|76543210|76543210| 比特
    |--------|-|-|-|-|---- |-|--|-|----|--------|--------|--------|--------|--------| 占位
    | BASE |G|D|0|A|LIMIT|P|D |S|TYPE|<------- BASE 23-0 ------>|<-- LIMIT 15-0 ->| 含义
    | 31-24 | |/| |V|19-16| |P |
    |B| |L| | |L |

    BASE: 段基址,由上图中的两部分(BASE 31-24 和 BSE23-0)组成
    G:LIMIT的单位,该位 0 表示单位是字节,1表示单位是 4KB
    D/B: 该位为 0 表示这是一个 16 位的段,1 表示这是一个 32 位段
    AVL: 该位是用户位,可以被用户自由使用
    LIMIT: 段的界限,单位由 G 位决定。数值上(经过单位换算后的值)等于段的长度(字节)- 1。
    P: 段存在位,该位为 0 表示该段不存在,为 1 表示存在。
    DPL:段权限
    S: 该位为 1 表示这是一个数据段或者代码段。为 0 表示这是一个系统段(比如调用门,中断门等)
    TYPE: 根据 S 位的结果,再次对段类型进行细分。
    段描述符安装在 GDT 或者 LDT 数组中,可以在 WinDbg 中使用命令 r gdtr来查看 GDT 基址在哪里。

    有关段描述符属性的具体细节,后文陆续给出。

    如何把段描述符填充到段选择子
    段寄存器一共有 96 位,其中 16 可见部分来源于段选择子的索引部分。剩下 80 位来源于 GDT 表。

    下面来分析一下,如何把 0x1B 、0x23 这两个选择子对应的描述符填充到段寄存器。

    做这个练习的时候,先不要问这些字段是什么含义,只要把这些字段的值查出来就行了。

    原始数据:

    |--地址--|-------------16进制值---------------|
    8003f000 00000000`00000000 00cf9b00`0000ffff
    8003f010 00cf9300`0000ffff 00cffb00`0000ffff
    8003f020 00cff300`0000ffff 80008b04`200020ab
    8003f030 ffc093df`f0000001 0040f300`00000fff

    0x1B
    0x1B = 0000 0000 0001 1011b
    索引号:0000 0000 0001 1= 3 (查找gdt[3])
    RPL: 11b = 3
    TI: 0 (查找 GDT 表)
    查找到的 GDT 描述符为:gdt[3] = 00cffb00`0000ffff
    段寄存器结构:
    selector = 0x001B
    attribute = 0xcffb (G = 1 DB = 1 P = 1 DPL = 3 S = 1 TYPE = 1011(非一致代码段,可读已访问过))
    base = 0x00000000
    limit = 0xffffffff

    10
    0x23
    0x23 = 0000 0000 0010 0011b
    索引号:0000 0000 0010 0 = 4
    TI: 0 (查找 GDT 表)
    RPL: 11b = 3
    查找到的 GDT 描述符为:gdt[4] = 00cff300`0000ffff
    段寄存器结构:
    selector = 0x23
    attribute = 0xcff3 (G = 1 DB = 1 P = 1 DPL = 3 S = 1 TYPE = 0011(可读可写向上扩展的数据段))
    base = 0x00000000
    limit = 0xffffffff

    这里最麻烦的应该是分析 limit 了。

    如何分析 limit
    limit 的含义是这个段的大小。实际上这么说的点不准确。limit 应该描述为,段大小再减去1字节。(这里的 limit 是换算后的 limit)。后面我用大写的 LIMIT 表示段描述符中的 20bit LIMIT。

    如果粒度 G=0,LIMIT= 0x3ff,这意味着该段的大小是 0x3ff+1=0x400 字节。如果 G=1,那意味着该段的大小是(0x3ff+1)*4KB=0x400000字节,所以换算后的 limit = 0x400000-1=0x003fffff.

    再举个例子。LIMIT=0xfffff, G=1,则该段的大小是 (0xfffff+1)*4KB=0x100000*0x1000=0x100000000字节,所以换算后的 limit=0x100000000-1=0xffffffff


    limit 简算法
    如果 G = 0,把段描述符中的 20 bit LIMIT取出来,比如 0x003ff,然后在前面补 0 至32bit,即 limit = 0x000003ff.
    如果 G=1,把段描述符中的 20 bit LIMIT取出来,比如 0x003ff,然后在后面补 f 至 32bit, 即 LIMIT = 0x003fffff
    总结
    本篇主要讲解了段寄存器 中的数据来源。上篇实验中,给出了几个实验,当时我们只是把另一个段寄存器中的数据读入到寄存器 ax(16bit),然后把 ax 代入到了 ds,可是 ax 明明只有 16 位啊,而 ds 有 96 位。

    CPU必然在背后帮我们做了一些事情,它从 GDT 表中取出对应的段描述符,经过分析后自动的填写的了段寄存器中。这个过程,是需要大家深刻理解和掌握的

    8086寄存器中,只有bx,bp,si,di这四个寄存器可以用在[……]中表示偏移地址
    ---------------------
    作者:--Allen--
    来源:CSDN
    原文:https://blog.csdn.net/q1007729991/article/details/52538080

  • 相关阅读:
    PowerShell2.0之与COM对象交互(二)Word自动化
    PowerShell2.0之与COM对象交互(三)Excel自动化
    PowerShell 2.0之使用WMI管理Windows(一)WMI基础
    PowerShell2.0之与COM对象交互(五)与脚本宿主代码协同工作
    PowerShell2.0之与COM对象交互(四)IE自动化
    PowerShell2.0之与COM对象交互(一)COM基础
    php中一些常用的语句收集
    NET第三方控件AspNetPager设置样式
    JAVAMyEclipse 自动提示(按alt+/)时假死现像
    NET数据访问基础类(基于OleDb)
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/10521297.html
Copyright © 2020-2023  润新知