基于李治军OS课程以及其实验楼的实验说明,对内存地址的映射过程进行梳理。
概览
开始访问一个变量
每个程序都有各个段组成,如ss, ds, cs等。假设现在访问一个全局变量i,它自然是在数据段ds中,假设它在ds中相对地址是0x3004
,那么在汇编中访问即是:ds:0x3004
最直观的需求就是要知道ds的位置,即其地址;而ds的位置信息记录在每个应用程序各自的LDT中;而LDT的位置信息记录在GDT中;GDT的地址存在寄存器gdtr中。所以为了得到ds的地址,会经过以下流程:
查找LDT的位置
其实就是寻找该应用程序的段表
- 首先读取gdtr,假设其内容为
0x00005cb8
,这就是GDT起始的物理地址。 - 随后要知道LDT起始的地址的线索(即能表明LDT在GDT中的位置信息),其存在ldtr中,假设是
0x0068
,这存的是一个选择子,其结构为:
索引(13位) | TI(1位) | RPL(2位) |
---|
将0x0068
用二进制表示就是:0000000001101,0,00
这样可知索引是13号(十进制)。其他的,TI = 0,表明是在GDT中,RPL = 00,表明请求特权级是0,即最高级别,只有内核态能访问。
之后便去GDT中寻找记录LDT地址的表项:
因为一项记录的长度是8B,所以这样计算地址:0x00005cb8 + 13 * 8 = 0x00005d20
此时便得到了该表项的物理地址,以其为起始,读出8B内容,得到0xa2d00068 0x000082fa
这就是段描述符的内容,其结构为:
0xa2d00068 0x000082fa
分别为dl(低位), dh(高位),分别对应图中的下部分和上部分,所以LDT的基地址便是这框起来的部分:
0xa2d00068 0x000082fa
按照从高位到低位的顺序拼起来,得到:0x00faa2d0
这就是LDT的物理地址!
查找ds的地址,然后得到线性地址
先获取ds的选择子,假设是:0x0017
二进制是:0000000000010,1,11
根据上面所述的结构可知,其索引是2号。因为已经知道LDT的物理地址了,便可以计算出2号项的地址:0x00faa2d0 + 2 * 8 = 0x00faa2e0
随后读出其内容,假设是:0x00003fff 0x10c0f300
再利用上述同样的方式得到ds的地址:0x10000000
所以,ds:0x3004
便可转成线性地址:0x10000000 + 0x3004 = 0x10003004
开始虚拟地址向物理地址映射
假设得到的线性地址是虚拟地址