x64 结构体系下的内存寻址
欢迎转载,转载请注明出处:http://www.cnblogs.com/lanrenxinxin/p/4735027.html
在阅读NewBluePill源码的时候,看内存的那一块简直头疼,全是x64下的寻址,之前根本就没有接触过x64的内存寻址上的内容,看的晕头转向,决定先把x64下的寻址给弄明白了再回过头来看NewBluePill的源码,然后在网上一顿找,居然没有找到关于x64寻址的博客或者文章,简直痛苦啊,终于把x64的寻址问题弄清楚了,总结出来分享一下学习历程。
0x01 x64寻址简介
在保护模式,CPU发出的线性地址,内存管理单元(MMU),根据当前CR3寄存器所指向的页表物理地址将该线性地址翻译成物理地址进行内存访问,该过程称为地址翻译。
在x64体系结构中,线性地址的结构如图

在x64体系中只实现了48位的virtual address,高16位被用作符号扩展,这高16位要么全是0,要么全是1。
不同于x86体系结构,每级页表寻址长度变成9位,由于在x64体系结构中,普通页大小仍为4KB,然而数据却表示64位长,因此一个4KB页在x64体系结构下只能包含512项内容,所以为了保证页对齐和以页为单位的页表内容换入换出,在x64下每级页表寻址部分长度定位9位。
为了正确翻译x64的线性地址,其页表也从x86的2级变成了4级,翻译过程如图所示,在x64体系结构中,每级页表包含512项(2^9)下级目录的指针,该指针称为页表项,描述了存储下级

- PML4T(Page Map Level4 Table)及表内的PML4E结构,每个表为4K,内含512个PML4E结构,每个8字节
- PDPT (Page Directory Pointer Table)及表内的PDPTE结构,每个表4K,内含512个PDPTE结构,每个8字节
- PDT (Page Directory Table) 及表内的PDE结构,每个表4K,内含512个PDE结构,每个8字节
- PT(Page Table)及表内额PTE结构,每个表4K,内含512个PTE结构,每个8字节。
每个table entry 的结构都是8个字节64位宽,而virtual address中每个索引值都是9位,因此每个table都是512 x 8 = 4K字节。
0x02 页转换模型
X64,准确的说应该是IA32e paging 模型提供了三种页转换模型,
① 4K页面的转换表结构;
② 2M 页面的转换结构;
③ 1G页面的转换结构;
在64位模式下,处理器将48的虚拟地址转化为物理地址,在兼容模式下,转化32位的虚拟地址。

三种模型都是物理页帧的基地址加上页偏移得到物理地址,不同只是在于页帧的大小划分不同:
①4K页面: 使用PML4T,PDPT,PDT和PT 四级页转化表结构;
②2M页面:使用PML4T,PDPT 和PDT三级页转化表结构;
③1G 页面:使用PML4T和PDPT二级页表转化结构。
而在这里我们主要讨论的是4K页面大小的寻址方式,因为在个人计算机上,普遍都是4K
页面寻址,其他的方式也主要就是页面大小的差异。
0x03 最大物理地址
在Intel中使用MAXPHYADDR来表示最大的物理地址,我们可以通过CPUID的指令来获得处理支持的最大物理地址,然而这已经不在此次的讨论范围之内,我们需要知道的只是:
当MAXPHYADDR 为36位,在Intel平台的桌面处理器上普遍实现了36位的最高物理地址值,也就是我们普通的个人计算机,可寻址64G空间;
当MAXPHYADDR 为40位,在Inter的服务器产品和AMD 的平台上普遍实现40位的最高物理地址,可寻址达1TB;
当MAXPHYADDR为52位,这是x64体系结构描述最高实现值,目前尚未有处理器实现。
而对下级表的物理地址的存储4K页面寻址遵循如下规则:
① 当MAXPHYADDR为52位时,上一级table entry的12~51位提供下一级table物理基地址的高40位,低12位补零,达到基地址在4K边界对齐;
② 当MAXPHYADDR为40位时,上一级table entry的12~39位提供下一级table物理基地址的高28位,此时40~51是保留位,必须置0,低12位补零,达到基地址在4K边界对齐;
③ 当MAXPHYADDR为36位时,上一级table entry的12~35位提供下一级table物理基地址的高24位,此时36~51是保留位,必须置0,低12位补零,达到基地址在4K边界对齐。
0x04 实际转化
l CR3
当CR4.PCIDE = 0时,CR3的结构如图,

