我可以推断出你正在使用
NASM (或
NASM 兼容) 汇编器。我不知道您用于构建引导加载程序的操作系统是什么,但我先假设是Linux或Windows。其他环境会有些相似。
为了使这更容易,您应将引导加载程序分成两个部分。一个是引导加载程序,第二个是在
0x1000:0x0000 加载的第二阶段。这使我们能够正确定义引导加载程序的起始点。 引导加载程序预计将被加载到物理地址
0x07c00,第二个阶段预计加载到
0x10000 ((0x1000<<4+)+0)。 我们需要汇编器来正确生成数据和代码的地址。
我写了一些StackOverflow答案,描述了我对代码所做修改的一些变化。其中一些更相关的是:
如果您不了解
段:偏移 对,我建议您阅读这篇
文章。 我提出这个问题是因为在您的问题和代码中似乎存在混淆。你似乎认为物理内存地址0x1000与段:偏移量0x1000:0x0000相同。 在您的问题中,您说:
jmp 0x1000:0000 ;Jump to 0x1000, start of second program
如果您查看该链接,您会发现这个段落:通过将段向左移动4位(乘以16进制),然后添加偏移量,segment:offset可以计算出物理地址。等式通常写作(segment<<4)+offset。在您的情况下,0x1000:0x0000是一个段为0x1000、偏移为0x0000的地址。使用等式计算内存中的物理地址,您将得到(0x1000<<4)+0x0000 = 0x10000(而不是0x1000)。
从您的代码中无法确定您如何使用NASM进行汇编。我提供了一个示例,但重要的部分是将引导加载程序拆分开来。假设我们将您的引导加载程序放入名为bootload.asm的文件中:
[bits 16]
[ORG 0x7c00]
xor ax, ax
mov ds, ax
cli
mov ss, ax
mov sp, 0x7c00
sti
reset:
xor ax,ax
int 0x13
jc reset
mov ax,0x1000
mov es,ax
floppy:
xor bx,bx
mov ah,0x2
mov al,0x1
mov ch,0x0
mov cl,0x2
mov dh,0x0
int 0x13
jc floppy
jmp 0x1000:0000
times 510 - ($ - $$) db 0
dw 0xAA55
请注意,我删除了这一行:
mov dl,0x0 ;Drive = 0 (Floppy)
这段代码将启动驱动器硬编码为软盘A:如果您从USB、硬盘或软盘B:启动,那么您的代码将无法正常工作,因为在这些情况下驱动器号很可能不是零。BIOS传递了实际用于加载引导程序的引导驱动器。该值位于寄存器DL中。这是您应该使用的BIOS磁盘函数的值。由于DL已经包含了引导驱动器,因此我们直接使用它。
第二阶段可以通过以下方式进行修改。我假设有一个名为stage2.asm
的文件:
[BITS 16]
[ORG 0x0000]
mov ax, cs
mov ds, ax
mov bx, var
mov ah, 0x0e
mov al, [bx]
xor bh, bh
int 0x10
jmp $
var:
db 'X'
我没有尝试简化你的代码。目的是展示如何添加胶水来解决你的问题。两个文件都使用
ORG
指令指定起始点。引导程序需要被组装以便它们能够在内存地址0x07c00处工作。你正在将第二阶段加载到0x1000:0x0000,它映射到物理地址0x10000。我们将ORG设置为0x0000,因为
jmp 0x1000:0000
会设置
CS= 0x1000和
IP= 0x0000。由于
IP是0x0000,我们希望ORG与之匹配,以便近内存引用相对于我们64k段的开头。
这将允许汇编器为您的变量和代码生成正确的内存引用。因为你在代码中没有正确地做这件事,所以你的第二阶段读取了错误的
var
内存位置,随后显示了不正确的字符。
一旦你将这2个文件拆分开来,你需要使用
NASM进行组装,然后将它们放入磁盘映像中。与你的问题不同,我将使用
DD来构建一个720k软盘映像,然后将引导程序放在开头(不截断磁盘),然后从紧随其后的扇区开始放置第二阶段。可以通过以下方式实现:
nasm -f bin bootload.asm -o bootload.bin
nasm -f bin stage2.asm -o stage2.bin
dd if=/dev/zero of=disk.img bs=1024 count=720
dd if=bootload.bin of=disk.img conv=notrunc
dd if=stage2.bin of=disk.img bs=512 seek=1 conv=notrunc
您可以使用QEMU这样的工具来运行此镜像:
qemu-system-i386 -fda disk.img
如果您使用的是Windows,并且没有访问DD的权限,那么您可以尝试使用以下修改版的stage2.asm:
[BITS 16]
[ORG 0x0000]
mov ax, cs
mov ds, ax
mov bx, var
mov ah, 0x0e
mov al, [bx]
xor bh, bh
int 0x10
jmp $
var:
db 'X'
times 737280 - 512 - ($ - $$) db 0
接下来使用以下命令组装和构建720K软盘镜像:
nasm -f bin bootload.asm -o bootload.bin
nasm -f bin stage2.asm -o stage2.bin
copy /b bootload.bin+stage2.bin disk.img
disk.img
是一个720K的磁盘映像,可用于QEMU或Bochs。最终disk.img
的大小应为737,280字节。
如果您想将一个内存地址的值移动到寄存器中,可以直接进行操作,无需使用中间寄存器。在你的stage2.asm
中,你有以下代码:
mov bx, var
mov ah, 0x0e
mov al, [bx]
它可以写成:
mov ah, 0x0e
mov al, [var]
这将会从内存位置var中移动一个字节,并直接移动到AL中。它的大小由NASM确定为一个字节,因为目标AL是一个8位寄存器。
mov al, [var]
的指令,直接将内存中的一个字节移动到一个8位寄存器中。 - Michael Petchmov al,0x11; 读取一个扇区
) - Fifoernik