0x01 2-9-9-12分页
前面我们说过,通过10-10-12的分页方式,物理地址最多可达4G(1024 x 1024 x 4kb),但众所周知,随着硬件的发展,4G内存已经无法满足要求了。所以1996年Inter设计了新的分页方式,即 2-9-9-12分页,又被称为 PAE(物理地址扩展)分页。
2-9-9-12分页原理
- 页的大小是确定的,4KB不能随便改,所以32位的最后一部分就确定为了12位。
- 如果想增大物理内存的访问范围,就需要增大PTE,增大了多少呢?考虑对齐的因素,将原来的4个字节增加到8个字节
- 由于PTE增大了,而PTT表的大小没变,依然是4KB,所以每张PTT表能放的PTE个数由原来的1024个减少到512个,512等于2的9次方,因此PTI=9
- 由于2的9次方个PDE就能找到所有的PTT表,因此PDI=9
- 与10-10-12不同,CR3不直接指向PDT表,而是指向一张新的表,叫做PDPT表(页目录指针表)。PDPT表中的每一个成员叫做PDPTE(Page-Directory-Point-Table Entry,页目录指针表项),每项占8个字节。因为PDPT表只有4个成员,因为2位比特位只能满足四种情况:00 01 10 11
PDPTE(Page-Directory-Point-Table Entry,页目录指针表项)
结构图:
P位:第0位,有效位
Avail:这部分供操作系统软件随意使用,CPU不使用
Base Addr:指向PDT表地址,由两部分组成
第一部分:高四字节32~35位
第二部分:低4字节12~31位
这两部分加起来共24位,后12位补0
灰色部分:保留位
PDE(Page-Directory Entry,页目录表项)
每个2-9-9-12分页机制下的PDE占8字节,其结构图如下:
PAT位:页属性表
只有当PS=1时,PAT位才是有意义的(页属性表只针对页)
其他属性位的含义在上面学习PDPTE时或在学习10-10-12分页的PDE与PTE时已经介绍,这里不再详述
PTE(Page-Table Entry,页表项)
每个2-9-9-12分页机制下的PTE占8字节,其结构图如下:
- PTE中12~35位是物理页基址,低12位补0
- 物理页基址+12位页内偏移指向具体数据
XD/NX标志位
PAE分页模式下,PDE与PTE的最高位为XD/NX位。即PDE/PTE的最高位,在Intel中称为XD,AMD中称为NX,即No Execution。
我们平常所说,一个数据段具有 读、写、执行三种权限,而对于一个物理页,只有 读和写 两种权限。那如果攻击者通过一些恶意的构造以执行的方式运行了某段数据,那就会造成一些不可预期的情况。比如,RET的时候使EIP跳到了某段数据上,程序就会将这段数据当作代码来执行了,如果这段数据由攻击者恶意构造,这就是任意代码执行的漏洞了,同样的,SQL注入本质上也是将一段不正常的数据当作代码执行导致的。
为了解决这样的问题,从而出现了一种硬件保护技术,我们通常称其为NX保护(堆栈不可执行保护),这个保护机制就是通过在PDE/PTE上设置了一个不可执行位 – XD/NX位。若是XD/NX位被置为1时,这个物理页上的数据就不可以被当作代码来执行,就算通过溢出使EIP跳至这页内存,执行的时候也会自动将这个程序crash掉。
0x02 TLB(Translation Lookaside Buffer, 转译后备缓冲器)
通过前面对分页机制的学习,我们可以知道,当程序通过一个线性地址比如 MOV EAX,[0x12345678] 访问一个物理页时,其并不是只读取了四个字节,而是要通过先读PDE、再读PTE、最后通过PTE找到物理页上的数据,若是PAE分页基址则前面还要多读一次PDPTE。通过多次的中转,虽然解决了大物理地址的寻址问题,但是同样也大大降低了访问效率。
为了解决这样一个问题,设计师们想到了用一种缓存的方式来对线性地址与其对应的物理地址做记录。他们在CPU内部做了一张表,用来记录这些东西。它的效率和寄存器一样快,名字叫做TLB(Translation Lookaside Buffer),其被翻译为转译后备缓冲器,也被翻译为页表缓存、转址旁路缓存。因为TLB追求极致的效率,所以它的存储容量很小,只能存少则几十条,多则也只有上百条。
TLB结构
TLB结构如下:
ATTR:属性
在10-10-12分页模式下:ATTR = PDE属性 & PTE属性
在2-9-9-12分页模式下:ATTR = PDPTE属性 & PDE属性 & PTE属性
LRU:统计信息
由于TLB的大小有限,因此当TLB被写满、又有新的地址即将写入时,TLB就会根据统计信息来判断哪些地址是不常用的,从而将不常用的记录从TLB中移除。
注意:
- 不同的CPU,TLB大小不同
- 只要Cr3发生变化,TLB立即刷新,一核一套TLB。但一些新式的CPU并不会全清TLB,比如有的使用ASN(address space number,地址空间号码)标记,只有匹配当前工作的 ASN 的 TLB 条目才会被视为有效
- 所以PDE和PTE中有个G标志位(当PDE为大页时,G标志位才起作用),如果G位为1,刷新TLB时将不会刷新PDE/PTE
- G位为1的页,当TLB写满时,CPU根据统计信息将不常用的地址废弃,保留最常用的地址
TLB种类
TLB在X86体系的CPU中的实际应用最早是从Intel的486CPU开始的,在X86体系的CPU中,一般都设有如下4组TLB:
- 第一组:缓存一般页表(4K字节页面)的指令页表缓存(Instruction-TLB);
- 第二组:缓存一般页表(4K字节页面)的数据页表缓存(Data-TLB);
- 第三组:缓存大尺寸页表(2M/4M字节页面)的指令页表缓存(Instruction-TLB);
- 第四组:缓存大尺寸页表(2M/4M字节页面)的数据页表缓存(Data-TLB)