英文:
I cannot execute my bootloader file in qemu emulator
问题
抱歉,以下是您要翻译的内容:
org 0x7c00
section .text
mov ah, 0x0e
mov si, message
print_loop:
lodsb
or al, al
jz done
int 0x10
jmp print_loop
done:
hlt
section .data
message db "Hello, World!", 0
times 510-($-$$) db 0
dw 0xaa55
关于您的问题,当我尝试在我的qemu模拟器中执行此代码时,它显示“找不到可引导设备”。您该如何修复它?
英文:
org 0x7c00
section .text
mov ah, 0x0e
mov si, message
print_loop:
lodsb
or al, al
jz done
int 0x10
jmp print_loop
done:
hlt
section .data
message db "Hello, World!", 0
times 510-($-$$) db 0
dw 0xaa55
When I try to execute this code in my qemu emulator, it shows "no bootable device found". How can I fix it?
答案1
得分: 3
你可能想要检查生成的引导扇区的实际内容,以确保其符合规则。我认为基本上只需要确保最后两个字节是正确的签名。
我提出这个问题的原因是因为我认为如果你正在使用部分,那么$-$$
是错误的东西。它计算当前位置与部分的开头之间的差异,而不是引导扇区的开头。
因此,如果代码部分有15个字节,紧随其后的数据部分有14个字节(都大致符合你的情况),那么在数据部分中的510 - ($ - $$)
将变为510 - (29 - 15) = 496
。这意味着你将有:
- 15字节的代码。
- 14字节的数据。
- 496字节的填充。
这总共是525
字节,在生成签名之前,所以它不会位于正确的位置,这意味着引导加载程序将无法识别磁盘为可引导。在这种情况下,偏移1fe
将包含填充中的两个00
字节。
你的原始代码生成的以下清单证实了这一点:
org 0x7c00
section .text
00000000 B40E mov ah, 0x0e
00000002 BE[0000] mov si, message
print_loop:
00000005 AC lodsb
00000006 08C0 or al, al
00000008 7404 jz done
0000000A CD10 int 0x10
0000000C EBF7 jmp print_loop
done:
0000000E F4 hlt
section .data
00000000 message:
00000000 48656C6C6F2C20 db "Hello, World!", 0
00000008 576F726C642100
0000000E 00<*496> times 510-($-$$) db 0
000001FE 55AA dw 0xaa55
你可以看到签名位于偏移1fe
,但这个偏移是相对于数据部分的(因为消息位于该部分的偏移000
处)。这意味着它没有考虑到将这两个部分合并为引导扇区时所使用的空间。
如果你将所有内容放在一个部分中,表达式应该变为510 - (29 - 0) = 481
,从而在签名之前得到正确的510
字节:
- 15字节的代码。
- 14字节的数据。
- 481字节的填充。
这仍然看起来签名在清单中的偏移是1fe
,但这是代码(而且唯一)部分内的偏移,消息位于00f
处。消息和签名之间的填充也较少:
org 0x7c00
section .text
00000000 B40E mov ah, 0x0e
00000002 BE[0000] mov si, message
print_loop:
00000005 AC lodsb
00000006 08C0 or al, al
00000008 7404 jz done
0000000A CD10 int 0x10
0000000C EBF7 jmp print_loop
done:
0000000E F4 hlt
0000000F message:
0000000F 48656C6C6F2C20 db "Hello, World!", 0
00000016 576F726C642100
0000001D 00<*481> times 510-($-$$) db 0
000001FE 55AA dw 0xaa55
还有一些关于你的代码的小问题。
首先,hlt
确实会停止CPU,但下一个外部中断可以重新启动它。由于你可能不希望尝试执行你的消息,因此可以考虑使用以下方法来防止这种情况发生:
done:
hlt
jmp done
其次,当BIOS将控制权转移到你的代码时,你应该依赖的东西非常少。例如,你不应该假设ds
设置为与cs
相同的值,就像你似乎期望的那样。
你应该明确强制使其成为如此,以及设置任何其他需要的东西,例如堆栈指针。
英文:
You may want to check the actual content of the generated boot sector to make sure it complies with the rules. I think that's basically just ensuring the final two bytes are the correct signature.
The reason I bring this up is because I think $-$$
is the wrong thing to use here, if you're using sections. It works out the difference between current location and the start of the section, not the start of the boot sector.
So, with a code section of fifteen bytes and an immediately following data section of fourteen bytes (both roughly what you have), 510 - ($ - $$)
in the data section becomes 510 - (29 - 15) = 496
. That means you will have:
- 15 bytes of code.
- 14 bytes of data.
- 496 bytes of padding.
That's a total of 525
bytes before you generate the signature so it won't be at the correct location, meaning the boot loader will not recognise the disk as bootable. In this case, offset 1fe
will contain two of the 00
bytes from the padding.
The following listing generated by your original code confirms this:
org 0x7c00
section .text
00000000 B40E mov ah, 0x0e
00000002 BE[0000] mov si, message
print_loop:
00000005 AC lodsb
00000006 08C0 or al, al
00000008 7404 jz done
0000000A CD10 int 0x10
0000000C EBF7 jmp print_loop
done:
0000000E F4 hlt
section .data
00000000 message:
00000000 48656C6C6F2C20 db "Hello, World!", 0
00000008 576F726C642100
0000000E 00<*496> times 510-($-$$) db 0
000001FE 55AA dw 0xaa55
You can see that the signature is at offset 1fe
but that offset is relative to the start of the data section (because the message is at offset 000
within that section). That means it's not taking into account how much space is used by the code when combining the two sections into a boot sector.
If instead you place it all in one section, the expression should then become 510 - (29 - 0) = 481
, giving the correct 510
bytes before the signature:
- 15 bytes of code.
- 14 bytes of data.
- 481 bytes of padding.
This still looks like the signature goes at offset 1fe
in the listing but that's the offset within the code (and only) section, with the message at 00f
. There's also less padding between the message and the signature:
org 0x7c00
section .text
00000000 B40E mov ah, 0x0e
00000002 BE[0000] mov si, message
print_loop:
00000005 AC lodsb
00000006 08C0 or al, al
00000008 7404 jz done
0000000A CD10 int 0x10
0000000C EBF7 jmp print_loop
done:
0000000E F4 hlt
0000000F message:
0000000F 48656C6C6F2C20 db "Hello, World!", 0
00000016 576F726C642100
0000001D 00<*481> times 510-($-$$) db 0
000001FE 55AA dw 0xaa55
And just some minor points on your code.
First, hlt
will indeed halt the CPU but the next external interrupt can restart it. Since you probably don't want that to try and execute your message, it may be worthwhile protecting against that with:
done:
hlt
jmp done
Second, when BIOS transfers control to your code, there's very little that you should rely on. For example, you should not assume that ds
is set to, as you seem to expect it, the same value as cs
.
You should explicitly force that to be the case, as well as setting up anything else that's needed such as the stack pointer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论