訪問內存以後,後面執行兩句代碼後;並不能保證剛纔訪問的代碼還在TLB中;有可能被刷新出去了;web
2萬次中有1次被淘汰;因爲訪問代碼不連續ide
// 7_TLB_test.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
DWORD g_out;
DWORD g_OldPte[2];
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
// 保存舊的pte ,以用來恢復pte 解決不藍屏
g_OldPte[0] = PTE(0x41c000)[0];
g_OldPte[1] = PTE(0x41c000)[1];
PTE(0x41c000)[0] = PTE(0x41d000)[0];// 不設置G位
PTE(0x41c000)[1] = PTE(0x41d000)[1];
__asm invlpg ds : [0x41c000] // 帶有 g 位的刷新;
// 刷新虛擬地址在TLB中
__asm
{
mov eax, ds: [0x41c000];// 這個時候到快表中了 TLB[0x41c000] 中的值因該是 1;
}
// pte 修改回來,可是TLB 中存在因此應該仍是 1
PTE(0x41c000)[0] = g_OldPte[0];
PTE(0x41c000)[1] = g_OldPte[1];
__asm
{
mov eax,ds:[0x41c000]
mov g_out,eax
} // 若是前面訪問以後還在快表中,那麼這裏應該是 [0x41d000] 中的 1;
// 若是再也不快表中了 那麼是修改回來的 ,原本的 [0x41c000] 中的 2;
/*__asm {
mov eax, cr3
mov cr3, eax
}*/
__asm invlpg ds : [0x41c000] // 帶有 g 位的刷新;
//// 調用調用;確保在 TL B 中
//__asm mov eax, ds:[0x41c000];
//// 恢復到原來的pte
////---- 這樣
//// 按道理 後面一旦後面刷新 TLB 將 普通 TLB 刷新出去,
//// 那麼 g_out = page2[0] 的值就 應該是 正常 的原 pte 對應的數據 -- 2。
//PTE(0x41c000)[0] = g_OldPte[0];
//PTE(0x41c000)[1] = g_OldPte[1];
//__asm
//{
//mov eax, cr3
//mov cr3, eax
//}
//g_out = page2[0]; // 講道理 在非G位下 應該是2(原PTE解析出的) -- 可是這裏咱們設置了PTE 的G位,
// // so 這裏應該是 TLB快表中 對應的 1;
__asm {
iretd
}
}
void _declspec(naked) go() {
{
pagel[0] = 1; //確保物理頁存在
page2[0] = 2;
}
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00~ 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
for (int i = 0; i < 200000; i++)
{
go();
if (g_out == 2)
{
printf("%d : %d ==== ",i, g_out);
printf("%d : %d\n", i, page2[0]); // 打印出來 仍是有小几率 不相同;說明仍是在快表中的。
}
}
system("pause");
}
我這裏循環了20000次 ,有1次G位即便在也被TLB淘汰了。函數
// 7_TLB_test.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
DWORD g_out;
DWORD g_OldPte[2];
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
// 保存舊的pte ,以用來恢復pte 解決不藍屏
g_OldPte[0] = PTE(0x41c000)[0];
g_OldPte[1] = PTE(0x41c000)[1];
PTE(0x41c000)[0] = PTE(0x41d000)[0]| 0x100;// 設置G位
PTE(0x41c000)[1] = PTE(0x41d000)[1];
__asm invlpg ds : [0x41c000] // 帶有 g 位的刷新;
// 刷新虛擬地址在TLB中
__asm
{
mov eax, ds: [0x41c000];// 這個時候到快表中了 TLB[0x41c000] 中的值因該是 1;
}
// pte 修改回來,可是TLB 中存在因此應該仍是 1
PTE(0x41c000)[0] = g_OldPte[0];
PTE(0x41c000)[1] = g_OldPte[1];
__asm
{
mov eax,ds:[0x41c000]
mov g_out,eax
} // 若是前面訪問以後還在快表中,那麼這裏應該是 [0x41d000] 中的 1;
// 若是再也不快表中了 那麼是修改回來的 ,原本的 [0x41c000] 中的 2;
//__asm invlpg ds : [0x41c000] // 帶有 g 位的刷新;即前面若是還在快表中,這裏刷新pte再返回3環程序後再次輸出。作測試用的沒有意義了。
__asm {
iretd
}
}
void _declspec(naked) go() {
{
pagel[0] = 1; //確保物理頁存在
page2[0] = 2;
}
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00~ 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
for (int i = 0; i < 20000; i++)
{
go();
if (g_out == 2)
{
printf("%d : %d ==== ",i, g_out);
printf("%d : %d\n", i, page2[0]); // 打印出來 仍是有小几率 不相同;說明仍是在快表中的。
}
}
system("pause");
}
總結: 注意啊 ::: 切換 cr3 刷新TLB G位的 無影響; 得 使用 測試
__asm invlpg ds : [0x41c000] // 無視 g 位的刷新;spa
前置知識 : 若是咱們的頁面沒有可執行屬性的話;在沒有TLB中時,咱們修改pte後,第一次訪問 絕對時修改pte以後的對應的物理頁數據;可是若是有可執行屬性,那麼在cpu 流水線 技術( 執行指令的時候,也在取指令,且根據將會執行的可能性提早取指令):orm
沒有 可執行屬性的時候;且沒有主動加入快表的時候;坑定 是可預計的數據:blog
可是 一旦加入了可執行屬性,流水線的預先取指令,可能執行到這兒,取後面的指令:ip
發現後面的指令有 0x405000 ,並且 0x405000 有可執行屬性,可能就預先取了這個指令;繼而訪問;加入了TLB。 (可是即便這樣這裏也是指令TLB ,可是這裏影響到了 數據TLB,可是機率也不高)內存
代碼:ci
DWORD g_out;
DWORD g_OldPte[2];
_declspec(allocate("data seg"))DWORD pagel[1024]; //41d000
_declspec(allocate("data seg"))DWORD page2[1024]; //41c000
//0x401000
void _declspec(naked) IdtEntry()
{
// 保存舊的pte ,以用來恢復pte 解決不藍屏
g_OldPte[0] = PTE(0x41c000)[0];
g_OldPte[1] = PTE(0x41c000)[1];
__asm{
mov eax,cr3
mov cr3,eax
}
//__asm mov eax, ds :[0x41b000]
PTE(0x41c000)[0] = PTE(0x41d000)[0];
PTE(0x41c000)[1] = PTE(0x41d000)[1];
__asm {
mov eax, ds :[0x41c000]
mov g_out, eax
}
PTE(0x41c000)[0] = g_OldPte[0];
PTE(0x41c000)[1] = g_OldPte[1];
_asm {
mov eax, cr3
mov cr3, eax
iretd
}
}
void _declspec(naked) go()
{
pagel[0] = 0xc3; //
page2[0] = 0xc390;
((void(*)())(DWORD)pagel)();
((void(*)())(DWORD)page2)();
__asm int 0x20
__asm ret
}
//eq 8003f500 0040ee00 00081000
void main()
{
if ((DWORD)IdtEntry != 0x401040)
{
printf("wrong addr: %p", IdtEntry);
exit(-1);
}
for (int i = 0; i < 10000; i++) {
go();
if (g_out != 0xc3)
printf("%d: %p\n",i, g_out);
}
system("pause");
}