地址映射
实验步骤
用汇编级调试启动linux-0.11:
cd ~/workspace/oslab
./dbg-asm
ubuntu终端进入bochs的调试模式,先让linux-0.11正常运行:
在linux-0.11中添加文件/usr/root/test.c,内容如下:
#includeint i = 0x12345678; int main(void) { printf("The logical/virtual address of i is 0x%08x", &i); fflush(stdout); while (i) ; return 0; }
在linux-0.11中编译test.c,运行目标文件:
gcc -o test test.c ./test
程序进入死循环,切换到ubuntu的终端,按下Ctrl+C暂停linux-0.11:
为了让linux-0.11中运行的test跳出循环,需要找到逻辑地址ds:0x3004对应的物理地址,将其内容(变量i)改为0。
首先要得到段表LDT,取得ds对应的段描述符,才能得到ds的基址,从而得到ds:0x3004对应的线性地址,进而从线性地址计算出物理地址。
LDT的段描述符
段描述符放在LDT中,ldt的描述符放在GDT中,GDT的地址与LDT在GDT中的项的索引分别保存在gdtr和ldtr中:
s部分是一个段选择子,dl和dh是bochs自动算得的段描述符。
ldtr为0x0068 => 0000 0000 0110 1000 b,可知索引为1101b即13,TI位为0,即GDT中的第13项为LDT的段描述符,每个段描述符64bit => 8byte:
得到的LDT段描述符(与sreg指令得到的ldtr中的dl、dh相同),从而我们可以得到LDT的基址为0x00f9a2d0。
ds的段描述符
ds段选择子为0x0017 => 0000 0000 0001 0111 b,可知索引为10b即2,TI位为1,即LDT中的第2项为ds的段描述符,每个段描述符64bit => 8byte:
得到的ds段描述符,从而我们可以得到ds的基址为0x10000000。
线性地址
故ds:0x3004对应的线性地址为0x10000000+0x3004=0x10003004。
由线性地址计算出物理地址
线性地址0x10003004 => 0001 0000 0000 0000 0011 0000 0000 0100 b,可知页目录号为1000000b即64,页表为11b即3,页内偏移为100b即4 。
页目录表的基址存放于CR3中:
获取页目录项:
可知页表基地址为0x00fa9000 。
获取页表项:
可知物理页基地址为0x00fa7000 。
可以看到内容是test.c中的变量i的值,将它设置为0:
让linux-0.11继续运行:
成功跳出循环,程序结束:
注解
段选择子
RPL:特权级,0~3权限递减;
TI:1表示INDEX为LDT表中的索引,0表示为GDT的;
INDEX:段描述符在表(LDT/GDT)中的项的索引。
段描述符中的段基址
段基址在段描述符中被分成3个部分,重新组合即可得到段基址。
由线性地址计算出物理地址
directory:页目录号
table:页表号
offset:页内偏移
table_base/page_base:页目录项/页表项的物理页面框号,作为地址的高位(其值左移12位得到基址)