【保护模式】x64下定位随机页表基址的思路
# 前言
昨天在看周哥讲 x64 内核的时候,得知了 windows10 的某个版本开始,页表基址不再固定了。
今天晚上突然有了个思路,就动手把他敲出来了,这种思路是不是已经烂大街了我也不确定,就当发出来学习交流吧。
# 随机页表基址原理
这里用 x86 的 10-10-12 分页举例吧,比较好理解,理解了 x64 的也差不多的
启用了保护模式和分页机制后,咱就不能直接访问物理地址了,都会被 MMU 当作虚拟地址进行转换。
但是 cr3 存的又是物理地址,不能直接操作页表了,那咋办呢?
聪明的前辈们,选择在页目录表中选择一项 (共 1024 项,每一项 4 字节),使其存储的物理地址与页目录表的基址 (cr3) 相同,这样子就可以构造一个访问页表的虚拟地址了,大概就是让 cpu 在地址转换的过程中绕圈圈。
画个图吧
# 定位思路
x64 也必然是随机选择 PXT 的其中一项 PXE 来存储 PXT 的物理地址,实现的随机页表基址
那么就可以通过构造所有可能指向 PXT 的虚拟地址 (共 512 项),转换为物理地址,再与 cr3 比较,最终得到正确的 PXT 基址。
只要知 ...
【动手写ToyLang】5.四则表达式解析与运算
# 准备冻手
理论讲那么多,想必大家也犯困了,马上就到冻手环节了,本节我们会实现一个支持括号的四则表达式编译器 & AST 解释器,用以验证我们所学习的知识。
# EBNF 文法
这里把本节代码所参考的 EBNF 文法贴上。
1234567exp = addexpaddexp = mulexp {oper2 mulexp}oper2 = '+' | '-'mulexp = parenexp {oper1 parenexp}oper1 = '*' | '/'parenexp = '(' addexp ')' | numexpnumexp = number
我们在上节文法的基础上稍作修改,支持了括号。
# AST
在编写语法分析器之前,我们需要先定义好每个 AST 节点 (符号) 的结构。
\ToyLang\ast\exp.h
123456789101112131 ...
【动手写ToyLang】4.递归下降
# 递归下降
先前用于描述的加减运算表达式的文法,实际上并不能直接通过递归下降分析法来解析。
说了这么多,递归下降到底是个什么玩意呢?
接下来我们通过以下能够应用递归下降进行解析的文法来解析输入串,了解其解析过程,读者大概就明白了。
1234block = '{' {stat} '}'stat = assignExp ';'assignExp = ident '=' valuevalue = number | string
{stat} 表示重复 stat ,此处表示可以有 0~n 个 stat 。
其中, ident 是标识符, number 、 string 是字面量,我们都会放到词法分析中去解析,故不在此列出其文法。
首先,假设 block 输入串为:
1234{ a = 1; b = "qwq";}
以下是解析的伪代码:
# 解析 block
1234567func ParseBl ...
【动手写ToyLang】3.语法分析
# 语法分析
按照传统的编译原理教材讲述的编译器结构, 词法分析阶段 之后,便是 语法分析阶段 。
以下摘自百度百科:
语法分析是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如 “程序”,“语句”,“表达式” 等等。语法分析程序判断源程序在结构上是否正确。源程序的结构由上下文无关文法描述。语法分析程序可以用 YACC 等工具自动生成。
简而言之,语法分析即要求完成对输入串是否能符合语言文法规定的检查。
关于文法的定义,参照下文。
# 语法分析器
我们需要实现的是语法分析器。
语法分析器的主要工作就是接收词法分析器输出的 Token,产出抽象语法树。
本意我是不想讲太多学科中严谨定义的内容,一个是不好懂,容易劝退;一个是我个人的理解也有限。
所以本系列文章就只简单提及我认为的 ToyLang 开发过程中必要的东西。
# 文法
这里还是请出百度百科:
文法是一个汉语词汇,读音为 wén fǎ ,即文章的书写法规,一般用来指以文字、词语、短句、句子的编排而组成的完整语句和文章的合理性组织。
学习编译原理的过程中,确实会有许多概念难以理解。
...
【动手写ToyLang】2.词法分析
# 词法分析
词法分析是整个编译器结构中最简单的一个阶段,所以放轻松,咱们往下看。
那么,词法分析是什么呢?
我们知道,程序开发者编写的源代码,也就是编译器最初能够接收到的输入,即连续的字符序列。
词法分析存在的意义,就是提前将源代码切分成能被后续编译程序直接使用的单词序列。
如源代码中的变量标识,关键字,字符串字面量,数值字面量等…
我们上一节课所展示的算术表达式, 3 + 2 ,也是先将其分成 3 + 2 三个节点,才能用于构成抽象语法树。
词法分析器产出的单词序列,我们将其称为 Token 。
# 输入四则运算表达式,产出 Token
我们既然需要将四则运算表达式转成 Token ,也就需要知道其单词序列的规则,当然,关于这一点,我们早已烂熟于心了。
以下是我通过正则表达式描述的 Token 匹配规则 (以我们将要开发的词法分析器为准)。
TokenType
Regex
Eof
\0
Number
\d+
OpAdd
+
OpSub
-
OpMul
*
OpDiv
/
SepLParen
(
SepRParen
)
...
【动手写ToyLang】1.从四则运算表达式开始
# 由此开始
如果你曾经接触过《编译原理》的话,不知道是否与我有着同样的困惑呢?
各种不近人情的名词,公式乱飞,这让我学习起来格外痛苦。
我在阅读过不少文章、书籍,并且尝试敲下一些代码之后,才逐渐理解了一些较为关键的东西。
实际上,当我真正完成了对四则运算表达式的解析的那一刻,我才真切感受到了编译原理的优雅与美妙之处,这大概就是由人类智慧的伟大之处吧 (偏得有点远了)。
因此,我才会选择先从四则运算表达式开始,将其逐步扩展成为一门 通用编程语言 ,也能让读者每一节都能感受到学习有所反馈的喜悦。
# 初尝构思
现在,我来尝试给你出一道题吧,请你用你所熟悉的语言,编写一个模块:
输入符合四则运算表达式规范的字符串 (可以假定只有整数,不存在括号);
输出整型结果;
要求关键逻辑由自己实现,不可借由库、语言本身提供的功能。
你能实现吗?
是否觉得脑子有些空白,难以组织成较为优雅的实现思路呢?
如果你现在就能想到很棒的解法,那至少你要比我厉害多了。
我曾经因为某些需求做过尝试,虽然最后写出来了,但是具体实现也非常丑陋,这里就不献丑了。
但是我可以给你大致描述一下我当初的思路:
首先 ...
【动手写ToyLang】0.前言
# 关于
本系列文章会手把手教你打造一门玩具通用编程语言。
计算机本身就是一门需要动手的学科,在对基本原理有一定程度的理解之后,自己动手实践才是学习的最好捷径,为此制造 "玩具",并不丢人。
我对《编译原理》这门学科的学习程度也十分有限,因此本系列文章的读者不仅仅是你们,也包括我,写下的这篇文章也是支撑我继续动手实践的动力。
学完本系列文章之后,基本上可以对编译原理有所认知,再继续往下学习也就不会那么困难了。
我会尽可能保证文章内容的准确,若还是难以避免的出现了错误,望批评指正,感激不尽。
# 准备工作
# 开发语言
这里笔者选用个人较为常用的 C++ 作为开发语言,风格尽量以《Google C++ Style Guide》为准,在我个人能力范围内尽量写得 "现代 C++" 一点。
另外,笔者对 C++ 的理解也较为浅薄,代码写得不好,还请理解。
# 开发环境
笔者基本上只在 Windows 下进行开发工作,因此选择自然是 Visual Studio ,读者可以自由选择自己喜欢的开发环境。
# 项目地址
最后,笔者已经将完整的项目代码放到了 ...
【Proxifier】基本配置与使用
# Proxifier
Proxifier 是为其他不支持指定代理服务器的应用进行强制代理的工具。
其原理 (大致) 是在内核层面通过驱动过滤的形式实现的网络控制。
# 下载
官方网站
http://www.proxifier.com/
应用本身是收费的,有能力请支持正版软件。
# 配置与使用
# 准备工作
这里使用 Fiddler 这个软件来担任代理服务器的工作。
启动 Fiddler 后,请先关闭 Windows 系统代理
我们需要使用浏览器来测试强制代理,但是 Fiddler 会自动开启系统代理。
并且浏览器默认会使用系统代理。
# 启动界面
# 配置代理服务器
工具栏 -> Profile -> Proxy Servers…
添加代理服务器
选择否
点击 OK
依然选择否
# 配置代理规则
工具栏 -> Profile -> Proxification Rules…
添加代理规则,保持与我一致即可。
添加了一条代理规则 chrome 并启用。
这里说明 ...
【Proxifier】基本配置与使用
# Proxifier
Proxifier 是为其他不支持指定代理服务器的应用进行强制代理的工具。
其原理 (大致) 是在内核层面通过驱动过滤的形式实现的网络控制。
# 下载
官方网站
http://www.proxifier.com/
应用本身是收费的,有能力请支持正版软件。
# 配置与使用
# 准备工作
这里使用 Fiddler 这个软件来担任代理服务器的工作。
启动 Fiddler 后,请先关闭 Windows 系统代理
我们需要使用浏览器来测试强制代理,但是 Fiddler 会自动开启系统代理。
并且浏览器默认会使用系统代理。
# 启动界面
# 配置代理服务器
工具栏 -> Profile -> Proxy Servers…
添加代理服务器
选择否
点击 OK
依然选择否
# 配置代理规则
工具栏 -> Profile -> Proxification Rules…
添加代理规则,保持与我一致即可。
添加了一条代理规则 chrome 并启用。
这里说明 ...
【MFC】视图与文档
# 视图
# 视图窗口简述
在 MFC 的设计中,图形的显示的这部分工作,交由 视图窗口 负责。
框架窗口则担容器之任,成为菜单、标题栏、视图窗口等窗口的容身之所,通常不直接在其客户区中绘制。
视图窗口就被设计为一个没有标题栏,只有客户区的窗口,通常覆盖在框架窗口的客户区上。
# CView
在 MFC 中,视图窗口对应的类即 CView ,继承自 CWnd ;
# CView::OnDraw
CView 中声明了一个纯虚函数 CView::OnDraw ,因此继承必须重写这个函数,用于处理绘制消息;
这个函数是由 CView::OnPanit 调用的。
# 使用视图窗口
代码示例
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include <afxwin.h>#include <afxext.h>class CMyView : pub ...