【问题标题】:Simple NASM "boot program" not accessing memory correctly?简单的 NASM “引导程序”无法正确访问内存?
【发布时间】:2011-10-02 11:01:41
【问题描述】:

**请注意,当我说启动程序时,我并不是指启动操作系统的程序。我的意思是,当您启动计算机并执行某些操作时运行的简单程序。

好吧,所以我非常精通 Assembly/NASM,但我认为我对它的掌握程度足以编写简单的引导程序。

嗯,我认为我已经掌握了足够好的知识。显然不是。

我尝试了一个在网上找到的简单启动程序。它运行良好(打印字母“A”)。然后我修改它以打印存储在内存中的字母。它失败了;它不是打印一个“A”,而是打印一个笑脸。 (我发誓,电脑现在在嘲笑我。)

这是源文件中的代码:

[BITS 16]    ; We start up in 16-bit real mode
[ORG 0x7C00] ; We're booted into memory at this address. (Or so I'm told)

mov ah, 0x0E       ; Teletype command
mov bh, 0x00       ; Page number
mov bl, 0x07       ; Attributes (7 == white foreground, black background)
mov al, [testChar] ; Character to print; load it from the memory referenced by testChar.

int 0x10  ; Tell the BIOS to execute the teletype command.

jmp $  ; Infinite loop prevents us from going off and executing the other junk in memory

testChar db 65  ; This is the character we want to print. 'A'.

; The following code pads the rest of the outputted binary file
;   and concludes it with the bootloader signature so I don't have
;   to do so manually.
times 510-($-$$) db 0
dw 0xAA55

如果我将 'move al, [testChar]' 替换为 'move al, 65',则字母 'A' 打印正确。我尝试过移动内存声明,尝试了所有括号组合或 BITS 和 ORG 周围没有括号,并且尝试增加和减少 testChar(即 [testChar+1])。每次,它都会打印一个笑脸、一个反向笑脸(当我增加 testChar 时),或者什么都不打印(当我将内存声明放在代码之前,可能是因为没有执行代码 =P)。我不能让这该死的东西工作。

现在,对于规范(因为它们可能是相关的):

  • 我正在运行带有 Intel Pentium II 处理器的 Dell Latitude CPi,因为这就是我要测试的全部内容(我不是用我的普通计算机测试汇编程序。见鬼。)。我很确定说处理器是 x86,因为我在上面运行过 Windows XP、Ubuntu 和 Arch Linux。

  • 我目前正在使用 NASM 在 Arch Linux 上编写和编译程序。

  • 引导程序从软盘运行

  • 我使用 'nasm -f bin FILENAME' 来编译代码。

  • 然后我使用 AL 的“mtools”包中的“mformat”命令通过“mformat -f 1440 -B BOOTPROGRAM A:'。

那么,这次我搞砸了什么?还是我的处理器/BIOS 有问题?

【问题讨论】:

  • 笑脸可能意味着它正在打印 ascii 字符 1,这意味着您没有正确使用 [testChar]。我的 ASM 太生疏了,不记得如何正确操作了……
  • 我想可能就是这样。问题是,我看不到任何其他方法可以做到这一点。 NASM 手册说如果我想从一个地址(实际上是 testChar)中获取内存,我必须把它放在括号中。当我查看实际的二进制文件时,相对于程序的开始,testChar 应该是 0x0e 之类的东西。因此,如果我输入testChar,它会将 0x0e 放入 AL 寄存器。但是如果我输入[testChar],它应该将存储的值放在地址0x0e。但是,相反,它似乎更喜欢放置一个 1(或任何笑脸的 ASCII 键)而不是进入内存。
  • “引导程序”的术语是引导加载程序。

标签: assembly memory-management nasm bootloader


【解决方案1】:

DS 可能填充了一些垃圾值,所以这样做:

push cs
pop ds

mov ax, cs
mov ds, ax
mov es, ax

更好的是,不要相信 CS,而是这样做:

xor ax, ax
mov ds, ax

请参阅this discussion:某些 BIOS 可能使用 07c0:0000 而不是传统的 0000:7c00,特别是在使用 ElTorito 从 CD-ROM 引导时。

【讨论】:

  • 我尝试了这两个版本。当我现在启动它时,它不会在屏幕上显示任何内容。不开玩笑。
  • 嗯,也就是说,当我在执行任何其他操作之前插入其中任何一段代码来启动它时,它什么也不显示。人力资源管理系统。我将尝试将 65 添加到 AL 寄存器。如果笑脸的 ASCII 码实际上是 1,那么它应该显示一个 B。
  • 加载 testChar 后向 AL 寄存器添加 65 也会使屏幕变为空白。我不知道还能做什么。
  • @AnonymousJohn:试试xor ax,ax,mov ds,ax
  • CS:IP 应该是 0000:7c000,但是有些 BIOS 可能使用 07c0:0000,所以最好不要相信 CS
【解决方案2】:

这将产生以下代码(只需在编译后的代码上运行 objdump)。

00000000  B40E              mov ah,0xe
00000002  B700              mov bh,0x0
00000004  B307              mov bl,0x7
00000006  A00D7C            mov al,[0x7c0d]
00000009  CD10              int 0x10
0000000B  EBFE              jmp short 0xb
0000000D  41                inc cx ; this is actually your testChar
                                   ; ignore the opcode translation

现在,如果您位于 0x7C00,那么 [0x7c0d] 将是其中的最后一个字节(即 0x41 或 65,或 ASCII “A”)。但是,如果像其他贡献者之一 (ninjalj) 提到您有一些奇怪的 bios 错误,这意味着您不在 0x7C00,那么 [0x7c0d] 是任何人的猜测。

【讨论】:

    【解决方案3】:

    我第一次运行它时运行良好!它打印“A”。使用命令 nasm [filename.asm] -o [filename.com] -l [filename.lst]

    我使用了 nasm OSbad.asm -o OSbad.com 。使用 MagicISO 制作可启动映像文件 OSbad.iso 并使用 Windows 磁盘刻录机将其刻录到 DVD/RW。加载 Oracle VM 并创建一个具有 256 Mb RAM、CD/DVD、2GB 硬盘的新虚拟机。用 DVD 启动,它会在屏幕上打印“A”。

    所以我猜你的程序正在运行。一定是你正在做的其他事情导致它不起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 2015-04-29
      相关资源
      最近更新 更多