assembly - 第二个扇区无法加载到引导文件中

标签 assembly nasm x86-16 qemu bootloader

这是引导加载程序小示例的代码的一部分。
它仅显示“myos”,但不显示“ok”。

. . . 
    mov si, statement1
    call print_string

    
    ; load second sector into memory

    mov ah, 0x02                    ; load second stage to memory
    mov al, 1                       ; numbers of sectors to read into memory
    mov dl, 0x80                    ; sector read from fixed/usb disk
    mov ch, 0                       ; cylinder number
    mov dh, 0                       ; head number
    mov cl, 2                       ; sector number
    mov bx, _OS_Stage_2             ; load into es:bx segment :offset of buffer
    int 0x13                        ; disk I/O interrupt

    jmp _OS_Stage_2                 ; jump to second stage

. . . 

statement1 db "myos", 0


    ; boot loader magic number
    times ((0x200 - 2) - ($ - $$)) db 0x00     ;set 512 bytes for boot sector which are necessary
    dw 0xAA55                                  ; boot signature 0xAA & 0x55


_OS_Stage_2:

. . . 
    mov si, statement2
    call print_string

statement2 db "ok", 0

    ; add how much memory we need
    times (1024 - ($-$$)) db 0x00
 

以下是跳转到_OS_Stage_2的代码。它不起作用。

此处包含完整的源代码

    bits 16]           ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00]        ; organize from 0x7C00 memory location where BIOS will load us



start:              ; start label from where our code starts
xor ax,ax           ; set ax register to 0
mov ds,ax           ; set data segment(ds) to 0
mov es,ax           ; set extra segment(es) to 0
mov bx,0x8000

mov ax,0x13         ;clears the screen
int 0x10            ;call bios video interrupt


mov ah,02           ;clear the screen with big font
int 0x10            ;interrupt displayt

; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10

mov si, command_prompt
call print_string

mov ax,0x00         ; get keyboard input
int 0x16            ; interrupt for hold & read input

; load second sector into memory

mov ah, 0x02                    ; load second stage to memory
mov al, 1                       ; numbers of sectors to read into memory
mov dl, 0x80                    ; sector read from fixed/usb disk
mov ch, 0                       ; cylinder number
mov dh, 0                       ; head number
mov cl, 2                       ; sector number
mov bx, _OS_Stage_2             ; load into es:bx segment :offset of buffer
int 0x13                        ; disk I/O interrupt

jmp _OS_Stage_2                 ; jump to second stage

int 0x19

print_string:
    mov ah, 0x0E            ; value to tell interrupt handler that take value from al & print it

.repeat_next_char:
    lodsb                ; get character from string
    cmp al, 0                    ; cmp al with end of string
    je .done_print               ; if char is zero, end of string
    int 0x10                     ; otherwise, print it
    jmp .repeat_next_char        ; jmp to .repeat_next_char if not 0

.done_print:
    ret                         ;return


command_prompt db "myos", 0

; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00     ;set 512 bytes for boot sector which are necessary
dw 0xAA55                                  ; boot signature 0xAA & 0x55


_OS_Stage_2:

mov al,2                    ; set font to normal mode
mov ah,0                    ; clear the screen
int 0x10                    ; call video interrupt

mov si, statement
call print_string

statement db "ok", 0

; add how much memory we need
times (1024 - ($-$$)) db 0x00

上面的代码是通过 NASM 在 ubuntu 上使用 qemu 模拟器通过 ./build-linux.sh (文件) 进行汇编的,如下所示。

#!/bin/sh

if test "`whoami`" != "root"
then
  echo "You must be logged in as root to build (for loopback mounting)"
  echo "Enter 'su' or 'sudo bash' to switch to root"
  exit
fi

if [ ! -e disk_images/os.flp ] then
  echo ">>> Creating new OS floppy image..."
  mkdosfs -C disk_images/os.flp 1440 || exit
fi

echo ">>> Assembling bootloader..."

nasm -O0 -w+orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit


echo ">>> Adding bootloader to floppy image..."

dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit

echo ">>> Creating CD-ROM ISO image..."

rm -f disk_images/os.iso
mkisofs -quiet -V 'OS' -input-charset iso8859-1 -o disk_images/os.iso -b os.flp disk_images/ || exit

echo '>>> Done!'

test-linux(文件)运行程序如下

#!/bin/sh

qemu-system-i386 -soundhw pcspk -drive format=raw,file=disk_images/os.flp,index=0,if=floppy

最佳答案

主要问题:您将单元 80h 硬编码为从引导加载单元加载,但您将镜像作为软盘驱动器传递到 qemu,因此您应该使用单元 00h。

解决方案:保留 dl 寄存器(dx 的一部分),因为它在进入加载程序时保持不变。先前的加载程序将当前的引导加载单元传递给您在此寄存器中,因此只需使用它即可。


