assembly 为什么我的汇编代码没有跳转到加载的代码?

qgelzfjb  于 2023-06-30  发布在  其他
关注(0)|答案(1)|浏览(146)

我写了一个简单的OS / bootloader,从磁盘加载4个额外的扇区,然后跳转到它们。但跳跃不起作用代码就挂了。
这是start.S文件

[BITS 16]
[ORG 0x7C00]

PROGRAM_SPACE equ 0x7E00

start:
    mov bp, 0x7c00
    mov sp, bp

    call ReadDisk
    mov bx, DiskSuccesString
    call print
    jmp 0x7E00

hang:
    jmp hang

print:
    push ax
    push bx

    mov ah,0x0e
    .loop:
    cmp word [bx], 0
    je .exit
        mov al,[bx]
        int 0x10
        inc bx
        jmp .loop
    .exit:
    pop ax
    pop bx
    ret



ReadDisk:
    mov ah, 0x01
    mov bx, 0x7E00
    mov al,4
    mov dl,[BOOT_DISK]
    mov ch,0x00
    mov dh,0x00
    mov cl,0x02
    int 0x13

    jc DiskError
    ret

BOOT_DISK:
    db 0

DiskError:
    mov bx, DiskErrorString
    call print
    jmp $

DiskErrorString:
    db 'Error while reading Disk     ',0

DiskSuccesString:
    db 'Succes!',0

times 510-($-$$) db 0 ; pad to 512 bytes and add MBR bootable signature
db 0x55
db 0xaa

这是kernel.S文件:

[BITS 16]
[ORG 0x7E00]
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF

mov bx, msg
call print

jmp $

print:
    push ax
    push bx

    mov ah,0x0e
    .loop:
    cmp word [bx], 0
    je .exit
        mov al,[bx]
        int 0x10
        inc bx
        jmp .loop
    .exit:
    pop ax
    pop bx
    ret

msg:
    db 'Welcome to PotatOS',0

times 2048-($-$$) db 0

这是我用来组装所有东西的文件:

#!/bin/zsh
rm start
rm kernel
nasm start.S
nasm kernel.S
cat start kernel > os.bin
qemu-system-x86_64 -enable-kvm -hda os.bin

我用了一个标签的地址,但取代了它的实际地址,但没有任何变化。

bd1hkmkf

bd1hkmkf1#

这里有很多未解决的问题

Bootstrap 从BIOS接收的唯一信息是DL寄存器中的磁盘标识。不能相信段寄存器包含合适的值。你必须自己设置这些,以便它们适合你的目标,特别是让它们雅阁ORG 0x7C00设置:

xor  ax, ax
mov  ds, ax
mov  es, ax
mov bp, 0x7c00
mov sp, bp

始终与SS段寄存器一起更改SP堆栈指针寄存器。并且始终在SP寄存器之前直接修改SS寄存器:

xor  ax, ax
mov  ss, ax       \ Always together and in this order
mov  sp, 0x7C00   /
ReadDisk:
  mov dl,[BOOT_DISK]
  • ReadDisk* 例程从 * Boot _DISK* 变量中检索值,但该变量从未初始化。设置完段寄存器(至少DS)后,请立即使用mov [BOOT_DISK], dl
ReadDisk:
  mov ah, 0x01

您没有加载任何内容。0x 01是返回AH寄存器中磁盘状态的函数。可以从磁盘读取扇区的BIOS功能编号为0x 02。

jmp  0x7E00
mov  bx, 0x7E00

看到PROGRAM_SPACE equ 0x7E00这行代码,可以这样写:jmp PROGRAM_SPACEmov bx, PROGRAM_SPACE

print:
  push ax
  push bx
  ...
  pop ax
  pop bx
  ret

你放在堆栈上的东西需要以相反的顺序出现!

push ax        \
push bx   \    |
...       |    |
pop  bx   /    |
pop  ax        /
cmp word [bx], 0

您的消息是ASCIIZ字符串。它们的后缀是单个零字节。不要试图用一个字大小的操作来检测这个终结符。因为BIOS.Teletype函数也使用BX作为它的一些输入,你应该避免使用BX作为你的消息指针。使用其他地址寄存器之一。例如cmp byte [si], 0

重写start.S

[BITS 16]
[ORG 0x7C00]

PROGRAM_SPACE equ 0x7E00

start:
    xor  ax, ax
    mov  ds, ax
    mov  es, ax
    mov  ss, ax
    mov  sp, 0x7C00
    mov  [BOOT_DISK], dl     ; Initialize with info from BIOS

    call ReadDisk
    mov  si, DiskSuccesString
    call print
    jmp  PROGRAM_SPACE

print:
    push ax
    push bx
    mov  bx, 0x0007    ; DisplayPage 0, GraphicsColor 7
    mov  ah, 0x0E
.loop:
    mov  al, [si]
    inc  si
    int  0x10
    cmp  byte [si], 0
    jne  .loop
    pop  bx
    pop  ax
    ret

ReadDisk:
    mov  dh, 0
    mov  dl, [BOOT_DISK]
    mov  cx, 0x0002
    mov  bx, PROGRAM_SPACE   ; ES:BX is buffer
    mov  ax, 0x0204
    int  0x13
    jc   DiskError
    ret

DiskError:
    mov  si, DiskErrorString
    call print
    jmp  $

BOOT_DISK:
    db 0

DiskErrorString:
    db 'Error while reading Disk', 0

DiskSuccesString:
    db 'Succes!', 0

times 510-($-$$) db 0
dw 0xAA55

不要忘记根据上面的内容重写kernel.S。

mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFF

无论如何,再次更改SS:SP不是一个好主意。而且一定要始终选择一个偶数放入SP寄存器。0xFFFF是一个真实的糟糕的选择!

相关问题