2

我正在将此代码用于 Hello World 引导加载程序。它没有打印出“Hello world\n”,而是打印出一个“H”并挂起。我已经使用 loadb 成功打印出消息,但我不明白为什么这种方法不起作用,因为它看起来是等效的。

[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

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

4

1 回答 1

4

您的程序完全按照您编写的方式运行。ASCII 中的小写字母e表示为65h,等于十进制的 101。因此,执行cmp al, 100 / jge hangif e(101) is inal会导致跳转到 label hang。一切安好。:)

解决您的问题的方法是简单地删除该行,因为我真的看不出它有任何用途 - 看看您如何让字符串由 a 终止\0,循环将在到达末尾时结束。

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

  • 请记住,标志是在(几乎)每个算术和逻辑运算之后设置的。因此,实际上没有必要在 acmp之后执行 a add,特别是如果跳转的唯一条件可以由其中一个标志表示。在这种情况下,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 的血压低得多,而且到处都强调它真的没有用。只需hlthang标签之后和跳转之前添加。
于 2012-04-16T00:51:19.947 回答