其他挑剔:

  • 没有错误处理,失败时只会崩溃。

  • 堆栈应由您的代码设置,以避免可能干扰您的扇区负载。

  • 运行完成后,您应该进行某种无限循环来结束,而不是让执行继续到代码末尾。我围绕 sti\hlt 做了一个循环以节省电量。

  • 您列出的完整源代码还有另一个错误,它缺少 bits 指令的左方括号 [。 (这似乎是 NASM 允许的,但这是错误的。)删除右方括号也是有效的,有两种形式的 bits 指令,带括号或不带括号。

  • 您没有在构建脚本中安装任何内容,因此您不需要成为 root 用户。

  • 此时您不需要创建 ISO 镜像,实际上也没有使用它来运行您的程序。

  • 如果您只是覆盖前两个扇区,则无需创建 DOS 文件系统,这会导致文件系统无法使用。我用另一个 dd 命令替换了它。


这是我的固定脚本和源代码,但错误处理和堆栈设置仍然缺失。脚本:

#!/bin/sh

if [ ! -e disk_images/os.flp ]
then
  echo ">>> Creating new OS floppy image..."
  dd if=/dev/zero of=disk_images/os.flp bs=1024 count=1440 || exit
fi

echo ">>> Assembling bootloader..."
nasm -O0 -w+orphan-labels -f bin -o source/bootload/nasma/boot.bin source/bootload/nasma/boot.asm || exit

echo ">>> Adding bootloader to floppy image..."
dd status=noxfer conv=notrunc if=source/bootload/nasma/boot.bin of=disk_images/os.flp || exit

echo '>>> Done!'

来源:(注意 push dxpop dxsti\hlt 循环。)

[   bits 16]           ; tell assembler that working in real mode(16 bit mode)
[org 0x7c00]        ; organize from 0x7C00 memory location where BIOS will load us

start:              ; start label from where our code starts
xor ax,ax           ; set ax register to 0
mov ds,ax           ; set data segment(ds) to 0
mov es,ax           ; set extra segment(es) to 0
mov bx,0x8000

push dx

mov ax,0x13         ;clears the screen
int 0x10            ;call bios video interrupt


mov ah,02           ;clear the screen with big font
int 0x10            ;interrupt displayt

; cursor position
mov al, 2
mov ah, 0
mov bl, 4
mov bh, 0
int 0x10
mov si, command_prompt
call print_string

mov ax,0x00         ; get keyboard input

int 0x16            ; interrupt for hold & read input

; load second sector into memory

mov ah, 0x02                    ; load second stage to memory
mov al, 1                       ; numbers of sectors to read into memory
pop dx
; mov dl, 0x80                    ; sector read from fixed/usb disk
mov ch, 0                       ; cylinder number
mov dh, 0                       ; head number
mov cl, 2                       ; sector number
mov bx, _OS_Stage_2             ; load into es:bx segment :offset of buffer
int 0x13                        ; disk I/O interrupt

jmp _OS_Stage_2                 ; jump to second stage

int 0x19

print_string:
    mov ah, 0x0E            ; value to tell interrupt handler that take value from al & print it

.repeat_next_char:
    lodsb                ; get character from string
    cmp al, 0                    ; cmp al with end of string
    je .done_print               ; if char is zero, end of string
    int 0x10                     ; otherwise, print it
    jmp .repeat_next_char        ; jmp to .repeat_next_char if not 0

.done_print:
    ret                         ;return


command_prompt db "myos", 0

; boot loader magic number
times ((0x200 - 2) - ($ - $$)) db 0x00     ;set 512 bytes for boot sector which are necessary
dw 0xAA55                                  ; boot signature 0xAA & 0x55


_OS_Stage_2:

mov al,2                    ; set font to normal mode
mov ah,0                    ; clear the screen
int 0x10                    ; call video interrupt

mov si, statement
call print_string

haltloop:
sti
hlt
jmp haltloop

statement db "ok", 0

; add how much memory we need
times (1024 - ($-$$)) db 0x00

关于assembly - 第二个扇区无法加载到引导文件中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72498957/

相关文章:

c - 如何使用 Sublime Text 生成程序集输出?

c - 如何在没有 Glibc 的情况下在 C 中使用内联汇编获取参数值?

function - 在 Nasm 中调用汇编函数

macos - 在 Mac OS X Maverick 上安装/编译 NASM 包

assembly - 如何从 DOS 中的标准输入读取字符以便重定向工作?

assembly - ljmp指令在linux内核fork系统调用中起什么作用?

c - 在单独的编译单元中调用函数是否有更多开销?

x86 - NASM 中断 x86 引用?

assembly - 为什么我们必须在MS-DOS 中初始化DS 和ES 寄存器?

8086 中的汇编代码