我正在制作自定义操作系统。我有两个nasm文件:
boot.asm:
[BITS 16] ;tell the assembler that its a 16 bit code
[ORG 0x7C00] ;Origin, tell the assembler that where the code will
;be in memory after it is been loaded
INT 0x13
JMP $ ;infinite loop
TIMES 510 - ($ - $$) db 0 ;fill the rest of sector with 0
DW 0xAA55 ; add boot signature
start.asm:
[BITS 16]
MOV AL, 72
CALL PrintCharacter
MOV AL, 101
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 111
CALL PrintCharacter
MOV AL, 44
CALL PrintCharacter
MOV AL, 32
CALL PrintCharacter
MOV AL, 87
CALL PrintCharacter
MOV AL, 111
CALL PrintCharacter
MOV AL, 114
CALL PrintCharacter
MOV AL, 108
CALL PrintCharacter
MOV AL, 100
CALL PrintCharacter
MOV AL, 33
CALL PrintCharacter
PrintCharacter:
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
INT 0x10
RET
TIMES 512 - ($ - $$) db 0
我使用以下命令将它们编译成.bin文件:
nasm boot.asm -f bin -o boot.bin
nasm start.asm -f bin -o start.bin
然后使用以下命令将它们添加到软盘映像中:
dd if=boot.bin bs=512 of=MyOS.img count=1
dd if=start.bin bs=512 of=MyOS.img count=2
当我从VirtualBox中的软盘映像启动时,它显示2个感叹号而不是1个感叹号,甚至在QEmu(Q.app)中都没有启动。我是操作系统开发的新手,所以如果有人能告诉我我做错了什么并给我一些关于如何更好地设置我的操作系统的指示,那就太好了。
答案 0 :(得分:5)
当然会打印出两个惊叹号。我们来看看你的代码:
...
MOV AL, 33
CALL PrintCharacter ; |1
; | ^ |4
PrintCharacter: ; v |2 | |
MOV AH, 0x0E ; | | |
MOV BH, 0x00 ; | | |
MOV BL, 0x07 ; | | |
INT 0x10 ; | | | 5
RET ; v |3 v ----> off to la-la land
注意:我添加了一些箭头来说明程序执行的进展情况。
前两行负责在您输出!
后打印最终Hello, World
。这可以通过调用PrintCharacter
子程序来实现。 (箭头1
和2
。)当PrintCharacter
返回时(箭头3
),您的程序会直接继续(箭头4
)...并且下一行代码恰好是PrintCharacter
的开头。由于AL
寄存器仍包含33(即!
的ANSI代码),因此会打印另一个感叹号。
然后,执行再次进入RET
,但这一次,因为你实际上没有CALL
PrintCharacter
,所以没有定义的地方可以返回,所以它返回到......一些未定义的地方,最有可能(箭头5
)。我想这是你的操作系统停止继续启动过程的瞬间。
结论:在您的代码打印Hello, World!
之后,它应该执行其他操作(至少停止),否则请不要感到惊讶得到未定义的行为或挂断...
答案 1 :(得分:1)
我不知道VirtualBox是如何启动你的代码的,但我很确定qemu没有,因为你是以错误的方式在磁盘映像上设置二进制文件。当你在磁盘映像上使用'dd'时,你需要传递一个选项,这样它就不会截断磁盘,如下所示:
dd if=boot.bin of=MyOS.img bs=512 count=1 conv=notrunc status=noxfer
dd if=start.bin of=MyOS.img bs=512 count=1 conv=notrunc seek=1 status=noxfer
conv = notrunc告诉'dd'它不应该截断磁盘,也就是说,删除它并用你的二进制文件覆盖它,status = noxfer使它更简洁,seek = 1将start.bin写入第二扇区磁盘(以0开头)。
要验证我在说什么,请尝试创建1MB的磁盘映像,并使用您正在使用的命令(即dd),您将看到磁盘映像已缩减为二进制文件的副本。
所以,最后,你使用start.bin作为磁盘映像调用qemu(MyOS.img在最后一个'dd'命令后成为它的副本),并且因为你最后没有使用启动签名start.bin,qemu BIOS不认为你的磁盘是可启动的。