【问题标题】:Hello World bootloader hanging after first characterHello World 引导加载程序在第一个字符后挂起
【发布时间】:2012-04-27 08:42:54
【问题描述】:

我正在将此代码用于 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]

【问题讨论】:

  • 电脑启动时为什么用[BITS 64]生成64位汇编代码,是16位模式

标签: assembly operating-system x86 bootloader


【解决方案1】:

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

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

另外还有四个提示:

  • 请记住,标志是在(几乎)每次算术和逻辑运算之后设置的。因此,实际上没有必要在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

【讨论】:

  • 感谢这样做解决了我的问题。我现在觉得自己很傻。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-04
  • 1970-01-01
  • 2014-07-16
  • 2020-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多