(segment 。在您的情况下, 0x1000:0x0000 是 0x1000 的段和 0x0000 的偏移量。使用等式获取内存中的物理地址,您将得到 (0x1000
从您的代码中无法判断您是如何使用 NASM 进行组装的。我提供了一个如何完成的示例,但重要的部分是将引导加载程序分开。假设我们将您的引导加载程序放在一个名为 bootload.asm 的文件中:
[bits 16]
[ORG 0x7c00] ; Bootloader starts at physical address 0x07c00
; BIOS sets DL to boot drive before jumping to the bootloader
; Since we specified an ORG(offset) of 0x7c00 we should make sure that
; Data Segment (DS) is set accordingly. The DS:Offset that would work
; in this case is DS=0 . That would map to segment:offset 0x0000:0x7c00
; which is physical memory address (0x0000<<4)+0x7c00 . We can't rely on
; DS being set to what we expect upon jumping to our code so we set it
; explicitly
xor ax, ax
mov ds, ax ; DS=0
cli ; Turn off interrupts for SS:SP update
; to avoid a problem with buggy 8088 CPUs
mov ss, ax ; SS = 0x0000
mov sp, 0x7c00 ; SP = 0x7c00
; We'll set the stack starting just below
; where the bootloader is at 0x0:0x7c00. The
; stack can be placed anywhere in usable and
; unused RAM.
sti ; Turn interrupts back on
reset: ; Resets floppy drive
xor ax,ax ; 0 = Reset floppy disk
int 0x13
jc reset ; If carry flag was set, try again
mov ax,0x1000 ; When we read the sector, we are going to read address 0x1000
mov es,ax ; Set ES with 0x1000
floppy:
xor bx,bx ;Ensure that the buffer offset is 0!
mov ah,0x2 ;2 = Read floppy
mov al,0x1 ;Reading one sector
mov ch,0x0 ;Track 1
mov cl,0x2 ;Sector 2, track 1
mov dh,0x0 ;Head 1
int 0x13
jc floppy ;If carry flag was set, try again
jmp 0x1000:0000 ;Jump to 0x1000, start of second program
times 510 - ($ - $$) db 0 ;Fill the rest of sector with 0
dw 0xAA55 ;This is the boot signature
你应该注意到我删除了这一行:
mov dl,0x0 ;Drive = 0 (Floppy)
这会将引导驱动器硬编码到软盘 A:。如果您从 USB、硬盘驱动器或软盘 B 启动:您的代码将无法工作,因为在这些情况下驱动器编号可能不会为零。 BIOS 传递用于加载引导加载程序的实际引导驱动器。该值在寄存器 DL 中。这是您应该用于 BIOS 磁盘功能的值。由于 DL 已经包含引导驱动器,我们就按原样使用它。
第二阶段可以这样修改。我假设一个名为stage2.asm的文件:
[BITS 16]
[ORG 0x0000] ; This code is intended to be loaded starting at 0x1000:0x0000
; Which is physical address 0x10000. ORG represents the offset
; from the beginning of our segment.
; Our bootloader jumped to 0x1000:0x0000 which sets CS=0x1000 and IP=0x0000
; We need to manually set the DS register so it can properly find our variables
; like 'var'
mov ax, cs
mov ds, ax ; Copy CS to DS (we can't do it directly so we use AX temporarily)
mov bx, var
mov ah, 0x0e
mov al, [bx]
xor bh, bh ; BH = 0 = Display on text mode page 0
int 0x10
jmp $
var:
db 'X'
我没有尝试简化您的代码。这个想法是展示如何添加胶水来解决您的问题。这两个文件都使用ORG 指令指定了一个起点。需要组装引导加载程序,以便它们在内存地址 0x07c00 处工作。您在 0x1000:0x0000 加载第二阶段,映射到物理地址 0x10000。我们将 ORG 设置为 0x0000,因为 FAR JUMP jmp 0x1000:0000 将设置 CS=0x1000 和 IP=0x0000。因为 IP 是 0x0000,我们希望 ORG 匹配它,以便近内存引用相对于 64k 段的开头。
这将允许汇编器为您的变量和代码生成正确的内存引用。因为您没有在代码中正确执行此操作,所以您的第二阶段是为 var 读取错误的内存位置并随后显示错误的字符。
一旦您拆分了 2 个文件,您需要使用 NASM 将它们组装起来,然后将它们放入磁盘映像中。与您的问题不同,我将使用 DD 构建一个 720k 软盘映像,然后将引导加载程序放在开头(不截断磁盘),然后将第二阶段从扇区开始放在后面。可以这样完成:
# Assemble both components as binary images with NASM
nasm -f bin bootload.asm -o bootload.bin
nasm -f bin stage2.asm -o stage2.bin
# Create a 720k disk image
dd if=/dev/zero of=disk.img bs=1024 count=720
# Place bootload.bin at the beginning of disk.img without truncating
dd if=bootload.bin of=disk.img conv=notrunc
# Place stage2.bin starting at the second 512byte sector and write
# it without truncating the disk image. bs=512 seek=1 will skip the
# first 512 byte sector and start writing stage2.bin there.
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] ; This code is intended to be loaded starting at 0x1000:0x0000
; Which is physical address 0x10000. ORG represents the offset
; from the beginning of our segment.
; Our bootloader jumped to 0x1000:0x0000 which sets CS=0x1000 and IP=0x0000
; We need to manually set the DS register so it can properly find our variables
; like 'var'
mov ax, cs
mov ds, ax ; Copy CS to DS (we can't do it directly so we use AX temporarily)
mov bx, var
mov ah, 0x0e
mov al, [bx]
xor bh, bh ; BH = 0 = Display on text mode page 0
int 0x10
jmp $
var:
db 'X'
; Extend the second stage to (720K - 512 bytes)
; bootload.bin will take up first 512 bytes
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 将是 QEMU 或 Bochs 应该可以使用的 720K 磁盘映像。 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 位寄存器。