全局描述符表GDT
全局描述符表主要是为了让计算机从实模式到保护模式.
在实模式下面访问的地址都是真实的物理地址, 这样的话每个程序都能直接的访问物理地址, 并修改物理地址会很容易的造成系统的崩溃, 死机. 所以为了让用户不能直接的访问物理地址创造了虚拟地址, 而让系统从物理地址映射到逻辑地址就是从实模式到保护模式的过程.(这里的物理地址就是线性地址, 主要因为只分段那么 物理地址=线性地址, 这里我就说是物理地址到逻辑地址之间的映射)
逻辑地址采用的分段的策略. 而让逻辑地址长度远多大于了物理地址的长度, 逻辑地址的由两段组成
[段选择(段选择子) : 段描述符]
[16位 : 32位]
每段选择是由16位组成, 段描述符是由32位组成, 由段选择子确定要访问哪个段描述符. 一个段描述符对应着一个进程, 也就是一个进程有一个唯一的段选择子对应. 段描述符有32位, 也就拥有2^32个地址, 也就是4G的地址范围啊, 正好是一个进程的运行内存的大小, 但是要注意不是进程一创建就会分配4G的内存, 不然我们电脑内存在大也运行不了几个进程, 进程的4G内存都是虚拟内存, 实际分配的大小是很小的, 直到进程认为自己的内存不足的时候才再申请更大的内存而已.
段选择和段描述符一共是48位的大小, 我们的寄存器根本没有这个位的, 怎么保存? 实际上GDT单独存放在GDTR特殊寄存器中, 低16位保存GDT大小, 高32位保存GDT在存储器中的位置. 它的结构体可设置为
typedef struct gdt_ptr_t
{
uint16_t limit;
uint32_t base;
}__attribute__((packed)) gdt_ptr_t;
GDT
表包含段描述符, 每个段32位(8个字节). 里面同时包含了段的访问权限. 所以是以4k进行对齐, 所以低3位都是为0, 而在分页机制中权限的判断就是在页的低3位进行判断., 可读写还是执行以及访问权限.
在NASM语法中每个GDT的信息的在另个结构体中存储
typedef struct gdt_entry_struct
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
}__attribute__((packed)) gpt_entry_struct;
GDT可以在内存的任何位置存放. 但是系统从实模式进入保护模式之前系统就应该要先为GDT分配内存, 而实模式是在1M一下的内存执行的, 那么GDT最初初始化并分配也就应该是在1M的空间中, 当开启保护模式后就可以在保护模式的地址空间内重新申请内存.
关于逻辑地址和线性地址以及GDT想了解的可以看一下我的另一篇博客地址空间