CR3可以使用64位宽,但是它表示的PML4T的物理基地址同样受到之前所说的MAXPHYADDR的约束,图示的只是理想的MAXPHYADDR为52位时的情况。
而当CR4.PCIDE = 1的时:

R3的低12位提供一个PCID值,用来定义当前Process Context ID.
当对CR3进行更新时,CR3第63位决定是否需要处理器的TLB和paging-struct cache,这不在我们此次谈论的范围之内。
l PML4E
接着再看PML4E的结构,如图:

PML4E并没有PS标志位,因此第7位是保留的,而PML4E提供的PDPT的物理基地址也受之前的MAXPHYADDR规则的约束。
l PDPTE
然后就是PDPTE结构:
由于新增了1G 页面,因此在PDPTE结构里将控制1G的页面转化,由PDPTE.PS标志位进行转换,如图:

当PDPTE.PS=1,也就是PDPTE的第7位为1时,PDPTE将提供1G的物理页面地址;当PDPTE.PS=0,也就是PDPTE的第7位为0时,使用非1G的页面,将提供下一级的PDT的物理基地址,同样受MAXPHYADDR规则的约束。
1G页面下的PDPTE 的结构解析如下:

同样地,PDPTE提供的1G页面的物理地址也遵守MAXPHYADDR的规则,1G页面的地址低30将补0,意味着1G边界上对齐。
4K和2M页面下的PDPTE结构解析如下:

将提供下一级PDT的物理基地址,同样也遵循MAXPHYADDR规则,那么再根据PDE.PS再决定是使用2M页面还是4K页面。
l PDE
PDE的结构和PDPTE类似,也是用PS(第7位)表示是使用2M的页面还是4K 的页面,下面是2M 页面的PDE结构解析:

同样对于页面的物理基地址也遵循MAXPHYAD原则。
接下来是4K 页面的 PDE 结构解析:

也遵循MAXPHYADDR 规则。
l PTE
PTE的结构解析:

同样遵循MAXPHYADDR规则。
0x05 实际例子
上面写了很多都是原理性的东西,可能看完之后对于x64还没有很清晰的认识,我们以一个很简单的例子来加深对于x64结构体系的寻址的认识。
#include "stdafx.h"
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
char szName[] = "HelloWorld";
printf("szName:%x\n",szName);
getchar();
return ; }
很简单的一个程序,就是打印出szName的虚拟地址,运行结果如下:

我们接下来要做的就是将0x2ffde8这个虚拟地址转换成物理地址,在物理页上找到我们的”HelloWorld”。
0x2ffde8 ===> 转换二进制:
000000000 000 0000 00 00 0000 001 0 1111 1111 1101 1110 1000
0 0 1 0xff 0xde8
PML4E索引 PDPTE索引 PDE索引 PTE索引 页内偏移

目标进程的DirBase为0x7d838000,根据我们之前学习的寻址方式,应该是按照MAXPHYADDR为36位的规则,即上一级table entry的12~35位提供下一级table物理基地址的高24位,此时36~51是保留位,必须置0,低12位补零。

因为PML4E的索引为0,所以我们的目标PML4E项的值为0x02b00000~7d274867,
12~35位为0x07d274,低12位补零,则:

PDPTE的索引也为0,目标PDPTE项的值为 0x03000000~7d737867,
PS位(第7位)为0,12~35位为 0x 07d737 ,低12位补零,则:

因为PDE的索引为1,所以我们要加上8,目标PDE项的值为 :0x01500000~7d7bb867
PS位(第7位)为0,12~35位为 0x07d7bb,低12位补零,则:

PTE的索引为0xff,所以要加上0xff*8,得到目标PTE项的值为:0x89a00000~7d084867
12~35位为 0x07d084,低12补零,得到页面物理基地址,再加上页面偏移,我们是0xde8,则:

