你好世界引导加载程序在第一个字符之后挂起



我正在将此代码用于 Hello world 引导加载程序。它不是打印出"Hello world",而是打印出一个"H"并挂起。我已经使用 loadsb 成功打印出消息,但我不明白为什么这种方法不起作用,因为它似乎等效。

[ORG 0x7c00]
[BITS 16]
    xor ax, ax  ;make it zero
    mov ds, ax
    mov ecx, msg
bios_print:
    mov al, [ecx]
    add ecx,1
    cmp al, 0  ;zero=end of str
    je hang    ;get out
    cmp al,100
    jge hang
    mov ah, 0x0E
    int 0x10
    jmp bios_print

hang:
    jmp hang
msg   db 'Hello World', 13, 10, 0



   times 510-($-$$) db 0
   db 0x55
   db 0xAA

编辑:我将 [位 64] 更改为 [位 16]

你的程序完全按照你编码的方式工作。ASCII 中的小写e表示为 65h,等于十进制中的 101。因此,如果e (101) 在 al 中,则执行 cmp al, 100 / jge hang 会导致跳转到标签hang。一切都很好。:)

解决您的问题的方法就是简单地删除该行,因为我真的看不出它有任何目的 - 看看你是如何让你的字符串被终止的,循环将在到达结束时结束。

不过,有四个额外的提示:

  • 请记住,标志是在(几乎)每个算术和逻辑运算之后设置的。因此,真的没有必要在add后做cmp,特别是如果跳跃的唯一条件可以用其中一个标志表示。在这种情况下,add ecx, 1 / cmp al, 0 / je hang可以用非常简单的add ecx, 1 / jz hang代替。这样可以节省两个字节,这在引导扇区条件下非常有价值。
  • 在调用 BIOS 例程时,您确实希望保留您在应用程序中使用的寄存器。BIOS来自不同的供应商,其中一些可能表现不佳,并破坏了寄存器中的内容。指令pusha就是这样做的。在调用任何不是你自己编写的代码段时,保留所有运行时信息通常是一个经验法则(尽管这在更"文明"的环境中听起来可能很极端 - 但 BIOS 和一般的实模式代码不是其中之一)。
  • 当计算机启动时,它处于实模式。此模式下的默认操作数和地址大小为 16 位(地址通过分段人为扩展到 20 位)。当然,您可以使用寄存器的 32 位部分,但必须在指令发生之前生成操作数大小前缀。这是另一个字节,你现在只有 510 个字节。:)因此,mov ecx, msg只是冗余的 - 地址的偏移部分永远不会超过 16 位。add ecx, 1也是如此.在这两种情况下,只需将ecx替换为cx即可。
  • 使用hlt说明。它使CPU的血压低得多,到处强调它真的没有用。只需在hang标签之后和跳转之前添加hlt即可。

最新更新