16_TLB与流水线
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与流水线的更多相关文章
- CI-持续集成(1)-软件工业“流水线”概述
CI-持续集成(1)-软件工业“流水线”概述 1 概述 持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次, ...
- 【GoLang】golang 的精髓--流水线,对现实世界的完美模拟
直接上代码: package main import ( "fmt" "runtime" "strconv" "sync" ...
- android so调试时遇到的坑 - arm流水线
直接看下面这段ARM汇编: 此时运行到的代码为ADD R3,PC 此时看一下寄存器窗口的值: 按理来说执行完ADD R3,PC后的效果应该是R3=R3+PC ,R3=40A1D5C8 但是我们可以执行 ...
- 【转载】关于OpenGL的图形流水线
本文转载自 http://blog.csdn.net/racehorse/article/details/6593719 GLSL教程 这是一些列来自lighthouse3d的GLSL教程,非常适合入 ...
- .Net中的并行编程-5.流水线模型实战
自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了 ...
- Intel系列CPU的流水线技术的发展
Intel系列CPU的流水线技术的发展 CPU(Central processing Unit),又称“微处理器(Microprocessor)”,是现代计算机的核心部件.对于PC而言,CPU的规格与 ...
- Verilog学习笔记设计和验证篇(一)...............总线和流水线
总线 总线是运算部件之间数据流通的公共通道.在硬线逻辑构成的运算电路中只要电路的规模允许可以比较自由的确定总线的位宽,从而大大的提高数据流通的速度.各个运算部件和数据寄存器组可以通过带有控制端的三态门 ...
- ARM流水线关键技术分析与代码优化
引 言 流水线技术通 过多个功能部件并行工作来缩短程序执行时间,提高处理器核的效率和吞吐率,从而成为微处理器设计中最为重要的技术之一.ARM7处理器核使用了典型三级流 水线的冯·诺伊曼结构,AR ...
- TMS320C54x系列DSP的CPU与外设——第8章 流水线
第8章 流水线 本章描述了TMS320C54x DSP流水线的操作,列出了对不同寄存器操作时的流水线延迟周期.(对应英语原文第7章) 8.1 流水线操作 TMS320C54x DSP有一个6段的指令流 ...
随机推荐
- 33-python基础-python3-列表插入元素-insert()方法-append()方法-extend()方法
1-insert()方法 insert()方法可以在列表任意下标处插入一个值. insert()方法的第一个参数是新值的下标,第二个参数是要插入的新值. 2-append()方法 调用 append( ...
- App加载主要流程
主要流程 Application OnCreate 加载第三方的sdk 加载自身的逻辑 发送远程数据请求 xxx.json 渲染界面 List
- C语言各种进制输出
#include<stdio.h> int main() { ; float f = 12.0; printf("十进制输出:%d\n", number); print ...
- sqlServer MERGE 对数据进行修改或插入自动视别 特别用于批量数据的插入或修改
sqlServer MERGE 对数据进行修改或插入自动视别 特别用于批量数据的插入或修改 MERGE customer AS targetTable --目标表 USING ( ...
- JS window对象 Location对象 location用于获取或设置窗体的URL,并且可以用于解析URL。 语法: location.[属性|方法]
Location对象 location用于获取或设置窗体的URL,并且可以用于解析URL. 语法: location.[属性|方法] location对象属性图示: location 对象属性: lo ...
- celery使用多队列
生产者: 文件1: 定义任务 #!/usr/bin/env python3 # coding: utf-8 from celery import Celery import settings pw = ...
- qt大小写字符串比较
https://blog.csdn.net/GraceLand525/article/details/48625593 Qt::CaseSensitivity cs = Qt::CaseInsensi ...
- 【LeetCode】贪心
[452] Minimum Number of Arrows to Burst Balloons [Medium] 给一堆线段,使用最少的arrow,穿过所有的线段.陈题,第一条线段的终点. Inpu ...
- 有穷自动机(NFA、DFA)&正规文法&正规式之间的相互转化构造方法
在编译原理(第三版清华大学出版社出版)中第三章的词法分析中,3.4.3.5.3.6小节中分别讲解了 1.什么是NFA(不确定的有穷自动机)和DFA(确定的有穷自动机) 2.如何将 不确定的有穷自动机 ...
- Vue学习笔记【7】——Vue指令之v-model和双向数据绑定
v-model是唯一可以实现双向数据绑定的vue指令 单向数据绑定:修改内存中的数据,页面上同步更改.v-bind <!-- v-bind 只能实现数据的单向绑定,从 M 自动绑定到 V, 无法 ...