终于在物理页上看到了我们熟悉的“HelloWorld”。
x64 结构体系下的内存寻址的更多相关文章
- X64下MmIsAddressValid的逆向及内存寻址解析
标 题: [原创]X64下MmIsAddressValid的逆向及内存寻址解析 作 者: 普通朋友 时 间: 2015-10-21,20:03:52 链 接: http://bbs.pediy.com ...
- Linux内存寻址之分页机制
在上一篇文章Linux内存寻址之分段机制中,我们了解逻辑地址通过分段机制转换为线性地址的过程.下面,我们就来看看更加重要和复杂的分页机制. 分页机制在段机制之后进行,以完成线性—物理地址的转换过程.段 ...
- Linux内存寻址之分段机制
前言 最近在学习Linux内核,读到<深入理解Linux内核>的内存寻址一章.原本以为自己对分段分页机制已经理解了,结果发现其实是一知半解.于是,查找了很多资料,最终理顺了内存寻址的知识. ...
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
- Linux内核源码分析 day01——内存寻址
前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...
- Linux内存寻址之分段机制及分页机制【转】
前言 本文涉及的硬件平台是X86,如果是其他平台的话,如ARM,是会使用到MMU,但是没有使用到分段机制: 最近在学习Linux内核,读到<深入理解Linux内核>的内存寻址一章.原本以为 ...
- NHibernate从入门到精通系列——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
- WebAssembly学习(四):AssemblyScript - 结构体系与内置函数
一.结构体系 1.编译 编译器的结构相对保守. 提供源文件,其文本被标记化并解析为抽象语法树. 这里执行语法级检查. 一旦解析了所有引用的源文件,就构造一个程序并从AST初始化. 在这里进行合理性检查 ...
- 浅谈 JVM 结构体系、类加载、JDK JRE JVM 三者的关系
一.java类,创建.编译.到运行的工程: 1.随便建一个Java类,保存后就是一个.java文件, 2.然后我们使用 javac命令编译 .java文件,生产 .class文件. 3.再然后使用 j ...
随机推荐
- 开发移动app与服务器端session的状态管理与交互
我们进行web开发的时候,一般使用cookie或session来保存用户的登录状态,通过检查cookie或session的数据来验证用户是否具有对某些需要登录的页面的访问权限,这一切都是通过浏览器来完 ...
- 获得N位数字字母随机组合
import string import random def get_rand(n): allw = string.letters+string.digits r = [] for i in ran ...
- iOS 第三方开源库----->AFNetworking
AFNetworking AFNetworking是一个为 iOS 和 Mac OSX 制作的令人愉快的网络库,它建立在URL 装载系统框架的顶层,内置在Cocoa里,扩展了强有力的高级网络抽象.它 ...
- iOS开发的22个奇谲巧技
结合自身的实践开发经验总结出了22个iOS开发的小技巧,以非常欢乐的语调轻松解决开发过程中所遇到的各种苦逼难题,光读着便已忍俊不禁. 1. TableView不显示没内容的Cell怎么办? 类似于图1 ...
- [转]IP_ADD_MEMBERSHIP : 组播错误 的解决方法:
[转]IP_ADD_MEMBERSHIP : 组播错误 的解决方法: http://www.cnitblog.com/dvb-dvb/archive/2012/10/15/aa.html by def ...
- perl连接mysql(转载)
文章来源:http://blog.sina.com.cn/s/blog_9d0445d50101czsr.html 首先需要用ppm安装DBI和DBD-mysql ,如果没有的话点击EDIT-pref ...
- Linux C 文件与目录2 文件的打开与关闭
文件的打开与关闭 open和close 文件的打开指的是从磁盘中找到一个文件,返回一个整形的打开文件顺序的编号.打开的文件处于可读.可写状态.文件的关闭指的是释放打开的文件,是文件处于不可读写的状态. ...
- 最小二乘法(least squares method)
一.背景 号到北大去听hulu的讲座<推荐系统和计算广告在视频行业应用>,想到能见到传说中的项亮大神,特地拿了本<推荐系统实践>求签名.讲座开始,主讲人先问了下哪些同学有机器学 ...
- android开发 解决启动页空白或黑屏问题
遇到的情况: app启动时进入启动页时出现白屏页,然后大概一秒之后就出现了背景图片. 原因:app启动时加载的是windows背景,之后再加载布局文件的,所以开始的黑屏/白屏就是windows的背景颜 ...
- android开发 图片合成
private static Bitmap compositeImages(Bitmap srcBitmap,Bitmap dstBitmap){ Bitmap bmp = null; //下面这个B ...