因为cpu在实模式下地址总线为20位,所以能访问到的内存在1M左右,为了能操作更多的内存,cpu生产商设计了保护模式,在此模式下总线地址可达32位,访问内存明显增加。
用保护模式来32位寻址的操作要用一个叫gdt的东西,这个gdt(Global Descriptor Table)叫全局描述表。我对它的理解是它像一个目录,每一条存着在内存里的一个段的头地址和这个段的大小。
这个段就理解为在内存中选取一小块,给它起个名字,那么他就是内存中的一个段了。
下边这个图更好描述
当然gdt在内存中的位置肯定要在实模式可以访问的范围内。
当要访问更大的地址的时候,要访问某个段就先访问该段在gdt中的条目,然后得到他的实际物理地址,启动保护模式的32位总线访问它。
move ax [0x5a1]
比方说实模式下想要把0x5a1位置的内存数据读到ax寄存器中那么用上边那个汇编语句就行,当然先把基地址寄存器设为0.
要是要访问5M位置的内存数据的话这种方式就行不通了,这时候要使用如下代码
[SECTION .gdt]
; 段基址 段界限 属性
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
LABEL_DESC_5M: Descriptor 0500000h, 0ffffh, DA_DRW
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
dd 0
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
Selector5M equ LABEL_DESC_5M - LABEL_GDT
mov bx, Selector5M ;用 es 指向5M内存描述符
mov es, bx
mov edi, 0
mov ax, [es:edi]
第一块代码是对gdt的一个编写,在这个表中给在内存5M位置的段起了个名字叫LABEL_DESC_5M,大小为0ffffh。我还写了其他的一些段,大家不要在意。
第二块代码就是使用了,其中Selector5M相当于LABEL_DESC_5M这个段在gdt这个表里是第几条,这里是第四条。把它通过bx寄存器传递给es寄存器。这个es寄存器就是专门来找gdt表中段的条目的。edi里的值是相对于5M这个位置的偏移,要是访问5M这个位置那么edi置为0,要是访问5M零1字节那么edi就置为1,以此类推,当然不能超过这个段的最大范围。然后最后一句话就是把5M位置的数据写入ax当中。
思考一下,若是用实模式的方法访问5M内存那么就是mov ax [0x500000],当然这个是运行不了的,寄存器和总线都不支持。
mov ax ,[es:edi]这句话可以看成mov ax [0x500000+0],他之所以能运行是因为这个[es:edi]引发了保护模式,应该是在es上寻址的话会启动保护模式读取gdt访问更大内存,这种实现是一种硬件实现。
总结为下面这个图