出于教学目的,我将此引导加载程序从mikeos.berlios.de/write-your-own-os.html改写为专门在地址0x 7 c 00加载。
最后的代码是:
[BITS 16] ; Tells nasm to build 16 bits code
[ORG 0x7C00] ; The address the code will start
start:
mov ax, 0 ; Reserves 4Kbytes after the bootloader
add ax, 288 ; (4096 + 512)/ 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 0 ; Sets the data segment
mov ds, ax
mov si, texto ; Sets the text position
call imprime ; Calls the printing routine
jmp $ ; Infinite loop
texto db 'It works! :-D', 0
imprime: ; Prints the text on screen
mov ah, 0Eh ; int 10h - printing function
.repeat:
lodsb ; Grabs one char
cmp al, 0
je .done ; If char is zero, ends
int 10h ; Else prints char
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Fills the remaining boot sector with 0s
dw 0xAA55 ; Standard boot signature
我可以单步执行程序,看到寄存器的变化,沿着正在执行的指令,使用gdb(si)单步执行,并使用QEMU监视器(info寄存器、x /i $eip等)进行检查。
在我进入10小时间隔后(BIOS打印例程),事情变得有点奇怪。如果我一次执行500条指令,我能看到“我”这个字(我的文本字符串的第一个字符)打印在屏幕上。所以我再次重新启动,走了400步(si 400)然后我一步一步地做,看看“我”在哪个确切的步骤中被打印出来。它从来没有发生过。我实际上一步一步地走了200步,什么也没有发生。当我一次踏出100步(si 100)时,我又在屏幕上打印出了“我”。
所以,我想知道是否有一个定时问题(一些系统中断妨碍了我一步一步的调试)。
无论如何,有没有办法跳过整个BIOS中断和其他功能,只是回去继续步进引导加载程序代码?正如评论中Peter Quiring所建议的,我尝试使用next。这没有工作。
(gdb) next
Cannot find bounds of current function
所以我试了一下nexti,它的行为就像si一样。
谢谢你!
3条答案
按热度按时间hk8txs481#
我已经用Python脚本自动化了您的过程:
这也适用于任何其他指令,但我没有看到它的许多其他用例,因为
nexti
已经跳过了call
。只需将其放到
~/.gdbinit.py
中,然后将source ~/.gdbinit.py
添加到~/.gdbinit
文件中。在GDB 7.7.1和Ubuntu 14.04上进行了测试。
sirbozc52#
这实际上是一个符合我的目的的解决方案。我所做的是设置断点,这样我就可以在gdb上使用“continue”和“si”沿着并按照屏幕上打印的消息,一次一个字符。下面是步骤。
在第一次运行中,我会逐步执行引导加载程序,这样我就可以实际检查存储指令的内存位置。
Linux外壳程序:
其他Linux shell(一些行已被抑制[...]):
在我运行QEMU监视器的终端中,我在gdb上的每个si之后找到执行此命令的指令的地址:
对于QEMU的初学者,x显示寄存器的内容,/i将其转换为指令,$eip是指令指针寄存器。通过重复这些步骤,我找到了lodsb和int 10 h指令的地址:
因此,在gdb上,我只为这些附加位置设置了断点:
现在,我可以在gdb上使用“continue”(c)和stepi(si)的组合,并跳过整个BIOS的内容。
可能有更好的方法来做到这一点。然而,就我的教学目的而言,这种方法效果相当好。
gzjq41n43#
实际上QEMU已经考虑到了这种情况,QEMU gdbstub内部有两个标志:NOIRQ和NOTIMER。这两个标志将阻止irq被注入guest虚拟机并暂停单步模式下的计时器时钟仿真。您可以通过以下方式查询qemu的功能:
对于KVM,您的主机可能需要linux内核v5.12+来支持NOIRQ,它实现了ioctl KVM_CAP_SET_GUEST_DEBUG2。
但请注意,NOIRQ只会防止IRQ,仍会注入例外/陷阱。