目录项和页表项

i386中为的地址映射
逻辑地址经过段映射为线性地址, 再经页映射到物理地址.
线性地址结构
这个结构可以用下图表示:
线性地址结构
目录项中含有指向一个页面表的指针, 页页面表中含有指向一个页面起始地址的指针. 每个目录项和页表项都是以4字节(32位机器)的长度存储的数据. 由于页面表和页面的起始地址都总是在4K字节的边界上, 这些指针的低12位都永远是0. 这样, 在目录项和页面表中都只要有20位的指针就够了, 余下的12位则可以用于控制或其他的目的.

为了方便理解这里copy了浅谈地址映射原理与举例分析中的例子. 若线性地址为,
0000 1000 0000 0100 1000 0101 0110 1000

高10位是0000 1000 00, 也就是32, 所以i386CPU就以32位下标去页面目录中找目录项. 这个目录项中的高20位指向一个页面表. 找到页面表后, CPU再来看线性地址的中间10位, 为 0001001000, 即十进制的72, 于是CPU就以此为下标在已经找到的页表中找到相应的表项. 这时这个线性地址的最低12位为0X568, 所以如果目标页面的起始地址为0X740000的话 (具体取决于内核中的动态分配), 那么物理地址就是0X740568.

其实段映射完全没必要存在, 只是i386为了兼容之前的16位段寄存器的, 不得不在采取段式地址映射来实现其"保护模式", 虽然只用页式管理就能实现更加有效和高效的"保护模式"下的内存地址映射, 事实上ARM等处理器就只有页式管理.

待续: 内存管理中的地址映射演变, 从实模式到保护模式

