TLB

admin 2024年2月15日23:55:03评论9 views字数 3742阅读12分28秒阅读模式

什么是TLB表

前面介绍了两种分页模式,本篇来介绍一下TLB,在说TLB之前,我们先来想象一个场景。

在我们日常工作中,如果指令大多数是:

mov eax,dword ptr ds:[0x12345001]

mov eax,dword prt ds:[0x12345666]

mov eax,dword prt ds:[0x12345777]

mov eax,dword prt ds:[0x12345888]

mov eax,dword prt ds:[0x12345fff]  ;读多个字节,这个时候就跨页了

以上只是举例了一些,如果只是正常寻址,以上指令每次都需要访问3次(10-10-12分页模式),PDE一次、PTE一次、物理页一次。当跨页时,那么我们次数就更多了,这样一直拆来拆去,是非常浪费资源的。尤其是上述都在一个物理页中,如果还需要每一个都拆的话,那么是非常不合理的。

因此,我们就需要有一张表,可以记录一些我们经常访问的一些线性地址与物理页直接的映射关系,这张表就叫TLB表。

TLB表是CPU内部的一张表。

TLB结构

LA(线性地址)

PA(物理地址)

ATTR(属性)

LRU(统计)

0x81010111

...

说明:

  • ATTR:属性是PDPE、PDE、PTE三个属性AND起来的,如果是10-10-12分页,那就是PDE and PTE

  • 不同CPU,这个表的大小不一样。

  • 只要CR3变了,TLB立马刷新,一核一套TLB

  • LA:只记录0x11111000,意思就是只记录线性地址,不记录偏移

操作系统的高2G映射基本不变,如果CR3改了,TLB刷新,重建高2G以上很浪费。所以PDE和PTE中有一个G标志位,如果G位为1,刷新TLB时,将不会刷新PDE/PTE的G位为1的页,当TLB满了,根据统计信息将不常用的地址废弃,最近最常用的保留

也就是说,TLB刷不刷新,与G位(第八位)是否为1有关,G = 1 ,不刷新。为全局页。

INVLPG指令的意义

用来删除全局页的,因为全局页刷新不了,只能删除。

TLB种类

TLB在X86体系的CPU里的实际应用最早是从Intel的486CPU开始的,在X86体系

的CPU里边,一般都设有如下4组TLB:

  • 第一组:缓存一般页表(4K字节页面)的指令页表缓存(Instruction-TLB);

  • 第二组:缓存一般页表(4K字节页面)的数据页表缓存(Data-TLB);

  • 第三组:缓存大尺寸页表(2M/4M字节页面)的指令页表缓存(Instruction-TLB);

  • 第四组:缓存大尺寸页表(2M/4M字节页面)的数据页表缓存(Data-TLB)

验证TLB的相关属性

1. 验证缓存的存在:

// TLB2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

int x = 0x1234;
DWORD y = 0;

PDWORD xPTE;
//00401020
void __declspec(naked) Test()
{
_asm
{
//int 3
mov eax,xPTE
mov eax,[eax]
mov dword ptr ds:[0xC0000000],eax //¸给地址0挂物理页
mov dword ptr ds:[0],0x1234
mov dword ptr ds:[0xC0000000],0x0234567 //修改地址0的物理页地址

mov eax,dword ptr ds:[0]
mov y,eax
retf
}
}


int main(int argc, char* argv[])
{
DWORD xAddr = (DWORD)&x;
printf("xAddr = %xn",xAddr);

xPTE = (PDWORD)(((xAddr >> 10) & 0x3FFFFC) + 0xC0000000);
printf("xPTE = %xn",xPTE);

char buff[6] = {0x44,0x33,0x22,0x11,0x48,0x00};
_asm
{
call fword ptr[buff] //
}
printf("hellon");
printf("y = %xn",y);
getchar();
return 0;
}

TLB

修改物理页后,值还是1234,所以,有缓存。

2. 验证CR3刷新,TLB清空

// TLB2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

int x = 0x1234;
DWORD y = 0;

PDWORD xPTE;
//00401020
void __declspec(naked) Test()
{
_asm
{
//int 3
mov eax,xPTE
mov eax,[eax]
mov dword ptr ds:[0xC0000000],eax //¸给地址0挂物理页
mov dword ptr ds:[0],0x1234
mov eax,cr3
mov cr3,eax
mov dword ptr ds:[0xC0000000],0x0234567 //修改地址0的物理页地址
mov eax,dword ptr ds:[0]
mov y,eax
retf
}
}


int main(int argc, char* argv[])
{
DWORD xAddr = (DWORD)&x;
printf("xAddr = %xn",xAddr);

xPTE = (PDWORD)(((xAddr >> 10) & 0x3FFFFC) + 0xC0000000);
printf("xPTE = %xn",xPTE);

char buff[6] = {0x44,0x33,0x22,0x11,0x48,0x00};
_asm
{
call fword ptr[buff] //
}
printf("hellon");
printf("y = %xn",y);
getchar();
return 0;
}

TLB

3. 验证全局页

// TLB2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

int x = 0x1234;
DWORD y = 0;

PDWORD xPTE;
//00401020
void __declspec(naked) Test()
{
_asm
{
//int 3
mov eax,xPTE
mov eax,[eax]
mov dword ptr ds:[0xC0000000],0x01234977 //9:1001 全局页
mov dword ptr ds:[0],0x1234
mov eax,cr3 //刷新TLB
mov cr3,eax //刷新TLB
mov dword ptr ds:[0xC0000000],0x0234567 //修改物理页
mov eax,dword ptr ds:[0]
mov y,eax
retf
}
}


int main(int argc, char* argv[])
{
DWORD xAddr = (DWORD)&x;
printf("xAddr = %xn",xAddr);

xPTE = (PDWORD)(((xAddr >> 10) & 0x3FFFFC) + 0xC0000000);
printf("xPTE = %xn",xPTE);

char buff[6] = {0x44,0x33,0x22,0x11,0x48,0x00};
_asm
{
call fword ptr[buff] //
}
printf("hellon");
printf("y = %xn",y);
getchar();
return 0;
}

TLB

未刷新

  • 验证INVLPG指令

// TLB2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>

int x = 0x1234;
DWORD y = 0;

PDWORD xPTE;
//00401020
void __declspec(naked) Test()
{
_asm
{
//int 3
mov eax,xPTE
mov eax,[eax]
mov dword ptr ds:[0xC0000000],0x01234977 //9:1001 全局页
mov dword ptr ds:[0],0x1234
INVLPG dword ptr ds:[0] //删除全局页
mov eax,cr3
mov cr3,eax
mov dword ptr ds:[0xC0000000],0x0234567 //修改物理页
mov eax,dword ptr ds:[0]
mov y,eax
retf
}
}


int main(int argc, char* argv[])
{
DWORD xAddr = (DWORD)&x;
printf("xAddr = %xn",xAddr);

xPTE = (PDWORD)(((xAddr >> 10) & 0x3FFFFC) + 0xC0000000);
printf("xPTE = %xn",xPTE);

char buff[6] = {0x44,0x33,0x22,0x11,0x48,0x00};
_asm
{
call fword ptr[buff] //
}
printf("hellon");
printf("y = %xn",y);
getchar();
return 0;
}

TLB

原文始发于微信公众号(loochSec):TLB

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月15日23:55:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   TLBhttp://cn-sec.com/archives/2164234.html

发表评论

匿名网友 填写信息