My first blog: GDT与基本描述符的结构

参考文章:Intel64 and IA32 Architectures Software Developer's Manual Volume 2 ~ 3

GDT(Global Descriptor Table,全局描述符表)是x86和amd64架构最最基本的数据结构,它存储在内存中,以GDTR记录基地址,是让电脑从实模式跳转到保护模式的台阶。在汇编代码中,我们可以用 lgdt [gdt_base] 来加载GDT到内存中。

GDT的结构是这样的:

GDTR.base->           _________________________      \

                     |________``````````_______|     |

                     |_________Items___________|     | <- GDTR.limit

                     |________``````````_______|     /

然后GDTR的结构是这样的:

79                                  16 15           0

|________________Base_________________|____Limit_____|

其实,它并没有这么高深,而只是一个表状结构而已。而里边的表项(描述符)则因为历史原因被分割得乱七八糟。

在实模式里,描述符(没此一说)就是个long-jmp pointer,如下所示。

31                    16 15                   0

|_________Base__________|________Limit________|

而在保护模式里,它分成了两类:段描述符和系统描述符

段描述符的格式如下:

63          56 55 54 53 52  51        48 47 46 45 44 43    40 39                                        16 15                    0

| Base(31:24) | G|DB| L|AVL|Limit(19:16)| P| DPL | S| Type   |_______________Base(23:0)___________________|________Limit(15:0)___|

Granularity-----^  ^  ^  ^                ^  ^     ^  ^

Default op size----'  |  |                |  |     |  |

Long mode-------------'  |                |  |     |  |

Available for developers-'                |  |     |  |

Present-----------------------------------'  |     |  |

Descriptor Privilege Level-------------------'     |  |

Is system descriptor-------------------------------'  |

Descriptor type: details under------------------------'

 

1 struct SEG_DESCRIPTOR
2 {
3     uint16_t Limit_Low;
4     uint16_t Base_Low;
5     uint8_t Base_Mid;
6     uint8_t Attr_Low;
7     uint8_t Attr_High__Lim_High;
8     uint8_t Base_High;
9 } __attribute__((packed));

 

 

 

Type字段和S字段指示了描述符的类型:S=0的情况暂不讨论。

3     2     1     0

-------------------

0:    E     W     A : Data Segment

-------------------

1:    C     R     A : Code Segment

当描述符是数据段时,Type.E表示Expand的方向,默认(0)为Expand-up;Type.W表示Writable,默认(0)表示Read-only;而Type.A表示Accessed,当描述符所表示的段被访问时,处理器会自动置这个字段为1。

当描述符是代码段时,Type.C表示Conforming,这个字段以后讨论;Type.R表示Readable,默认(0)表示不可读(只可执行);Type.A同上。

 

1 #define     DATA_Org      0x10
2 #define     DATA_W      0x12
3 #define     CODE_Org      0x18
4 #define     CODE_R      0x1A
5 #define     CODE_C      0x1C
6 #define     CODE_CR     0x1E

 

DPL字段是访问描述符需要的权限等级。这就是保护模式的意义所在之一。

P字段表示描述符是否存在。

AVL字段是留给开发者用的,不过我感觉实质上没什么用。

L字段和DB字段指示代码段的bits。如下:

L     DB

0       0 -->  16位,即实模式

0       1 -->  32位,即保护模式

1       0 -->  不合法(加载时跳#GP)

1       1 -->  64位,即长模式

G字段表示段的粒度,0表示1字节,1表示4KB。一般把G置1,limit设成0xFFFFF就是所谓的4GB Flat Segmentation,即平坦分段模式。

上述字段在保护模式都可用,然而到了长模式里,仅剩Type、S、DPL、P、L可用,其他一律忽略(除limit、DB、G全部位置1外,其他一律为0),统统变成Flat Mode,且limit再也不会检查了。因为在长模式里,分段内存管理变得次要,转而抬升为头等的是分页内存管理。这并不代表GDT的作用减弱。因为除了段描述符外,我们还有一大批系统描述符没讲。

 

本文到此结束。如有错误望指正。

附:汇编静态创建段描述符

 1 ; 1:Base 2:Limit 3:Attribute
 2 ; 所有参数按段描述符基地址设置。
 3 %macro SEGDESC 3
 4  dw %2 & 0xFFFF
 5  dw %1 & 0xFFFF
 6  db (%1 >> 16) & 0xFF
 7  db %3 & 0xFF
 8  db (%3 >> 8) & 0xF0 | (%2 >> 16) & 0xF
 9  db (%1 >> 24) & 0xFF
10 %endmacro

 动态创建段描述符

 1 ; rdi: 描述符基地址 esi:Base r8d:Limit r9w: Attr
 2 create_segdesc:
 3  mov [rdi], r8w
 4  mov [rdi + 16], si
 5  shr r8d, 16
 6  shr esi, 16
 7  mov [rdi + 32], si
 8  and r9w, 0F0FFh
 9  shl r8w, 8
10  or  r9w, r8w
11  mov [rdi + 40], r9w
12  and si, 0FF00h
13  and word [rdi + 48], 0FFh
14  or  [rdi + 48], si
15 ret

 

 

 

       

posted @ 2017-08-20 08:12  Js2xxx  阅读(827)  评论(0编辑  收藏  举报