任务描述 本关任务:分析版本 0 内核的第一次缺故障,回答下列问题: 1.该故障由几进程引发? 2.在该故障发生前,该进程执行的最后一个可执行文件是什么?该可执行文件的第 2 块(每块 1KB )的头 16 字节的内容是什么? 3.引发该故障的线性地址是什么?该进程的代码段起始地址是多少? 4.该故障处理前,该线性地址对应的目录的地址值分别是什么? 5.该故障处理时,申请到的空闲帧的起始地址是什么?该帧的头 16 字节的内容是什么? 6.该故障处理过程中、读入硬盘数据后,上述帧的头 16 字节的内容是什么? 7.该故障处理过程中、修改对应的页表后,上述线性地址对应的页表的值是什么? 相关知识 为了完成本关任务,你需要掌握: 1.如何跟踪到缺故障的发生; 2.如何跟踪可执行文件的执行; 3.如何显示 bochs 虚拟机硬盘中某个可执行文件的内容; 4.在 gdb 中如何知道引发缺故障的线性地址是多少; 5.函数 do_no_page 的处理过程是怎样的; 6.在 gdb 中如何查看当前进程的(用户)代码段的起始地址; 7.如何分析线性地址空间到物理地址空间的映射关系; 8.如何计算一个线性地址对应的物理地址; 9.如何计算一个线性地址的高 10 位中间 10 位的值; 10.目录页表的格式是什么; 11.如何查看某个目录的值; 12.在 gdb 调试时,如何知道某帧的头 16 字节的内容。 实验准备 本关卡使用版本 0 内核进行分析,内核文件为 ~/os/linux-0.11-lab/0 。 如何跟踪到缺故障的发生 在 Linux 0.11 中,故障有两种类型:缺故障写保护(访问权限异常)故障,分别由函数 do_no_page do_wp_page 处理: 因此,只需在函数 do_no_page 处设置断点,即可跟踪缺故障的发生。 如何跟踪可执行文件的执行 可执行文件的执行是通过系统调用 execve 完成的,其实现函数 sys_execve 会调用 C 函数 do_execve ,因此只需在后者处设置断点即可: 具体执行的文件名放在参数 filename 中,该参数来自用户空间,为了在调试时都能准确显示其值,可以在显示时加上用户数据段起始地址(与用户代码段起始地址相同): 如何显示 bochs 虚拟机硬盘中某个可执行文件的内容 可以用版本 0 内核启动 bochs 虚拟机,然后使用 hexdump 命令查看: 显示画面如下: 其中第二块(假设每块占 1KB )的头 16 字节的内容是 8b 44 24 08 a3 00 a0 00 e8 00 0e 00 00 00 6a 00 。 在 gdb 中如何知道引发缺故障的线性地址是多少 该地址记录在函数 do_no_page 的参数 address 中: 函数 do_no_page 的处理过程是怎样的 如果面是零,则字节分配一个空闲帧并初始化为全零;如果面来自于当前进程的可执行文件,则会分配空闲帧、读入硬盘上的可执行文件数据、修改页表: 在 gdb 中如何查看当前进程的(用户)代码段的起始地址 数据段的起始地址与代码段相同,只是会实际使用段内的不同区域。 如何分析线性地址空间到物理地址空间的映射关系 首先分析目录中的每个有效的目录,找到所有二级页表的首地址;然后分析每一个二级页表,查看其中有效的页表,计算出面与帧之间的对应关系。最后的映射关系类似描述如下: 线性地址区间 物理地址区间 0x00000000-0x00ffffff -> 0x00000000-0x00ffffff 0x04000000-0x0409ffff -> 0x00000000-0x0009ffff 如何计算一个线性地址对应的物理地址 在 x86 CPU 中,如果启用了分地址转换机制,线性地址会通过目录页表被转换为物理地址,整体过程如下: 具体过程是,首先以线性地址的高 10 位为索引目录中找到对应的目录,然后以线性地址的中间 10 位为索引页表中找到对应的页表,最后将页表中的帧起始地址与线性地址的低 12 位(内偏移)相加,得到最后的物理地址。 如何计算一个线性地址的高 10 位中间 10 位的值 可以单独开一个终端来运行 gdb , 然后在其中进行计算: 上面显示线性地址 0x401fcac 的高 10 位为 16 ,中间 10 位为 31 。 目录页表的格式是什么 页表的格式如下: 可见,一个页表占 4 个字节,其中高20位是帧起始地址的高 20 位,在 x86 中
11-20
本关任务通过调试版本 1.3 内核回答问题: 1 进程第 1 次调用函数 output_char 时,它的 mynext 变量的物理地址是多少? 1 进程第 2 次调用函数 output_char 时,它的 mynext 变量的物理地址是多少? 相关知识 为了完成本关任务,你需要掌握: 1.如何查看 1 进程的函数调用 output_char() 所对应的汇编指令; 2.如何计算 1 进程的 mynext 变量的逻辑地址(段地址:段内偏移); 3.在 bochsdbg 中,如何查看一个逻辑地址处的值; 4.如何计算一个线性地址对应的物理地址; 5.如何查看 CR3 寄存器的值; 6.目录页表的格式是什么; 7.如何查看某个目录的值; 8.在 bochsdbg 中,如何直接查看某物理地址处的值; 9.如何计算一个线性地址的高 10 位中间 10 位的值。 环境准备 本关卡使用版本 1.3 内核进行分析,内核文件存放在/data/workspace/myshixun/exp1中。 如何查看 1 进程的函数调用 output_char() 所对应的汇编指令 1 进程在第 155 行调用了函数 output_char : 因此只需要先跟踪到第 155 行,然后反汇编即可看到对应的汇编指令,反汇编命令如下: 如何计算 1 进程的 mynext 变量的逻辑地址(段地址:段内偏移) 在跟踪到 1 进程的运行后,可以直接查看变量 mynext 所在的段内偏移: 其段地址默认存放在寄存器 ds 中。 在 bochsdbg 中,如何查看一个逻辑地址处的值 可以使用 x 命令直接查看,类似如下: 上图中,同时显示了逻辑地址 0x17:0x1fcac 对应的线性地址,即 0x401fcac 。 如何计算一个线性地址对应的物理地址 在 x86 CPU 中,如果启用了分地址转换机制,线性地址会通过目录页表被转换为物理地址,整体过程如下: 具体过程是,首先以线性地址的高 10 位为索引目录中找到对应的目录,然后以线性地址的中间 10 位为索引页表中找到对应的页表,最后将页表中的帧起始地址与线性地址的低 12 位(内偏移)相加,得到最后的物理地址。 如何查看 CR3 寄存器的值 在 bochsdbg 中使用 creg 命令即可: 目录页表的格式是什么 页表的格式如下: 可见,一个页表占 4 个字节,其中高20位是帧起始地址的高 20 位,在 x86 中帧的长度为 4KB ,帧起始地址的低 12 位都是 0 。 另外,页表的倒数第 2 位(位 1 )如果为 1 ,表示这个面可以写,否则只能读;倒数第 1 位(位 0 )如果为 1 ,表示这个面存在对应的帧,否则表示不存在对应的帧。 例如,如果某页表的值为: 则说明该对应的帧存在,其为 0x1 ,帧的起始地址为 0x1000 ,这个面只能读不能写。 目录的格式与页表类似。 如何查看某个目录的值 如果目录的起始地址为 0 ,则用以下命令可以显示前 4 个目录的值: 其中最后一个目录为 3 目录,其值为 0x00004027 ,目录从 0 开始编。 查看页表的方法与此类似。 在 bochsdbg 中,如何直接查看某物理地址处的值 可以使用 xp 命令: 与之不同的是,命令 x 用来显示某逻辑地址或线性地址处的值。 如何计算一个线性地址的高 10 位中间 10 位的值 可以单独开一个终端来运行 gdb , , 然后在其中进行计算: , 上面显示线性地址 0x401fcac 的高 10 位为 16 ,中间 10 位为 31 。 编程要 通过 gdb dbg 调试查找答案,将第一关的答案填写在/data/workspace/myshixun/第一关.txt中。 1 进程第 1 次调用函数 output_char 时,它的 mynext 变量的物理地址是多少? 1 进程第 2 次调用函数 output_char 时,它的 mynext 变量的物理地址是多少? 测试说明 平台会对你的操作进行检测,同时会对文档的内容进行检测。请完成操作并且填写文档内容之后再点击评测。
最新发布
12-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值