Bochs常用调试命令
b [addr] // 加断点于[addr]
c //继续运行
ctrl+c // 暂停运行
n // 单步运行
回车 // 继续上次的命令
r // 查看常用寄存器信息
sreg // 查看段寄存器信息
q // 退出 debug
按照实验指导,将test.c导入到linux0.11的用户目录下,打开调试,在0.11中编译,运行。发现一直在循环。
↑ 0.11中
↑ 调试器中
终端上显示的代码是下一行将要执行的代码(还未执行)。
所以当前下一句是cmp dword ptr ds:0x3004, 0x00000000 ; 833d0430000000
。这句话是反汇编的结果,意思是拿虚拟地址ds:0x3004
的值跟0比。通过之前亲手导入的test.c,我们知道如果相等则退出死循环。所以现在的目的就是在这个环境下找出虚拟地址ds:0x3004
所对应的物理地址是多少,利用bochs的setpmem指令将那个物理地址上的内容改为0,再继续运行一句,linux0.11就可以退出死循环。这就是该实验的目的。
取巧
由于bochs里面的命令很多、很强大,所以如下图,两句话就把地址拿到了。
当然这对知识的增长毫无帮助。
正解
先查段表,得到虚拟地址,再查页表,得到物理地址。
step1. 找到段表(LDT)地址
关注这一行:ldtr:s=0x0068, dl=0x52d00068, dh=0x000082fd, valid=1
这个ldtr是什么:寄存器,里面的某些位包含当前进程的ldt表的首地址。即,切换了它就切换了用户的段表。(类比PC,切换了PC就切换了用户代码)
ldtr的结构如下图
0x0068=0000000001101|0|00,意思是,要去GDTR中找,第(1101)2项,其实就是第13项。
按照下图,
拼一拼凑一凑:
所以LDT首地址是:0x00fd52d0
step2. 查到ds真实值
ds是段基址,值就在ldt表中,首先打出ldt表的内容。
那么代表ds的是哪个呢?
拿出一开始的截图:
ds=0x0017=0000000000010|1|11,所以在ldt表中查第三项。那就是0x00003fff 0x10c0f300
再拼一拼凑一凑:
所以ds真实值为0x10000000
加上偏移,所以变量i的虚拟地址为:0x10003004
验证:
step3. 虚拟地址转物理地址
这里实验指导写的十分清晰:
step4. 找页框号
IA-32 下,页目录表的位置由 CR3 寄存器指引。“creg”命令可以看到:
页目录表首地址是0
找第65个项
这就是页目录号
页目录表和页表中的内容很简单,是 1024 个 32 位(正好是 4K)数。这 32 位中前 20 位是物理页框号,后面是一些属性信息(其中最重要的是最后一位 P)。
所以页表地址为 0x00fa7000
所以页框号为 0x00fa6000
页框号+偏移为最终答案0x00fa6004
ref
https://www.lanqiao.cn/courses/115(实验地址)
https://blog.csdn.net/genzld/article/details/90672003(图1.1)
https://blog.csdn.net/weixin_53159274/article/details/137796343(Bochs命令)