“Global Descriptor Table”的版本间差异

来自osdev
跳到导航 跳到搜索
(创建页面,内容为““全局描述符表”(“GDT”)是特定于 IA-32]和[[X86-64 | X86-64体系结构的二进制数据结构。它包含告诉CPU关于内存分段的条目。 类似的中断描述符表包含任务中断描述符。 建议阅读GDT教程。 == GDTR == “GDT”由“GDTR”寄存器中的值指向。 这是使用“LGDT”汇编指令加载的,该指令的参数是指向“GDT描述符”…”)
 
第1行: 第1行:
“全局描述符表”(“GDT”)是特定于[[IA32_体系结构| IA-32]和[[X86-64 | X86-64]]体系结构的二进制数据结构。它包含告诉CPU关于内存[[分段|分段]]的条目。 类似的[[中断描述符表]]包含[[任务]]和[[中断|中断]]描述符。
'''全局描述符表'''('''Global Descriptor Table - GDT''')是特定于[[IA32_Architecture_Family|IA-32]]和[[X86-64|x86-64]]体系结构的二进制数据结构。 它包含告诉CPU有关内存[[Segmentation|分段]]的条目。 还存在一个类似的 [[Interrupt Descriptor Table|中断描述符表(Interrupt Descriptor Table)]],其中包含 [[task|任务]] 和 [[Interrupts|中断]] 描述符。


建议阅读[[GDT教程]]。
建议阅读[[GDT Tutorial|GDT教程]]。


== GDTR ==
== GDTR寄存器 ==


“GDT”由“GDTR”寄存器中的值指向。 这是使用“LGDT”汇编指令加载的,该指令的参数是指向“GDT描述符”结构的指针:
'''GDT'''由'''GDTR'''寄存器中的值指向。 这是使用'''LGDT'''汇编指令加载的,该指令的参数是指向'''GDT描述符'''结构的指针:


{| class="wikitable"
{| class="wikitable"
第15行: 第15行:
|'''Size'''<br><br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|'''Size'''<br><br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|}
|}
* '''Size:''' 表的大小(以字节为单位)减去1。之所以发生此减法,是因为“Size”的最大值为65535,而“GDT”的长度最多为65536字节(8192个条目)。此外,任何“GDT”的大小都不能为0字节。
* '''Size:''' 表的大小(以字节为单位)减去1。 之所以发生这种减法,是因为 '''size''' 的最大值是65535的,而'''GDT'''的长度最多可达65536个字节 (8192个条目)。 此外,'''gdt'''不可以具有0字节的大小。
* '''Offset:''' “GDT”的线性地址(不是物理地址,分页适用)。
* '''Offset:''' '''GDT'''的线性地址(不是物理地址,分页适用)。


请注意,“LGDT”加载的数据量在32位和64位模式下有所不同,偏移量在32位模式下为4字节长,在64位模式下为8字节长。
请注意,'''LGDT'''加载的数据量在32位和64位模式中不同,偏移量在32位模式中为4字节长,在64位模式中为8字节长。


有关更多信息,请参见“第2.4节”。1:《英特尔软件开发人员手册》第3-A卷的“全局描述符表寄存器(GDTR)”和“图2-6:内存管理寄存器”。
有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 '''Section 2.4.1: Global Descriptor Table Register (GDTR)''' 和 '''Figure 2-6: Memory Management Registers'''。


== 表格 ==
== 表说明 ==


“GDT”中的条目长度为8字节,形成如下表格:
'''GDT'''中的条目长度为8字节,形成如下表格:


{|class="wikitable"
{|class="wikitable"
|+ Global Descriptor Table
|+ Global Descriptor Table
! Address !! Content
! 地址 !! 内容
|-
|-
| GDTR Offset + 0 || Null
| GDTR Offset + 0 || Null
第41行: 第41行:
|}
|}


'GDT'”(条目0)中的第一个条目应始终为空,并应使用后续条目。
'''GDT''' (条目0) 中的第一个条目应始终为null,并应使用后续条目。


“段选择器”可访问表中的条目,它们通过汇编指令或硬件功能(如“[[Interrupts]]”加载到“[[Segmentation]]”寄存器中。
表中的条目由'''[[Segment Selector|段选择器(Segment Selectors)]]'''访问,这些条目通过汇编指令或硬件功能(如'''[[Interrupts|中断]]''')加载到'''[[Segmentation|段]]'''寄存器中。


== 段描述符 ==
==段描述符(Segment Descriptor)==


表中的每个条目都有一个复杂的结构:
表中的每个条目都有一个复杂的结构:
{| class="wikitable"
{| class="wikitable"
|+ Segment Descriptor
|+ Segment Descriptor
第70行: 第70行:


* '''Base:''' 一个32位的值,包含段开始的线性地址。
* '''Base:''' 一个32位的值,包含段开始的线性地址。
* '''Limit:''' 一个20位的值,以1字节单位或4KB页面表示最大可寻址单元。 因此,如果选择页面粒度并将“限制”值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB地址空间。
* '''Limit:''' 20位值告诉最大可寻址单元,以1字节为单位,或以4KiB页为单位。 因此,如果选择页面粒度并将 '''Limit''' 值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB地址空间。


在64位模式下,忽略“Base”和“Limit”值,每个描述符覆盖整个线性地址空间,而不管它们设置为什么。
在64位模式下,忽略'''Base'''和'''Limit'''值,每个描述符覆盖整个线性地址空间,不管它们设置为什么。


有关更多信息,请参见“第3.4节”。《英特尔软件开发人员手册》第3-A卷第5部分:段描述符“”和“图3-8:段描述符”。
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的'''Section 3.4.5: Segment Descriptors'''和'''Figure 3-8: Segment Descriptor'''。


{| class="wikitable"
{| class="wikitable"
第88行: 第88行:
!style="width: 12.5%;"|0
!style="width: 12.5%;"|0
|-
|-
|'''Pr''' ||colspan=2|'''Privl''' || '''S''' || '''Ex''' || '''DC''' || '''RW''' || '''Ac'''
|'''P''' ||colspan=2|'''DPL''' || '''S''' || '''E''' || '''DC''' || '''RW''' || '''A'''
|}
|}


* '''Pr:''' 当前位。 允许条目引用有效段。 Must be set ('''1''') for any valid segment.
* '''P:''' 当前位。 允许条目引用有效段。 必须为任何有效段设('''1''')
* '''Privl:''' 描述符特权级别字段。 包含段的[[Security#Rings | CPU特权级别]]'''0''' = highest privilege (kernel), '''3''' = lowest privilege (user applications).
* '''DPL:''' 描述符特权级别字段。 包含段的[[Security#Rings| CPU特权级别]] '''0''' =最高权限(内核),'''3''' = 最低权限(用户应用程序)。
* '''S:''' 描述符类型位。 If clear ('''0''') the descriptor defines a system segment (eg. a [[Task_State_Segment|Task State Segment]]). 如果设置('''1''),则定义代码或数据段。
* '''S:''' 描述符类型位。 如果清 ('''0'''),则描述符定义一个系统段 (例如 [[Task_State_Segment|任务状态段-Task State Segment]])。 如果设('''1'''),则定义代码或数据段。
* '''Ex:''' Executable bit. If clear ('''0''') the descriptor defines a data segment. If set ('''1''') it defines a code segment which can be executed from.
* '''E:''' Executable bit. 如果清('''0'''),则描述符定义数据段。 如果设('''1'''),它定义了一个可以从中执行的代码段。
* '''DC:''' Direction bit/Conforming bit.
* '''DC:''' Direction bit/Conforming bit.
  ** For data selectors: Direction bit. If clear ('''0''') the segment grows up. If set ('''1''') the segment [[Expand_Down|grows down]], ie. the '''Offset''' has to be greater than the '''Limit'''.
** 对于数据选择器: Direction bit。 如果清('''0'''),则该段将向上增长。 如果设('''1''')[[Expand_Down|向下增长]],即'''Offset'''必须大于'''Limit'''
  ** For code selectors: Conforming bit.
** 对于代码选择器:Conforming bit。
  *** If clear ('''0''') code in this segment can only be executed from the ring set in '''Privl'''.
*** If Clear('''0''')该段中的代码只能从'''Privl'''中设置的Ring执行。
  *** If set ('''1''') code in this segment can be executed from an equal or lower privilege level. For example, code in ring 3 can far-jump to ''conforming'' code in a ring 2 segment. The '''Privl''' field represent the highest privilege level that is allowed to execute the segment. For example, code in ring 0 cannot far-jump to a conforming code segment where '''Privl''' is 2, while code in ring 2 and 3 can. 请注意,特权级别保持不变,即。 a far-jump from ring 3 to a segment with a '''Privl''' of 2 remains in ring 3 after the jump.
*** 如果设('''1'''),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的''conforming''代码。 '''Privl'''字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 '''Privl''' 为2的conforming代码段,而ring2和ring中的代码可以。 请注意,特权级别保持不变,即在跳转后,从Ring3到'''Privl'''为2的段的far-jump仍保留在Ring3中。
* '''RW:''' Readable bit/Writable bit.
* '''RW: ''' 可读位/可写位。
  ** For code segments: Readable bit. If clear ('''0'''), read access for this segment is not allowed. If set ('''1''') read access is allowed. 决不允许对代码段进行写访问。
** 对于代码段:可读位。 如果清('''0'''),则不允许对此段进行读取访问。 如果设('''1'''),则允许读取访问。 永远不允许对代码段进行写访问。
  ** 对于数据段:可写位。 If clear ('''0'''), write access for this segment is not allowed. If set ('''1''') write access is allowed. Read access is always allowed for data segments.
** 对于数据段:可写位。 如果清 ('''0'''),则不允许对此段进行写访问。 如果设('''1'''),则允许写访问。 数据段始终允许读取访问。
* '''Ac:''' Accessed bit. Best left clear ('''0'''), the CPU will set it when the segment is accessed.
* '''A:''' Accessed bit. 最好清('''0'''),CPU将在访问段时设它为1。


{| class="wikitable"
{| class="wikitable"
第113行: 第113行:
!style="width: 25%;"|0
!style="width: 25%;"|0
|-
|-
|'''Gr''' || '''Sz''' || '''L'''
|'''G''' || '''DB''' || '''L'''
|Reserved
|Reserved
|}
|}


* '''Gr:''' Granularity flag, indicates the size the '''Limit''' value is scaled by. If clear ('''0'''), the '''Limit''' is in 1 Byte blocks (byte granularity). If set ('''1'''), the '''Limit''' is in 4 KiB blocks (page granularity).
* '''G:''' 粒度(Granularity )标志,指示'''Limit'''值的缩放大小。 如果清 ('''0'''),则 '''Limit''' 以1字节块为单位 (字节粒度)。 如果设('''1'''),'''Limit'''单位是4KiB块(页面粒度)。
* '''Sz:''' Size flag. If clear ('''0'''), the descriptor defines a 16-bit protected mode segment. If set ('''1''') it defines a 32-bit protected mode segment. A GDT can have both 16-bit and 32-bit selectors at once.
* '''DB:''' Size flag. 如果清('''0'''),则描述符定义一个16位保护模式段。 如果设 ('''1'''),它定义了一个32位受保护的模式段。 GDT可以同时具有16位和32位选择器。
* '''L:''' Long-mode code flag. If set ('''1'''), the descriptor defines a 64-bit code segment. When set, '''Sz''' should always be clear. For any other type of segment (other code types or any data segment), it should be clear ('''0''').
* '''L:''' Long-mode code flag. 如果设('''1'''),则描述符定义64位代码段。 设1时,'''Sz''' 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该是清('''0''')。
 
==系统段描述符==
 
对于系统段,例如定义 '''[[Task State Segment|任务状态段]]''' 或 '''[[Local Descriptor Table|本地描述符表]]''' 的系统段, '''Access Byte'''的格式略有不同,以便定义不同类型的系统段,而不是代码段和数据段。
 
有关详细信息,请参阅《英特尔软件开发人员手册》,'''Section 3.5: System Descriptor Types'''和'''Section 3.5: System Descriptor Types'''。
 
{| class="wikitable"
|+ Access Byte
|-
!style="width: 12.5%;"|7
!style="width: 12.5%;"|6
!style="width: 12.5%;"|5
!style="width: 12.5%;"|4
!style="width: 12.5%;"|3
!style="width: 12.5%;"|2
!style="width: 12.5%;"|1
!style="width: 12.5%;"|0
|-
|'''P'''&nbsp;&nbsp;&nbsp; ||colspan=2|'''DPL''' || '''S''' || colspan=4|'''Type'''
|}
 
* '''Type:''' 系统段的类型。
 
32位保护模式下可用的类型:
* '''0x1:''' 16-bit TSS (Available)
* '''0x2:''' LDT
* '''0x3:''' 16-bit TSS (Busy)
* '''0x9:''' 32-bit TSS (Available)
* '''0xB:''' 32-bit TSS (Available)
 
长模式下可用的类型:
* '''0x2:''' LDT
* '''0x9:''' 64-bit TSS (Available)
* '''0xB:''' 64-bit TSS (Available)
 
==长模式系统段描述符==
 
对于'''[[Long Mode]]'''中的'''[[Task State Segment]]'''或'''[[Local Descriptor Table]]'''。 '''Segment Descriptor'''的格式不同,以确保 '''Base''' 值可以包含64位 '''[[Linear Address|线性地址]]'''。 它占用了两个常用条目表中的空间,采用了一种小端格式,因此该条目的下半部分在表中的上半部分之前。
 
有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的'''Section 7.2.3: TSS Descriptor in 64-bit Mode'''和'''Figure 7-4: Format of TSS and LDT Descriptors in 64-bit Mode'''。
 
{| class="wikitable" style="display: inline-table;"
|+ 64-bit System Segment Descriptor
|-
!colspan=5 style="text-align: left;"|127 &nbsp;&nbsp;<span style="float: right;">96</span>
|-
|colspan=5|Reserved
|-
!colspan=5 style="text-align: left;"|95 &nbsp;&nbsp;<span style="float: right;">64</span>
|-
|colspan=5|'''Base'''<br>63&nbsp;&nbsp;&nbsp;<span style="float: right;">32</span>
|-
!style="width: 20%; text-align: left;"|63&nbsp;&nbsp;&nbsp;<span style="float: right;">56</span>
!style="width: 12.5%; text-align: left;"|55&nbsp;&nbsp;&nbsp;<span style="float: right;">52</span>
!style="width: 12.5%; text-align: left;"|51&nbsp;&nbsp;&nbsp;<span style="float: right;">48</span>
!style="width: 25%; text-align: left;"|47&nbsp;&nbsp;&nbsp;<span style="float: right;">40</span>
!style="width: 25%; text-align: left;"|39&nbsp;&nbsp;&nbsp;<span style="float: right;">32</span>
|-
|'''Base'''<br>31&nbsp;&nbsp;&nbsp;<span style="float: right;">24</span>
|'''Flags'''<br>3&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|'''Limit'''<br>19&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
|'''Access Byte'''<br>7&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|'''Base'''<br>23&nbsp;&nbsp;&nbsp;<span style="float: right;">16</span>
|-
!colspan=3 style="text-align: left;"|31 &nbsp;&nbsp;<span style="float: right;">16</span>
!colspan=2 style="text-align: left;"|15 &nbsp;&nbsp;<span style="float: right;">0</span>
|-
|colspan=3|'''Base'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|colspan=2|'''Limit'''<br>15&nbsp;&nbsp;&nbsp;<span style="float: right;">0</span>
|}


== 另见 ==
== 另见 ==
=== 文章 ===
===文章===
* [[GDT Tutorial]]
* [[GDT Tutorial|GDT教程]]
* [[Getting to Ring 3]]
*[[Getting to Ring 3|到达Ring 3]]
* [[Segmentation]]
*[[Segmentation|段]]
* http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler
* http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler


=== 外部参照 ===
===外部参照===


* [http://files.osdev.org/mirrors/geezer/os/pm.htm Protected Mode tutorial]
* [http://files.osdev.org/mirrors/geezer/os/pm.htm Protected Mode tutorial]
* [http://www.intel.com/design/processor/manuals/253668.pdf Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A:. System Programming Guide, Part 1 (order number 253668)] chapter 2.4[[Category:X86 CPU]]
* [http://www.intel.com/design/processor/manuals/253668.pdf Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A:. System Programming Guide, Part 1 (order number 253668)] chapter 2.4[[Category:X86 CPU]]
  [[de:Global Descriptor Table]]
[[de:Global Descriptor Table]]

2022年3月6日 (日) 14:13的版本

全局描述符表Global Descriptor Table - GDT)是特定于IA-32x86-64体系结构的二进制数据结构。 它包含告诉CPU有关内存分段的条目。 还存在一个类似的 中断描述符表(Interrupt Descriptor Table),其中包含 任务中断 描述符。

建议阅读GDT教程

GDTR寄存器

GDTGDTR寄存器中的值指向。 这是使用LGDT汇编指令加载的,该指令的参数是指向GDT描述符结构的指针:

GDT Descriptor (GDTR)
79 (64-bit mode)
48 (32-bit mode)   16
15   0
Offset
63 (64-bit mode)
31 (32-bit mode)   0
Size

15   0
  • Size: 表的大小(以字节为单位)减去1。 之所以发生这种减法,是因为 size 的最大值是65535的,而GDT的长度最多可达65536个字节 (8192个条目)。 此外,gdt不可以具有0字节的大小。
  • Offset: GDT的线性地址(不是物理地址,分页适用)。

请注意,LGDT加载的数据量在32位和64位模式中不同,偏移量在32位模式中为4字节长,在64位模式中为8字节长。

有关更多信息,请参阅《英特尔软件开发人员手册》 (第3-A卷) 的 Section 2.4.1: Global Descriptor Table Register (GDTR)Figure 2-6: Memory Management Registers

表说明

GDT中的条目长度为8字节,形成如下表格:

Global Descriptor Table
地址 内容
GDTR Offset + 0 Null
GDTR Offset + 8 Entry 1
GDTR Offset + 16 Entry 2
GDTR Offset + 24 Entry 3
... ...

GDT (条目0) 中的第一个条目应始终为null,并应使用后续条目。

表中的条目由段选择器(Segment Selectors)访问,这些条目通过汇编指令或硬件功能(如中断)加载到寄存器中。

段描述符(Segment Descriptor)

表中的每个条目都有一个复杂的结构:

Segment Descriptor
63   56 55   52 51   48 47   40 39   32
Base
31   24
Flags
3   0
Limit
19   16
Access Byte
7   0
Base
23   16
31   16 15   0
Base
15   0
Limit
15   0
  • Base: 一个32位的值,包含段开始的线性地址。
  • Limit: 20位值告诉最大可寻址单元,以1字节为单位,或以4KiB页为单位。 因此,如果选择页面粒度并将 Limit 值设置为0xFFFFF,则该段将在32位模式下跨越整个4 GiB地址空间。

在64位模式下,忽略BaseLimit值,每个描述符覆盖整个线性地址空间,不管它们设置为什么。

有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 3.4.5: Segment DescriptorsFigure 3-8: Segment Descriptor

Access Byte
7 6 5 4 3 2 1 0
P DPL S E DC RW A
  • P: 当前位。 允许条目引用有效段。 必须为任何有效段设(1)。
  • DPL: 描述符特权级别字段。 包含段的 CPU特权级别 0 =最高权限(内核),3 = 最低权限(用户应用程序)。
  • S: 描述符类型位。 如果清 (0),则描述符定义一个系统段 (例如 任务状态段-Task State Segment)。 如果设(1),则定义代码或数据段。
  • E: Executable bit. 如果清(0),则描述符定义数据段。 如果设(1),它定义了一个可以从中执行的代码段。
  • DC: Direction bit/Conforming bit.
    • 对于数据选择器: Direction bit。 如果清(0),则该段将向上增长。 如果设(1)段向下增长,即Offset必须大于Limit
    • 对于代码选择器:Conforming bit。
      • If Clear(0)该段中的代码只能从Privl中设置的Ring执行。
      • 如果设(1),此段可以从相等或较低的特权级别执行代码。 例如,Ring3中的代码可以跳转到Ring2段中的conforming代码。 Privl字段表示允许执行该段的最高权限级别。 例如,Ring0中的代码不能far-jump到 Privl 为2的conforming代码段,而ring2和ring中的代码可以。 请注意,特权级别保持不变,即在跳转后,从Ring3到Privl为2的段的far-jump仍保留在Ring3中。
  • RW: 可读位/可写位。
    • 对于代码段:可读位。 如果清(0),则不允许对此段进行读取访问。 如果设(1),则允许读取访问。 永远不允许对代码段进行写访问。
    • 对于数据段:可写位。 如果清 (0),则不允许对此段进行写访问。 如果设(1),则允许写访问。 数据段始终允许读取访问。
  • A: Accessed bit. 最好清(0),CPU将在访问段时设它为1。
Flags
3 2 1 0
G DB L Reserved
  • G: 粒度(Granularity )标志,指示Limit值的缩放大小。 如果清 (0),则 Limit 以1字节块为单位 (字节粒度)。 如果设(1),Limit单位是4KiB块(页面粒度)。
  • DB: Size flag. 如果清(0),则描述符定义一个16位保护模式段。 如果设 (1),它定义了一个32位受保护的模式段。 GDT可以同时具有16位和32位选择器。
  • L: Long-mode code flag. 如果设(1),则描述符定义64位代码段。 设1时,Sz 应始终清0。 对于任何其他类型的段(其他代码类型或任何数据段),它应该是清(0)。

系统段描述符

对于系统段,例如定义 任务状态段本地描述符表 的系统段, Access Byte的格式略有不同,以便定义不同类型的系统段,而不是代码段和数据段。

有关详细信息,请参阅《英特尔软件开发人员手册》,Section 3.5: System Descriptor TypesSection 3.5: System Descriptor Types

Access Byte
7 6 5 4 3 2 1 0
P    DPL S Type
  • Type: 系统段的类型。

32位保护模式下可用的类型:

  • 0x1: 16-bit TSS (Available)
  • 0x2: LDT
  • 0x3: 16-bit TSS (Busy)
  • 0x9: 32-bit TSS (Available)
  • 0xB: 32-bit TSS (Available)

长模式下可用的类型:

  • 0x2: LDT
  • 0x9: 64-bit TSS (Available)
  • 0xB: 64-bit TSS (Available)

长模式系统段描述符

对于Long Mode中的Task State SegmentLocal Descriptor TableSegment Descriptor的格式不同,以确保 Base 值可以包含64位 线性地址。 它占用了两个常用条目表中的空间,采用了一种小端格式,因此该条目的下半部分在表中的上半部分之前。

有关详细信息,请参阅《英特尔软件开发人员手册》,第3-A卷的Section 7.2.3: TSS Descriptor in 64-bit ModeFigure 7-4: Format of TSS and LDT Descriptors in 64-bit Mode

64-bit System Segment Descriptor
127   96
Reserved
95   64
Base
63   32
63   56 55   52 51   48 47   40 39   32
Base
31   24
Flags
3   0
Limit
19   16
Access Byte
7   0
Base
23   16
31   16 15   0
Base
15   0
Limit
15   0

另见

文章

外部参照

de:Global Descriptor Table