我无法在QEMU模拟器中执行我的引导加载程序文件。

huangapple go评论86阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年8月10日 12:13:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872613.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定