Windows分段分页机制杂谈
Windows系统下的分段机制和分页机制一直以来困惑着我,我结合以前的博文加上最近看的一篇文章做一个小总结,以后如果有新的想法也会更新。
首先来了解下系统CPU的地址线 、数据线和工作模式:
CPU型号 | 地址线 | 数据线 | 工作模式 |
8086 | 20 | 16 | 实模式 |
80286 | 24 | 16 | 实模式、保护模式 |
80386 | 32 | 32 | 实模式、保护模式、虚拟8086模式 |
80486以及pentium | 32 | 32 | 实模式、保护模式、虚拟8086模式 |
实模式、虚拟8086模式和保护模式的286兼容模式一般采用16位寻址方式,保护模式中32位模式则是采用32位寻址方式。要了解Windows的分段和分页机制,必不可少的会接触到三个重要名词:逻辑地址(虚拟地址);线性地址;物理地址。下面摘自某网页的解释:
逻辑地址(Logical Address) 是指由程序产生的与段相关的偏移地址部分。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,cpu不进行自动地址转换);逻辑也就是在Intel 保护模式下程序执行代码段限长内的偏移地址(假定代码段、数据段如果完全一样)。应用程序员仅需与逻辑地址打交道,而分段和分页机制对您来说是完全透明的,仅由系统编程人员涉及。应用程序员虽然自己可以直接操作内存,那也只能在操作系统给你分配的内存段操作。
线性地址(Linear Address) 是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。
物理地址(Physical Address) 是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。
(这解释中有一点我有疑问,实模式中有分段部件,在实模式下,有1MB的寻址空间,它被分成了至多为64KB的段,没有分页部件,故线性地址即物理地址。如果有人清楚麻烦告知)
了解了这三个地址后,我们知道了Windows分段和分页机制存在的目的就是为了让逻辑地址通过分段和分页映射到物理内存中。接下来介绍32位保护模式下分段分页机制。
在介绍这些之前,首先要掌握部分微机接口的知识,在实模式和虚拟8086模式下段寄存器存放的是段基址,而在保护模式中存放的是选择符。
16位保护模式的全地址形式如下:
16位选择符 | 16位偏移值 |
逻辑地址即虚拟地址是由16位选择符中前14位与16位偏移量连接(非相加)而成,每段最长为64KB,每个任务空间可以达到1GB。
32位保护模式的全地址形式如下:
16位选择符 | 32位偏移值 |
逻辑地址是由16位选择符中14位与32位偏移量连接而成,每段最长为4GB,每个任务的最大工件可达64TB。
了解了逻辑地址的形成后,接下来就可以开始进行分段,也就是逻辑地址朝线性地址的转换:
上图中首先将32位偏移量与段寄存器中的选择符拼接成48位的地址。根据选择符中的TI标志位从GDT或者LDT中取出段基址、段限、属性。然后使用偏移量
与段基址相加,判断是否超过段限,这样就可以获得线性地址。
上图中则为非PAE机制分页中以4KB来分页的方式。将线性地址分成三个部分,从CR3寄存器中取出页目录表(Page Directory )的基址,取线性地址高10位为页目录号
通过这两个数据我们可以获得页表(Page Table)的基址,取线性地址中间10位可以获得页号,然后从页表中取出页的基址,与线性地址中剩余的12位计算得到物理地址
当然,上面的分页机制仅仅是分页机制中的一种,下面我将介绍非PAE机制下4MB的分页和PAE机制下的分页。(内容主要截取自看雪)
如果采用非PAE机制下的4KB分页,则PDE(Page Directory Entry)和PTE(Page Table Entry)的计算方式如下:
PDE = ((VA >> 22) << 2 ) & 0xffc + 0xc0300000;
PTE = ((VA >> 12) << 2 ) & 0x3FFFFC + 0xc0000000;
下面介绍PAE方式下的分页机制,同样分成两种不同大小的分页,分别为4K和2M:
在PAE模式下,PDE和PAE的计算方式如下:
PDE = ((lVirtualAddress>>21)<<3) & 0x3FF8 + 0xC0600000;
PTE = ((lVirtualAddress>>12)<<3) & 0x7FFFF8 + 0xC0000000;
转载于:https://www.cnblogs.com/liuconggang/archive/2013/01/22/2871972.html