实模式:
实模式简单来说就是16位模式(也有16位保护模式,但由于地址线的限制,实则都差不多),在16位模式下是使用20根地址线,可以寻址1MB内存,但又由于处理器内部的寄存器只有16位(以前的处理器),因此为了能访问整个1M内存,所以采用段地址+偏移地址的寻址方式(段地址*16+偏移地址)。
主要特点
1.内部寄存器为16位
2.最大寻址空间为1MB
3.可访问内存中的任意位置
保护模式:
保护模式是工作在32位模式下,具有32位的内部寄存器,以及32(or64)根地址线,最大访问空间为4GB内存,可以访问整个4G内存空间,但由于依然是在x86处理器的架构下,为了兼容,而依然采用段式寻址空间。
主要特点
1.内部寄存器有32位
2.最大寻址空间为4GB
3.段寄存器中保存段的选择子(不再是段基地址)
比较:
实模式和保护模式之间差别挺大的,保护模式运算能力、寻址能力都增强,但最大的差别还是保护模式的安全性能大大加强,而实模式下几乎没有安茜可讲,因为随便一个程序都可以自由访问内存中的任意空间,因此加强安全性能的方法莫过于对内存访问模式的改变:
内存访问模式:
本质上还是采用段+偏移的方法,
1.实模式
段寄存器(cs,ss,es,ds…)中存储的就是段基地址,可以没有限制的读写,也就是使用段寄存器时,就是直接用的里面存储的内容
2.描述符表
在来看保护模式之前,先来看一下描述符表:
描述符表就是描述符的集合,描述符存储的是段相关的信息,描述符统一的一个挨着一个的放在内存的一段空间中,这就构成了一个描述符表。
1.全局描述符表(GDT)是为整个软硬件系统服务的,必须在进入保护模式之前定义。
2.局部描述符表(LDT)是用户程序自己使用的,因此每个用户程序都有一个LDT,并且每个LDT在GDT中都有一个对应的描述符。
并且为了跟踪GDT,处理器内部专门有一个寄存器来负责:
1.全局描述符表寄存器(GDTR)
该寄存器称为全局描述表寄存器(GDTR),该寄存器为48位,分别是32位的基地址和16位的边界,
描述符边界也就是表的大小,最大为64KB,又由于一个描述符占8字节,因此最多可以定义8192个描述符。
2.描述符
P.S.上面一大堆参数,就简单介绍吧。。。
G=0:段界限以字节为单位;1:段界限以4KB为单位
D/B=0:指令中的偏移地址或者操作数是16位;1:32位
L=64位代码段标志
AVL=
P=0:段不在内存中;1段在内存中
DPL=描述符的特权级(0,1,2,3)
S=0:系统段;1:代码段或者数据段
TYPE=指示描述符的类别,有4位
对于数据段分别为(X,E,W,A)
| X | E | W | A | 描述符类别 | 含义 |
|---|---|---|---|---|---|
| 0 | 0 | 0 | x | 数据 | 只读 |
| 0 | 0 | 1 | x | 数据 | 读、写 |
| 0 | 1 | 0 | x | 数据 | 只读,向下扩展 |
| 0 | 1 | 1 | x | 数据 | 读、写,向下扩展 |
对于代码段分别为(X,C,R,A)
| X | C | R | A | 描述符类别 | 含义 |
|---|---|---|---|---|---|
| 1 | 0 | 0 | x | 代码 | 只执行 |
| 1 | 0 | 1 | x | 代码 | 执行、读 |
| 1 | 1 | 0 | x | 代码 | 只执行,依从的代码段 |
| 1 | 1 | 1 | x | 代码 | 执行、读,依从的代码段 |
3.安装段描述符并加载GDTR
;创建0#描述符,它是空描述符,这是处理器的要求
mov dword [bx+0x00],0x00
mov dword [bx+0x04],0x00
;创建#1描述符,保护模式下的代码段描述符
mov dword [bx+0x08],0x7c0001ff
mov dword [bx+0x0c],0x00409800
;创建#2描述符,保护模式下的数据段描述符(文本模式下的显示缓冲区)
mov dword [bx+0x10],0x8000ffff
mov dword [bx+0x14],0x0040920b
;创建#3描述符,保护模式下的堆栈段描述符
mov dword [bx+0x18],0x00007a00
mov dword [bx+0x1c],0x00409600
;初始化描述符表寄存器GDTR
mov word [cs: gdt_size+0x7c00],31 ;描述符表的界限(总字节数减一)
lgdt [cs: gdt_size+0x7c00];把从标号gdt_size开始的6字节加载到GDTR寄存器
局部描述符的安装类似,也是选取一块内存用于LDT存储局部描述符,然后使用lldt指令,加载到局部描述符表(LDT不需要空描述符)
;创建描述符
mov dword [...],0x...
mov dword [...],0x...
...
;初始化描述符表寄存器LDTR
mov word [...],...
lldt [...]
3.保护模式
段寄存器(cs,ss,es,ds,gs,fs)不再存储段基地址,而是段的选择子,而且段寄存器还包括一个不可见的部分,描述符高速缓冲器。
保护模式下访问模式:
1.每当引用一个段时,可理解为改变段地址内容的指令,如
jmp ...
;or
call ...
mov ax,...
mov ds,ax
调用该类指令时,会将段地址左移4位,并传送到描述符高速缓冲器,并且之后如没有改变段地址(调用上面一类的指令),访问该段寄存器时,便一直使用改地址。
2.要访问内存时,传送给段选择器(段寄存器)的内容不再是逻辑段地址(就是实模式中的直接可用的地址),而是段描述符在描述符表中的索引号。
传送给段选择器的段选择子如上图所示
由<描述符索引号(3~15)+TI(2)+RPL(0~3)>3部分组成:
1.描述符索引号:用于在描述符表中选择一个段描述符
2.TI:0:描述符在GDT(全局描述符表)中,1:描述符在LDT(局部描述符表)中
3.RPL:请求特权级
这里以2.描述表中创建的描述表为例,里面有4个描述符:
| 描述符名称 | 索引号 |
|---|---|
| 空描述符 | 0 |
| 代码段描述符 | 1 |
| 数据段描述符 | 2 |
| 堆栈段描述符 | 3 |
举个选择堆栈段的例子:
;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作
mov cx,00000000000_11_000B ;加载堆栈段选择子
mov ss,cx
上面的索引号就是0000000000011,也就是3
TI:0
RPL:0
3.最后在实际访问中,根据段描述符以及段选择子的信息,来决定这次访问是否合法,特别是特权级是否合法的问题。
P.S.关于保护模式下的内存访问,看完上面内容后,可配合保护模式下的内存访问一起看
总结
实模式和保护模式有很多不同,但是对于写代码来说,其实最大的影响就是32位下面的内存访问模式:
实模式:
随意访问,但是最大只能访问1MB内存
保护模式:
可以访问全部的4GB内存,但是受到限制,程序不能随意访问自身空间外的内存,因此保护模式比实模式安全。
#
最后上面的代码、图片引用自《x86汇编语言 从实模式到保护模式》里面的(还没写32位下的代码。。。借用一下)
本文对比了实模式和保护模式的主要特点,实模式下,16位处理器使用段地址+偏移地址寻址1MB内存,而保护模式提供32位内部寄存器和4GB最大寻址空间,通过描述符表实现更安全的内存访问,增强了系统安全性。

695

被折叠的 条评论
为什么被折叠?



