## 跟踪地址翻译
调试进bochs,进linux0.11,编译运行test.c
查各项参数--- LDT表 | GDT表 | 线性地址 | 页表。 然后计算出 i 的物理地址,通过修改物理内存的方式让程序退出
- ./dbg-asm 调试启动
- c 继续执行
- 编译运行test.c, 死循环....
- crtl+c 暂停运行
- 在内核的话按c。如果不是cmp的话按n单步运行,知道 000f cmp出现
- u/7 从当前位置开始7条指令的反汇编代码
- 变量i保存在ds:0x3004这个地址,并不停地和0进行比较,直到它为0,才会跳出循环
- **开始寻找ds:0x3004对应的物理地址**
- ds:0x3004是虚拟地址, ds表明这个虚拟地址在ds段
- 首先要找到段表,然后通过ds的值在段表中找到ds段的具体信息,然后才能就行进行地址翻译
- 每个在IA-32上运行的应用程序都有一个段表,叫LDT,段的信息叫段描述符
- LDT存在于哪里?ldtr寄存器是线索的起点,通过他可以在GDT(全局描述符表)中找到LDT的物理地址
- sreg 找到ldtr的值 —— 0x0068,转化为二进制 0000000001101000 ,这个数字表示LDT存在在GDT表的 1101号位置,即13号位置——**参见段选择子
- 那GDT的位置在哪?就是上面执行sreg后gdtr的值,这里显示是0x00005cb8(实验指导书是0x00005cc8),这个地址是物理地址
- xp/32w 0x00005cb8 (xp /32w 0x00005cc8)可以查看从该地址开始。32个字的内容,及其GDT表的前16项
- GDT表的没项都是64位,8个字节。
- 之前我们知道LDT在GDT表的第13位(见上面,具体每位数据的参考意义见后文)。所以我们要查找的项的地址为: 0x00005cb8 + 13 * 8(xp/2w 0x00005cb8+13*8)。得到的值是0x00005d20: 0x92d00068 0x000082fa (0x00005d30 : 0xc2d00068 0x000082f9)
- 不知道计算出的对不对?执行sreg看ldtr那行的dl和dh有两点 dl=0x92d00068 dh=0x000082fa
- 组合一下 0x**92d0**0068 0x**00**0082**fa** 得到 **0x00fa92d0**(00f9c2d0). 这个就是LDT的物理地址(原因见后面的段描述符介绍)
- xp/8w 0x00fa92d0,显示LDT的前四项内容
```
[bochs]:
0x00fa92d0 <bogus+ 0>: 0x00000000 0x00000000 0x00000002 0x10c0fa00
0x00fa92e0 <bogus+ 16>: 0x00003fff 0x10c0f300 0x00000000 0x00faa000
```
- **段描述符的介绍**
- 在保护模式下,段寄存器有另外的一个名字,叫做段选择子
- 段选择子保存的主要内容是该段在段表里面的索引值
- 利用这个索引就能够从段表里面选择出相应的段描述符
- 简单例子
- sreg
- 看ds,之前是看了ldtr
- ds = 0x0017
- 段选择子是一个16位的寄存器
- 15-3 段描述符索引 2 T1 1-0 RPL (最上面的ldtr中的1101就是第一段——段描述符索引)
- RPL 是请求特权级,当访问一个段的时候,处理器要检查RPL和CPL(CPL 放在CS的位0 和位1中,用来表示当前代码的特权级)。即使程序由足够的特权级CPL来访问一个段,但是如果RPL(放在DS中,用来表示请求数据段)的特权级不够,仍然是不能够访问这个段。但是如果RPL的值大于CPL(值越大,权限越小),则用RPL的值覆盖CPL的值(应该可以理解为依据权最小的那个来决定能不能访问)。
- TI 是表指示标记,如果TI=0,则表示段描述符在GDT中,则会去GDT中查找;如果是1,则会去LDT中去查(最上面的是0,顺理成章在GDT中查~)
- 就上面ds的例子 0x0017 = 0000000000010111. RPL = 11,最低的特权级(很好理解,因为实在应用程序中执行)。 TI = 1, 表示在LDT中查找,查找谁? 10 = 2。。查找从LDT表中的第3个段描述符(在LDT中,从0开始编号)
- LDT和GDT差不多,都是每项占8个字节 所以第三项
- 找到了dl=0x00003fff, dh=0x10c0f300 。这样的话段描述符就是0x10000000
- 这个段描述符里面装的是什么?
- 一个64位的二进制数。存放段的基址和段限长等重要的数据
- 31-24 基地址 23 G 22 D/B 21 0 20 AVL 19-16段限长 15 P 14-13 DPL 12 S 11-8 TYPE 7-0 基地址
- 31-16 基地址 15-0段限长
- P(Present)是段是否存在的标记
- S用来表示 是系统段描述符(S=0)还是 代码或者数据段描述符(S=1
- TYPE 表示段的类型,比如数据段,代码段,可读,可写
- DPL是段的权限,和前面提到的CPLRPL一起使用
- G是粒度。G=0表示段限长以位为单位,G=1表示段限长以4KB为单位
- 段基址和线性地址
- 需要的其实是他,上面的例子中 0x10000000 ,这个就是ds段在线性地址空间的起始地址。基址?
- 段基址+偏移地址 = 线性地址
- ds:0x3004的线性地址: 0x10000000 + 0x3004 = 0x10003004
- calc ds:0x3004就可以验证了
- 页表
- 好像已经知道线性地址了,接下来我们需要计算的是物理地址了。这个过程中需要查找页表
- 线性地址: 页目录号+页表好+页内偏移。然后页目录表查也目录号,也表查页表号,和页内偏移加起来就是物理地址
- 需要算出线性地址中的页目录号,页表号,页内偏移
- 上面三者分别对应了32位线性地址的10位+10位+12位
- 0x10003004 的页目录号是64 页号3 页内偏移4
- IA-32架构下,页目录表的位置由CR3寄存器指引
- creg , 显示0, 说明页目录表的基址为0
- 看其他内容 xp/68w 0
- 看到的东西就是页目录表和页表中的内容 1024个32位(4K)
- 32位中的前20位是物理页框号,后面的是一些属性(最重要的是最后一位P)
- 我们要找的是第65个页目录项 xp/w 0+64*4
- 0x00000100: 0x00fa6027
- 027是属性 P=1 页表所在的物理页框号 0x00fa6。 页表在物理内存的0x00fa6位置
- 从0x00fa6开始查找3号页表项 xp/w 0x00fa6000+3*4 0x00fa600c : 0x00fa5067
- 物理地址
- 线性地址 0x10003004对应的物理页框号为0x00fa5067 , 页内偏移是0x004
- 0x00fa5004
- 变量i的物理地址
- 验证 page 0x10003004或者xp/w 0x00fa5004
- 修改内存来改变i的值
- setpmem 0x00fa5004 4 0
- 从 0x00fa5004地址开始的4个字节都为0,
在我的电脑上是0x00fa5004
## 共享内存
- **基于已经实现信号量的lab4**
- 修改 include/linux/sys.h
- include/unistd.h
- kernel/system_call.s
- mm/shm.c (含释放,所以不需要修改memory.c)
- mm/Makefile