You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换至GDT/保护模式后print.asm无法输出问题求助

问题分析与修复方案

你的代码存在几个关键问题,导致保护模式下无法输出内容,同时实模式阶段的调用逻辑也存在错误,逐一说明如下:

1. 实模式错误调用32位print函数

boot.asm的start段处于16位实模式,但你引入的print.asm是[bits 32]标记的保护模式函数。实模式下执行32位指令会直接引发崩溃,程序根本无法进入保护模式,更无法执行后续的输出逻辑。

修复:

  • 拆分print模块,分别实现实模式16位print和保护模式32位print,调用时严格匹配当前运行模式。
  • 实模式print使用BIOS中断int 0x10(ah=0x0e)实现字符输出,保护模式直接操作显存地址0xb8000。

2. 保护模式print函数的寄存器传递错误

print.asm中,你将字符串地址存入ecx,但lodsb指令默认从esi寄存器读取数据,未将ecx的值传递给esi,导致无法正确读取字符串内容,自然无法输出。

修复:

在print函数开头添加mov esi, ecx,将字符串地址从ecx转移到esi,供lodsb指令使用。

3. 磁盘读取功能号错误

disk.asm中int 0x13的功能号ah=0x01是读取磁盘状态,而非读取扇区。正确的读扇区功能号是ah=0x02,否则磁盘读取逻辑完全失效,还会触发diskErr调用32位print函数,进一步引发崩溃。

修复:

将mov ah, 0x01改为mov ah, 0x02,同时添加重试次数限制,避免无限死循环。


修正后的关键代码片段

实模式print模块(print16.asm)

[bits 16]
print16:
    pusha
    mov ah, 0x0e
.print_loop:
    lodsb
    cmp al, 0
    je .print_done
    int 0x10
    jmp .print_loop
.print_done:
    popa
    ret

保护模式print模块(print32.asm)

[bits 32]
videoMemory equ 0xb8000
whiteOnBlack equ 0x0f

print32:
    pusha
    mov edx, videoMemory
    mov esi, ecx  ; 将字符串地址从ecx转到esi,供lodsb使用
    mov ebx, whiteOnBlack

    call printString32
    popa
    ret

printString32:
    pusha

.loop:
    lodsb
    cmp al, 0
    je .done
    mov [edx], al
    mov [edx+1], bl  ; 单独写入属性字节,避免ax寄存器高位干扰
    add edx, 2
    jmp .loop

.done:
    popa
    ret

修正后的boot.asm调用逻辑

[ORG 0x7C00]

jmp start

%include "boot/disk.asm"
%include "boot/print16.asm"  ; 引入实模式print
%include "boot/gdt.asm"
%include "boot/switch.asm"
%include "boot/print32.asm"  ; 引入保护模式print

hang:
    jmp hang

start:
    mov bp, 0x9000
    mov sp, bp
    
    mov si, realmsg  ; 实模式用si传递字符串地址
    call print16

    mov si, loadmsg
    call print16

    mov si, protmsg
    call print16

    call switchPM

    ; 以下代码不会执行,因为switchPM直接跳转到beginPM
    mov si, diskmsg
    call print16

    call diskLoad
    jc diskErr

    jmp hang

; 常量定义保持不变
realmsg db "Loading real mode...", 0x0D, 0x0A, 0
loadmsg db "Loading OS...", 0x0D, 0x0A, 0
diskmsg db "Loading disk sectors...", 0x0D, 0x0A, 0
diskmsgdone db "Disk sectors loaded", 0x0D, 0x0A, 0
diskerr db "Error loading disk sectors", 0x0D, 0x0A, 0
protmsg db "Loading protected mode...", 0x0D, 0x0A, 0
protmsgdone db "Protected mode loaded", 0x0D, 0x0A, 0

times 510-($-$$) db 0
db 0x55
db 0xAA

[bits 32]
beginPM:
    mov ecx, protmsgdone
    call print32
    jmp hang  ; 停在此处查看保护模式输出

修正后的disk.asm

diskLoad:
    mov bx, 0x8000
    mov dh, 0x00
    mov dl, 0x80
    mov ch, 0x00
    mov cl, 0x02
    mov al, 0x01
    mov ah, 0x02  ; 改为读扇区功能号
    int 0x13
    jc .retry
    ret
.retry:
    dec byte [retry_count]
    jnz diskLoad
    jmp diskErr

retry_count db 3  ; 限制重试3次,避免死循环

diskErr:
    mov si, diskerr
    call print16
    jmp hang

额外注意事项

  • switchPM执行后会直接跳转到32位的initPM,再调用beginPM,因此boot.asm中call switchPM之后的代码永远不会执行。你需要把磁盘读取逻辑移到保护模式下实现,或者在进入保护模式前完成磁盘读取。
  • 进入保护模式后,BIOS中断无法使用,若需磁盘操作,需自行实现32位ATA磁盘驱动。

内容的提问来源于stack exchange,提问作者Pigioty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:45:32