x86 程序集:int13h 似乎无法加载程序
x86 Assembly: int13h seems to not load program
最近我一直在尝试做一个操作系统来玩,我从引导加载程序开始。首先,我想首先说明我昨天问了另一个关于相同副作用的问题(程序不是 运行),但事实证明原因可能与我最初想的不同。所以,这是引导加载程序代码:
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
您正在将 bootloader.asm
与 nasm -f elf
组装在一起,这在默认情况下会导致其成为 assemble 32 位代码。因此,当 运行 在 16 位实模式下时,您得到的机器代码不会做正确的事情。
您可以通过将 bits 16
放在 bootloader.asm
文件的顶部来解决这个问题。但是 ELF 目标文件格式首先不是为 16 位代码设计的,尝试将它用于这么小的代码段是相当荒谬的。相反,我建议只使用
构建引导扇区
nasm -f bin -o bootloader.bin bootloader.asm
因为 -f bin
默认使用 16 位模式。然后跳过 ld
和 objcopy
行,并使用 bootloader.bin
代替您之前调用的 bootloader.o
(这不是一个好的文件名,因为 .o
通常表示可重定位目标文件,而不是二进制映像)。
你不会有调试信息,但对于像引导扇区这样短的代码来说,这无论如何都是不必要的。只需让您的调试器在逐步执行指令时取消assemble指令,并与您的源代码进行比较。
修复此问题和评论中提到的错误(覆盖 cx
中的磁道和扇区号,并需要 jmp 0x5000:0000
)代码成功启动、加载和 运行是扇区。它会在屏幕上显示 I
并停止,就像您告诉它的那样。
最近我一直在尝试做一个操作系统来玩,我从引导加载程序开始。首先,我想首先说明我昨天问了另一个关于相同副作用的问题(程序不是 运行),但事实证明原因可能与我最初想的不同。所以,这是引导加载程序代码:
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
您正在将 bootloader.asm
与 nasm -f elf
组装在一起,这在默认情况下会导致其成为 assemble 32 位代码。因此,当 运行 在 16 位实模式下时,您得到的机器代码不会做正确的事情。
您可以通过将 bits 16
放在 bootloader.asm
文件的顶部来解决这个问题。但是 ELF 目标文件格式首先不是为 16 位代码设计的,尝试将它用于这么小的代码段是相当荒谬的。相反,我建议只使用
nasm -f bin -o bootloader.bin bootloader.asm
因为 -f bin
默认使用 16 位模式。然后跳过 ld
和 objcopy
行,并使用 bootloader.bin
代替您之前调用的 bootloader.o
(这不是一个好的文件名,因为 .o
通常表示可重定位目标文件,而不是二进制映像)。
你不会有调试信息,但对于像引导扇区这样短的代码来说,这无论如何都是不必要的。只需让您的调试器在逐步执行指令时取消assemble指令,并与您的源代码进行比较。
修复此问题和评论中提到的错误(覆盖 cx
中的磁道和扇区号,并需要 jmp 0x5000:0000
)代码成功启动、加载和 运行是扇区。它会在屏幕上显示 I
并停止,就像您告诉它的那样。