1 前面做的实验起始有缺陷

访问内存之后,后面执行两句代码后;并不能保证刚才访问的代码还在TLB中;有可能被刷新出去了;

实验验证缺陷:

代码 不连续 TLB 被淘汰:

2万次中有1次被淘汰;由于访问代码不连续

代码:

// 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
DWORD g_OldPte[2];
#pragma section("data seg", read, write)
_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");
}

G位即使存在 访问代码不连续也可能被淘汰:

我这里循环了20000次 ,有1次G位即使在也被TLB淘汰了。

代码:

// 7_TLB_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
DWORD g_OldPte[2];
#pragma section("data seg", read, write)
_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 位的刷新;

3 流水线指令TLB 和数据TLB 得相互影响

前置知识 : 如果我们的页面没有可执行属性的话;在没有TLB中时,我们修改pte后,第一次访问 绝对时修改pte之后的对应的物理页数据;但是如果有可执行属性,那么在cpu 流水线 技术( 执行指令的时候,也在取指令,且根据将会执行的可能性提前取指令):

现象:

没有 可执行属性的时候;且没有主动加入快表的时候;坑定 是可预计的数据:

但是 一旦加入了可执行属性,流水线的预先取指令,可能执行到这儿,取后面的指令:

发现后面的指令有 0x405000 ,而且 0x405000 有可执行属性,可能就预先取了这个指令;继而访问;加入了TLB。 (但是即使这样这里也是指令TLB ,但是这里影响到了 数据TLB,但是概率也不高)

代码:

#include "pch.h"
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>

#define PTE(x) ( (DWORD*)(0xc0000000 + ((x >> 12) << 3)))
#define PDE(X) ( (DWORD*)(0xc0600000 + ((x >> 21) << 3)))
DWORD g_out;
DWORD g_OldPte[2];
#pragma section("data seg", read, write)
_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");
}

16_TLB与流水线的更多相关文章

  1. CI-持续集成(1)-软件工业“流水线”概述

    CI-持续集成(1)-软件工业“流水线”概述 1   概述 持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次, ...

  2. 【GoLang】golang 的精髓--流水线,对现实世界的完美模拟

    直接上代码: package main import ( "fmt" "runtime" "strconv" "sync" ...

  3. android so调试时遇到的坑 - arm流水线

    直接看下面这段ARM汇编: 此时运行到的代码为ADD R3,PC 此时看一下寄存器窗口的值: 按理来说执行完ADD R3,PC后的效果应该是R3=R3+PC ,R3=40A1D5C8 但是我们可以执行 ...

  4. 【转载】关于OpenGL的图形流水线

    本文转载自 http://blog.csdn.net/racehorse/article/details/6593719 GLSL教程 这是一些列来自lighthouse3d的GLSL教程,非常适合入 ...

  5. .Net中的并行编程-5.流水线模型实战

    自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了 ...

  6. Intel系列CPU的流水线技术的发展

    Intel系列CPU的流水线技术的发展 CPU(Central processing Unit),又称“微处理器(Microprocessor)”,是现代计算机的核心部件.对于PC而言,CPU的规格与 ...

  7. Verilog学习笔记设计和验证篇(一)...............总线和流水线

    总线 总线是运算部件之间数据流通的公共通道.在硬线逻辑构成的运算电路中只要电路的规模允许可以比较自由的确定总线的位宽,从而大大的提高数据流通的速度.各个运算部件和数据寄存器组可以通过带有控制端的三态门 ...

  8. ARM流水线关键技术分析与代码优化

    引 言    流水线技术通 过多个功能部件并行工作来缩短程序执行时间,提高处理器核的效率和吞吐率,从而成为微处理器设计中最为重要的技术之一.ARM7处理器核使用了典型三级流 水线的冯·诺伊曼结构,AR ...

  9. TMS320C54x系列DSP的CPU与外设——第8章 流水线

    第8章 流水线 本章描述了TMS320C54x DSP流水线的操作,列出了对不同寄存器操作时的流水线延迟周期.(对应英语原文第7章) 8.1 流水线操作 TMS320C54x DSP有一个6段的指令流 ...

随机推荐

  1. 2019-8-28-WPF-开发

    title author date CreateTime categories WPF 开发 lindexi 2019-8-28 11:3:39 +0800 2018-2-13 17:23:3 +08 ...

  2. shell脚本 set命令

  3. CodeForces - 337D 树形dp

    题意:一颗树上有且仅有一只恶魔,恶魔会污染距离它小于等于d的点,现在已经知道被污染的m个点,问恶魔在的可能结点的数量. 容易想到,要是一个点到(距离最远的两个点)的距离都小于等于d,那么这个点就有可能 ...

  4. nodejs模块——fs模块 WriteFile写入文件

    WriteFile写入文件 使用fs.writeFile(filename,data,[options],callback)写入内容到文件. 参数说明: filename String 文件名 dat ...

  5. JMeter 服务器监控插件环境配置

    1.工具准备: jmeter下载地址:(尽量下载老版本如apache-jmeter-2.11,其他的版本比较高,可能和jmeter-plugins不兼容) http://jmeter.apache.o ...

  6. CleanMyMac x如何关闭自动更新,CleanMyMac关闭自动更新的方法

    在众多Mac清理软件中,CleanMyMac x应该是大多数Mac用户的选择,因为它不仅可以帮助我们清理系统垃圾,还可以帮助我们彻底卸载Mac上不需要的应用程序.今天要给大家介绍的是CleanMyMa ...

  7. Yii2中GridView

    Yii2 GridView与dropdownList结合的用法 http://www.yiichina.com/tutorial/473 <?=$form->field($model, ' ...

  8. ORACLE动态sql在存储过程中出现表或视图不存在的解决方法

    Oracle动态sql在存储过程中出现表或视图不存在的解决方法 CREATE OR REPLACE PROCEDURE P_test is strsql varchar2(2000); BEGIN   ...

  9. stl+数论——1247D

    其实也不算很难想,每个元素质因子分解后的p^c的p和c用pair的形式存在每个元素vector里 要去前面找一个数使得所有指数相加是k的倍数,那么把vector里的所有c 模 k,然后去找前面互补的数 ...

  10. NX二次开发-基于MFC界面对话框与NX交互的开发

    打开VS2013 点击新建,选择MFC DLL 点击确定 点下一步 什么都不改,直接点完成 进来之后先编译一下,看是否编译成功 打开项目属性,更改这几处 $(UGII_BASE_DIR)\ugopen ...