x86程序集:int13h似乎并没有加载程序



最近我一直在尝试制作一个有趣的操作系统,并从引导加载程序开始。首先,我想说,昨天我问了另一个关于相同副作用(程序未运行(的问题,但事实证明,原因可能与我最初想象的不同。所以,这是引导程序代码:

start: jmp boot
boot:
cli                               ; Disable interrupts
cld                               ; Clear direction flags

mov al, 2                         ; Read 2 sectors
mov ch, 0                         ; Track 0
mov cl, 2                         ; Read 2nd sector (1st sector is bootloader)
mov dh, 0                         ; Head number
mov dl, 0                         ; Drive number (0 = floppy drive)
; Specify memory address to read floppy to
mov cx, 0x5000
mov bx, cx
mov es, bx
xor bx, bx
mov ah, 0x2                       ; INT 0x13 with AH=0x2 means read sector
int 0x13                          ; Call BIOS to read sector
jmp cx                            ; Jump to sector
; Must be 512 bytes
times 510 - ($-$$) db 0
dw 0xAA55                           ; Boot Signature

然而,我从未运行过这个示例程序。在QEMU上运行这个程序时,我以前认为问题是jmp去错了地址,但现在在获得内存转储并进行更多调试后,我发现jmp发生了,它去到了正确的地址,但地址0x5000都是零,绝对没有任何内容,也没有任何接近它的内容。这可能是GDB/QEMU不擅长分割或真实模式的问题吗?我读到一些关于这方面的文章。或者我用错了int 0x13?也许分割不能这样工作?既然我使用寄存器的值作为地址,开始将数据存储到其中,然后也使用它跳到那里,那么它不应该是完全相同的地址吗?因此应该是正确的吗?我在网上找不到任何有助于解决这个问题的东西,我完全困惑了。请开导我。感谢所有的帮助,谢谢!

构建磁盘映像所采取的步骤:

首先,我用构建引导程序

nasm -f elf bootloader.asm -F dwarf -g -o ../build/bootloader/bootloader.o
ld -m elf_i386 -T bootloader.lds ../build/bootloader/bootloader.o -o ../build/bootloader/bootloader.o.elf
objcopy -O binary  ../build/bootloader/bootloader.o.elf ../build/bootloader/bootloader.o

链接器脚本:

OUTPUT(bootloader);
PHDRS
{
headers PT_NULL;
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ;
}

SECTIONS
{
. = SIZEOF_HEADERS;
.text 0x7c00:  {  *(.text)  } :text
.data :  {  *(.data)  } :data
}

为了用调试信息创建它,使它更容易与GDB一起使用。

然后,这是我使用的示例程序:

start: jmp MovCursor
MovCursor:
cld
mov ah, 0x2
mov bh, 0
mov dh, 12
mov dl, 0
int 0x10
jmp PutChar
PutChar:
mov ah, 0xA
mov al, 0x49
mov bh, 0
mov cx, 1
int 0x10
hlt
jmp Print
Print:
mov si, msg          ; Load start address of the message into SI
jmp printstring
printstring:
xor ax, ax
mov ds, ax
lodsb                ; Load byte at DS into AL, increment SI
or al, al            ; Check if AL is 0 (and set flags)
jz exitloop          ; If zero jump to end
mov ah, 0xE          ; INT 0x10/AH=0xE is teletype output
int 0x10             ; Call BIOS to print
jmp printstring      ; Repeat for next character
exitloop:
hlt
msg db "Welcome to kOS!", 0ah, 0dh, 0h

使用nasm -f bin os/io.asm -o os/io编译为原始二进制文件。

然后,最后,构建图像:

dd if=/dev/zero of=disk.img bs=512 count=2880
dd if=build/bootloader/bootloader.o of=disk.img bs=512 seek=0
dd if=os/io of=disk.img bs=512 seek=1

QEMU命令:qemu-system-i386 -machine q35 -fda disk.img -gdb tcp::26000 -S

您正在用nasm -f elf组装bootloader.asm,默认情况下,这会导致它组装32位代码。因此,当在16位真实模式下运行时,您得到的机器代码不会做正确的事情。

您可以通过将bits 16放在bootloader.asm文件的顶部来解决此问题。但是ELF对象文件格式一开始并不是为16位代码设计的,试图将其用于如此小的代码段是相当荒谬的。相反,我建议使用构建引导扇区

nasm -f bin -o bootloader.bin bootloader.asm

因为CCD_ 10默认使用16位模式。然后跳过ldobjcopy行,使用bootloader.bin来代替之前所说的bootloader.o(这不是一个好的文件名,因为.o通常意味着一个可重定位的对象文件,而不是二进制映像(。

您不会有调试信息,但对于像引导扇区这样短的代码来说,这是不必要的。只要让调试器在逐步执行指令时对其进行反汇编,并与源代码进行比较。

在修复了这个问题和注释中提到的错误(覆盖cx中的磁道和扇区号,并且需要jmp 0x5000:0000(之后,代码成功地引导、加载和运行了扇区。它在屏幕上显示I并停止,就像你告诉它的那样。

相关内容

最新更新