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

32位保护模式下VGA输出错乱,疑似内存布局或GDT配置问题求助

32位保护模式下VGA输出错乱,疑似内存布局或GDT配置问题求助

各位大佬好,我正在用x86汇编和C写一个引导加载程序和简单内核,切换到32位保护模式后C代码能正常运行,但VGA输出总是错乱——要么消息互相覆盖,要么部分内容直接消失,实在卡壳了来求助!

我正在实现的功能:

  • 从引导加载程序加载并运行简单C内核
  • 进入32位保护模式
  • 通过0xB8000地址直接写入VGA文本内存

目前能正常工作的部分:

  • 引导加载程序能成功加载内核到内存
  • 可以顺利切换进入32位保护模式
  • 少量echo()调用能正常通过VGA显示文本

遇到的问题:

当我给C文件增加更多echo()调用后,输出就开始损坏了:文本会出现在错误的位置,或者部分内容突然消失。感觉像是内存布局出了问题——会不会我看似进入了保护模式,但实际上还受实模式1MB内存限制的影响?

相关代码片段:

引导加载程序及保护模式切换代码(boot.asm):

[org 0x7c00]
KERNEL_LOCATION equ 0x1000

mov [BOOT_DISK], dl
xor ax, ax
mov es, ax
mov ds, ax
mov bp, 0x8000
mov sp, bp

mov bx, KERNEL_LOCATION
mov dh, 2
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
mov dl, [BOOT_DISK]
int 0x13 ; 暂时没加错误处理,之后会补!

mov ah, 0x0
mov al, 0x3
int 0x10 ; 切换到文本模式

CODE_SEG equ GDT_code - GDT_start
DATA_SEG equ GDT_data - GDT_start

cli
lgdt [GDT_descriptor]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_SEG:start_protected_mode

jmp $

BOOT_DISK: db 0

GDT_start:
GDT_null:
    dd 0x0
    dd 0x0
GDT_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 0b10011010
    db 0b11001111
    db 0x0
GDT_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 0b10010010
    db 0b11001111
    db 0x0
GDT_end:

GDT_descriptor:
    dw GDT_end - GDT_start - 1
    dd GDT_start

[bits 32]
start_protected_mode:
    mov ax, DATA_SEG
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000 ; 32位栈基址
    mov esp, ebp

    jmp KERNEL_LOCATION

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

C内核代码示例(kernel.c):

#include <stdint.h>

volatile uint8_t* video = (uint8_t*)0xB8000;

void echo(const char* message, uint8_t color, int row, int col) {
    // VGA内存基地址
    volatile uint8_t* video = (uint8_t*)0xb8000;
    // 确保列数在有效范围(0-79)
    if (col < 0 || col >= 80) return;
    // 计算偏移量
    int offset = (row * 80 + col) * 2;
    // 确保不超出屏幕内存范围
    if (offset >= 4000) return;
    // 写入消息字符
    for (int i = 0; message[i] != '\0'; ++i) {
        // 防止超出80列
        if (col + i >= 80) break;
        // 写入字符和颜色字节
        video[offset + i * 2] = message[i];
        video[offset + i * 2 + 1] = color;
    }
}

int main() {
    echo("HELLO WORLD!", 0xD0, 0, 0);
    // 这里加更多echo调用后就出问题了
    return 0;
}

内核入口代码(entry.asm):

global _start
extern main

section .text
[bits 32]
_start:
    call main
    jmp $

我已经尝试过的方法:

  • 增大栈的大小(把ebp设到更高的地址)
  • 限制echo的输出范围,确保不会越界
  • 手动检查内存布局,确认VGA地址0xB8000未被占用

我的疑问:

是不是我虽然进入了保护模式,但因为没设置分页或者GDT段限配置不对,导致内存不能完全使用?还是内核加载到了错误的内存区域,导致它覆盖了VGA内存或者自身代码?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:43:01