【问题标题】:(NASM) (80x86) Bootloader NEEDS xor ax, ax(NASM) (80x86) 引导加载程序需要 xor ax, ax
【发布时间】:2017-01-07 11:56:48
【问题描述】:

我正在学习如何从 osdev 制作引导加载程序。我正在使用 NASM 来组装我的代码,并使用 x86 机器来运行我的引导加载程序。这是一小段代码,它打印一个字符并进入一个无限循环:

BITS 16

xor ax, ax

mov ah, 0x0E
mov al, 0x41
int 0x10

jmp $

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

我的问题是:为什么当我注释 'xor ax, ax' 指令时代码没有运行?在上面的代码中可以看到,修改了ax的值是为了存储中断参数,所以代码应该在没有xor指令的情况下运行...

补充说明:

  • 我正在使用以下命令在 Xubuntu 下组装代码: nasm -f bin -o main.bin main.asm

  • 我正在使用以下命令将 512 字节的机器代码存储到笔式驱动器中: sudo dd if=main.bin of=/dev/sdb

  • 我的电脑可以从笔式驱动器启动

非常感谢。

【问题讨论】:

  • 通常你会在引导加载程序文件的顶部有org 0x7c00,在xor ax, ax之后你将它复制到DS寄存器和ES如有必要(不会受到伤害),在xor ax, ax 之后使用mov ds, axmov es, axxor ax, ax 与将 AX 归零几乎相同。由于您在 xor ax,ax 完成与否之后立即覆盖 AH 和 AL 并不重要。你确定有没有它的工作方式不同吗?还应该考虑设置SS:SP(栈段和指针)
  • 唯一的另一种可能性是您的 BIOS 正在(盲目地)覆盖它认为的 BPB,该 BPB 经常出现在引导加载程序的开头(通常在 JMP 指令之后)。如果它盲目地更新您的引导加载程序,则可能是 BIOS 在您的代码加载到 RAM 后所做的修改导致您的代码行为不正常。
  • 我建议您考虑在 int 10h/ah=0eh 之前执行 xor bx, bx,因为 BH 应该是要写入的页码(将其设置为 0)。
  • 更多关于 BIOS 参数块的信息可以在here 找到。 xor ax,ax 在正常工作的引导加载程序中根本不需要。真正的硬件有一些奇怪的怪癖,这些怪癖在 bochs、qemu、virtualbox 等虚拟环境中通常是看不到的。
  • @RyanB :见彼得的回答。他做到了。在 IRC 聊天中也提到过。当我提到“真正的硬件有一些奇怪的怪癖,你在 bochs、qemu、virtualbox 等虚拟环境中通常看不到的时候,我暗示了这个想法。”但作为提示可能有点迟钝。

标签: x86 nasm bootloader


【解决方案1】:

