我在阅读 Linux0.11 源码时,对一个指令 LDS 感到困惑。
看了下 intel 指令集手册,能猜到 LDS 的功能,但不确定。
于是决定搭建调试环境,看看 LDS 的功能是否真如自己猜测。
首先 make debug 运行 qemu-Linux0.11,命令如下:
使用 gdb 连接,给 0x7c00 打断点,可以看到汇编指令如图
跟我们自己看到的 bootsect.s 的汇编指令差别也太大了
为了验证被加载在程序 0x7c00 的汇编指令到底是不是 bootsect.s 的代码,我决定使用 xxd 看二进制文件的内容
首先根据运行 qemu-Linux0.11 的命令来看,可知它加载了软盘 Image
xxd Image, 可见第一个 512 字节末尾是 55AA,这确实是启动扇区
再次运行 gdb-qemu-Linux0.11,使用 x/256x 0x7c00 查看位于 0x7c00 的内存内容,如下
由于大小端问题,内存内容的排序看起来和 xxd 有点不同,但实际上是一样的。看来 Image 第一个扇区的内容确实被加载到了 0x7c00
阅读 Makefile,发现 Image 的第一个扇区确实是由 bootsect.s 编译出的 bootsect 二进制文件构成的,使用 xxd 查看 bootsect,如下图
几乎一致,可以确定 bootsect.s 的内容确实被加载到了 0x7c00,那么问题应该出在 gdb 的反汇编上
STFW,在谷歌查到下面这个网页
https://stackoverflow.com/questions/32955887/how-to-disassemble-16-bit-x86-boot-sector-code-in-gdb-with-x-i-pc-it-gets-tr
根据高赞回答,在调试一般的 16 位汇编时,只需要使用 set architecture i8086 命令即可(存疑,已证明不行)
但是 qemu-system-i386 是属于实模式,它会使用段寄存器来进行寻址,gdb 对于这种段寄存器寻址的机制并没有很好的支持,因此在运行 gdb 之前需要先加载一串超长的 gdb.init 脚本
首先使用 wget https://ternet.fr/media/gdb_init_real_mode.txt 下载这个脚本文件,已证明不行
试过了,发现不行。
==============================================
根据前面的探索,使用 qemu+gdb 对 x86 实模式调试非常艰难,我认为我们应该使用 bochs 进行实模式的调试
TODO:here