【问题标题】:Reading boot Sector of the hard disk读取硬盘的引导扇区
【发布时间】:2013-07-15 15:47:42
【问题描述】:

我正在尝试学习实模式汇编。我想读取硬盘的引导扇区,所以下面是代码

org 100h

start:
xor ax, ax
mov es, ax    ; ES <- 0
mov cx, 1     ; cylinder 0, sector 1
mov dx, 0080h ; DH = 0 (head), drive = 80h (0th hard disk)
mov bx, buff ; segment offset of the buffer
mov ax, 0201h ; AH = 02 (disk read), AL = 01 (number of sectors to read)
int 13h

jnc .read

 .read:
  mov     ax, cs ; set up segments
  mov     ds, ax
  mov     es, ax
  mov     al, 03h
  mov     ah, 0
  int 10h

 mov     si, buff
 call    print_string

.done:
 jmp     .done


print_string:
lodsb        ; grab a byte from SI

test    al, al  ; logical or AL by itself
jz      .done   ; if the result is zero, get out

mov     ah, 0x0E
int 0x10      ; otherwise, print out the character!
jmp     print_string
.done:
 ret

buff dw 512

我的执行环境是DosBox0.70,exe文件是.COM。 我希望在屏幕上看到 512 个字节,但是当我运行我的 .COM 文件时,它只是空白屏幕。我可以看到它背后的几个原因

1) 给出的代码没有从 Bios 中断正确返回 (int 13h)。 2)String 应该以 null 结束,这里没有发生。

但不确定是否是上述原因导致它发生,如果是,我该如何应对这些问题??

【问题讨论】:

  • 试试mov bx, offset buff
  • @EgorSkriptunoff:代码看起来像是为 NASM 编写的,它没有/不需要 offset 关键字。
  • 引导扇区很可能包含超出 ASCII 表中可打印范围的字节(并且它包含值为 0 的字节)。尝试编写一个将每个字节打印为两个十六进制数字并重复此操作 512 次的函数,而不是使用您的 print_string 函数。顺便说一句,您已将缓冲区声明为可容纳 1024 个字节(512 个字)。
  • 版本#2:由于某种原因,MBR 的第一个字节为零。
  • @EgorSkriptunoff 如果 MBR 的第一个字节为零,则不应打印任何内容。

标签: assembly x86 real-mode


【解决方案1】:

Dos 将 .com 文件加载到它自己选择的某个段,并将 dses 设置为该段。您的 buff 在该段中,而不是段 0!您正在读取第 0 段的第一个扇区,这可能会破坏您的 IVT。别管es

读取一个扇区后,您检查进位标志(指示错误),但无论是否设置都放入.read。如果错误,您可能需要重置驱动器并再次尝试读取。您可能需要一个“重试计数器”,这样您就不会陷入无限循环。

您的buff 不保留 512 个字节,而是保留两个值为 512 的字节。由于它位于文件的末尾,这可能不会造成任何伤害,但它不是“正确的”。

成功读取扇区后,您可以将其打印为 ascii 字符,但您希望打印所有 512 个字节,而不是在遇到的第一个 0 处停止。十六进制转储可能更具可读性。

如果您的 MBR 的第一个字节为零,我们就陷入了泥潭!有效引导扇区的第一个字节应该是短的jmp,后跟nop,或接近jmp。我们对以这种方式启动引导扇区有点随意,大多数 BIOS 都不检查,但这就是“应该”存在的。如果 CPU 将 0 视为第一个字节,它会执行什么? (提示:这是一个add

我认为您的两个主要问题是将es 设置为零,如果遇到零则停止打印。再试一次。 FFS,在读取工作可靠之前,不要尝试向驱动器写入任何内容!

【讨论】:

  • 谢谢弗兰克,关于“您检查进位标志(指示错误),但进入.read”的观点,我正在做的事情是检查我的读取扇区是否通过那么它会清除进位标志,如果进位标志被清除,jnc指令会做一个短跳转,我在这里做错了吗??
  • 不,如果进位标志是明确的,你就可以了。但是如果设置了进位标志,您仍然会直接转到.read:。这不会造成太大的伤害,但您的引导扇区不会位于buff
  • 好的弗兰克,明白你的意思。但仍然有问题的一点是让 es 独自一人(不设置为零),你能告诉我更详细的信息吗?
  • int 13h 将扇区读取到位于es:bx 的缓冲区中。您的缓冲区 buff 不在段 0 中,但在任何段中 dos 将您的文件加载到(并将 dses 设置为)。我以为我有一个例子,但我可以找到使用 IDE 控制器使用端口读取引导扇区,而不是 BIOS int 13h。 IDE 驱动器现在很少见,所以它不会工作。
  • 感谢@Frank 的热心帮助,我会尝试按照您的建议进行操作,并会再次回来。
【解决方案2】:

磁盘的引导扇区包含的不是 ASCII 数据,而是代码。很有可能,第一个字节将是 NULL 并且剩余的可能是不可打印的代码(例如 CR、LF 等)。

尝试通过打印 ascii 代码的 INT 10h 打印缓冲区,并以 0 结尾可能会导致根本不显示任何内容。

您应该将缓冲区的每个字节转换为十六进制字符串,然后将这些字符串打印到显示器上。这样,您将获得引导扇区的简单十六进制转储。

【讨论】:

  • 感谢@johnfound 的回答,有一件事想知道MBR 的第一个字节是否为零,那么即使它是十六进制的,也无法使用int10h 打印它来显示。对吗??
  • 当然,如果你停止在字节 0 上打印,那么可以,但是如果你想进行十六进制转储,你必须简单地打印扇区的所有 512 字节。
  • Johanfound 想对 Frank cmets 说点关于让 es 保持原样的事情吗??
  • @AmitSinghTomar - 弗兰克是完全正确的。对于 .COM 程序,没有必要将 ES 和 DS 设置为 CS,因为它们已经由 DOS 设置。只有当您希望它们指向其他地方时,您才必须设置 DS 或 ES。
猜你喜欢
  • 2023-03-23
  • 2020-06-12
  • 2011-11-09
  • 2013-07-16
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 2012-07-25
  • 2013-03-18
相关资源
最近更新 更多