理论上你在写MBR而不是VBR时不需要BPB1,并且xor ax, ax的存在指令不会影响启动。
但是,您应该包含xor bh, bh(更多关于Int 10/AH=0Eh


很遗憾,这只是理论。

特别是对于 USB 设备,某些固件会隐式假定 BPB,包括完整的 FDC 描述符(具有有效的操作系统名称)。
非常感谢 Michael Petch 强调这一点。

自从引入UEFI 实现,特别是处理CSM (Compatibility Support Module) 的部分,即传统引导,编写完全支持的MBR 变得很棘手。

固件有时会尝试自动检测要使用的引导模式,并且由于所有 UEFI 设备也是符合规范的旧设备,因此固件必须依靠一些怪癖来区分它们。

我的固件将设备检测为“旧设备”,即使明确如此告知,至少满足以下条件之一:

  • MBR 分区表中有一个可引导的非空分区。
    根本不检查 CHS 或 LBA 中的起始/结束地址。
  • 第一条指令是xor ax, ax(两种形式:33 C031 C0)。 这是因为大多数引导加载程序做的第一件事就是通过 AX 将段寄存器设置为零。

可能还有其他“签名”,例如第一个字节的跳转,但我还没有测试它们(还)。

如果固件未能将设备检测为旧设备并且它不是符合 UEFI 标准的设备,它将被跳过。


您可以使用xor ax, ax(在这种情况下,我建议使用db 33h, 0c0h 和文档注释)或添加一个虚拟分区条目,如下所示。

BITS 16
ORG 7c00h                       ;Soon or later you'll need this

 xor bh, bh
 mov ah, 0x0E
 mov al, 0x41
 int 0x10

_loop:
 hlt                            ;Be eco-friendly
jmp _loop

 ;Pad to the first PTE (Partition Table Entry), it is at 1beh
 TIMES 01beh-($-$$) db 00h

 dd 80h                         ;Bootable partition at CHS 0:0:0 (Which is illegal but not checked)
 db 01h                         ;Non empty partition (Type 1 is MS-DOS 2.0 FAT)

 ;Pad to the end of the sector minus 2
 TIMES 510-($-$$) db 00h
 dw 0aa55h                      ;Signature

1 根据dd命令的参数。

【讨论】:

  • 哈哈,我会再次为环保评论投票:)
  • 相信您不需要 BPB 是错误的。您可能不会使用太多真正的硬件,但在 USB 引导期间,许多 BIOS 会将介质的驱动器几何结构(如 BIOS 所见)写入 BPB 区域。如果你有 BIOS 认为 BPB 所在的代码,一些 BIOS 会盲目地写入该区域,假设 BPB 在那里。其他 BIOS 将尝试检查 USB 设备的第一条指令是否是 JMP 指令(有些是愚蠢的,甚至不检查它是 2 字节还是 3 字节编码)。如果找到 JMP,则 BIOS 假定存在 BPB 并写入该区域。
  • 当然,如果 BIOS 盲目地重写您的代码,则行为可能是未定义的。正如 OP 在#OSdev 论坛上发现的那样(第二意见),这种事情并非闻所未闻。 OP 还提到,即使他使用 sti 指令而不是 xor ax,ax,他的代码也能正常工作。
  • @MichaelPetch 我的介绍是为了展示在完美世界中应该如何工作。在完美世界中,即使在 USB 驱动器中,MBR 也不需要 BPB。还是这样?
  • 不幸的是,我们并不生活在一个完美的世界中。离得很远。在一个完美的世界中,它不需要它。 USB 引导特别是一个有问题的事情,通常必须采取更实用的方法才能与最广泛的硬件兼容:(
【解决方案2】:

现在是 2018 年,我偶然发现了同样的问题。 Micheal 的答案和 cmets 似乎是最好的解决方案。我们并不生活在一个完美的世界中,事实就是这样。这就是我在开始 OS Dev 时想开发 BIOS 的原因。我讨厌不检查就在我的计算机上运行别人的代码。但这对于固件和 BIOS 来说太难了。如果您在不知道自己在做什么的情况下弄乱 BIOS,它甚至可能会使您的 PC 变砖。

无论如何,我刚刚添加了这条评论,以防其他人以后偶然发现同样的问题。我会认真建议检查源代码和/或反向工程一些已经可用的引导加载程序,如 GRUB、Windows 引导管理器、LILO 等。您还可以为您的 PC 下载 live USB linux 发行版,将其安装在闪存驱动器中并查看在十六进制编辑器中引导扇区代码,甚至可以反汇编它。

这并不完全是问题的答案,但值得一提。为了使这更相关,我只能说我已经反转了 GRUB 的代码,它安装在 Kali Linux USB 可引导上,它以 XOR BP, BP 指令开头。

【讨论】:

  • 有没有办法获取BIOS机器码?会有帮助的
  • Afaik 如果你有正确的软件,你当然可以阅读 eeprom/equivalent。 PS - 抱歉迟到的回复。我之前没有评论权限。
猜你喜欢
  • 2014-12-26
  • 1970-01-01
  • 2022-01-07
  • 2013-07-07
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多