18-线性地址转换实验

概述

上一篇介绍了有关页的概念,以及线性地址转换物理地址过程。受于篇幅限制,抱歉我把实验部分放在了这里。如果你觉得上一篇看完还是晕晕的,那这里的实验希望你能好好做一下。

实验内容很简单,用 malloc 申请一段内存,然后往这段内存写点数据,顺便查看下申请的这段内存的地址是多少,接着,中断到 WinDbg 中,使用线性地址转换方法,找到这个线性地址对应的物理地址,并验证这段物理地址中保存的数据就是你在程序中写入的。

实验代码

// 文件名:LinearAddr.cpp
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    char buf[] = "hello world! I'm in linear address convertion experiment!";
    char *p = (char*)malloc(strlen(buf)+1);
    strcpy(p, buf);
    printf("%s\n", p);
    printf("%08x\n", p);
    getchar();
    free(p);
    return 0;
}

实验步骤

  • 编译并运行

在虚拟机中编译以上代码,运行。这时候会在 getchar()处停下来,然后不要回车,在 WinDbg 中中断下来。


这里写图片描述
图1 运行,然后中断到 WinDbg

  • 转换线性地址

图1中看到的线性地址是 003729a0,按照10-10-12拆分,得到的值是 0000 0000 00—-11 0111 0010—-1001 1010 0000 即000-372-9a0. 以后,我会把这种拆分后的地址称为三段式结构。

  • 其中第一段是一级页表索引号,它的值是 0,一级页表英文简称是 PDT
  • 第二段是二级页表索引号,它的值是 372(注意这是16进制),二级页表的简称是 PTT。
  • 第三段是普通页的页内偏移。

首先我们需要知道 PDT 的基址。在 WinDbg 中使用 !process 0 0查看。


这里写图片描述
图2 使用 !process 0 0 查看DirBase

然后一直找到最后一个位置,LinearAddr.exe 进程。见图3.

这里写图片描述
图3 进程 LinearAddr.exe 的页目录基址是 19656000

所以 PDT=0x19656000.

接下来,就是查找 PDT[0] 的值。因为每个元素大小是4字节,PDT[0] 的值就是地址 PDT + 0*4 处的值。


这里写图片描述
图4 查看 PDT[0] 的值

我们知道,一级页表 PDT 中的每个元素存储了二级页表的编号,那么这里看到的二级页表编号是否就是 1410d067 呢?还记得我说过吗,页表编号只需要用 20 bit 来存储,想起来了吗?

页表中的每个元素的高20位是用来存储页表编号的,所以这里二级页表的编号应该是 1410d,后面的 067 只是 1410d 号页面的属性。根据运算规则,可以计算出二级页表的基址为 1410d000(因为每个页大小是 4KB)。

故有 PTT=1410d000.

然后我们拿着线性地址的第二段,它是一个索引号,它的值是16进制0x372. 所以我们需要去查看 PTT[0x372] 是多少。因为每个元素的大小是4字节,所以PTT[0x372]的值就是地址PTT+0x372*4处的值。


这里写图片描述
图5 查看 PTT[372] 的值

最终我们得到 PTT[0x372]=0736c067,依据规则,我们得到该保存的页面编号的值是 0736c。于是计算得到这个页的页基址是 0736c000,这只是一个普通页,用来保存数据的。

我们还有线性地址的第 3 段没有使用,它记录了普通页的页内偏移值。所以,最终的物理地址就是 0736c000+9a0 = 0736c9a0

在WinDbg中使用命令!db 0736c9a0就可以按字节方式查看该地址存储的数据。


这里写图片描述
图6 查看最终的物理地址处的数据

如果最后你能看到右侧有 hello world! I'm in ...的字样,恭喜你,完成了该实验。

总结

本篇使用 WinDbg + VM 虚拟机双机调试,实现手工线性地址转换实验,以加深对10-10-12线性地址转换的理解。

实验中使用了 !process 0 0查看进程的页目录基址,每个进程都有属于自己的页目录基址,当CPU执行某个进程的时候,就会把这个进程的页目录基址加载的 CR3 寄存器,因为每个进程的页目录基址都不一样,所以使用的一套页目录页表也是不同的。这也就是为什么不同进程之间的地址空间是隔离的。

如果你感兴趣的话,可以尝试着修改一个进程的页表,来修改另一个进程空间地址的值。甚至,你可以读写地址为0的内存单元的值。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值