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

基于NASM编写基础OS内核:平展二进制输出替代方案问询

平展二进制内核实现基础输出的替代方案

为什么不用int 10h?

int 10h是实模式依赖BIOS的中断调用,一旦内核切换到保护模式(像《Bare Bones》教程那样),BIOS中断就没法用了。这时候必须直接操作硬件相关的内存区域,最基础的就是写文本模式的视频内存。

直接写视频内存的正确实现(文本模式)

文本模式下,视频内存的起始地址是0xB8000(实模式和保护模式都能访问,只要内存映射正确)。每个显示字符占2字节:

  • 第1字节:ASCII字符本身
  • 第2字节:显示属性(前景色+背景色,比如0x07就是黑底白字,最常用的默认样式)

下面是NASM平展二进制的可运行示例代码:

; 编译命令:nasm -f bin kernel.asm -o kernel.bin
org 0x100000  ; 假设内核被加载到内存1MB位置(0x100000),这是保护模式内核的常规起始地址

section .text
bits 32  ; 声明使用32位保护模式指令

start:
    mov esi, msg       ; ESI寄存器指向要输出的字符串首地址
    mov edi, 0xB8000   ; EDI寄存器指向视频内存起始地址
    mov ah, 0x07       ; AH存显示属性:黑底白字
.loop:
    lodsb              ; 从ESI指向的内存取1字节到AL,ESI自动+1(取下一个字符)
    test al, al        ; 检查AL是否为0(字符串结束标记)
    jz .done           ; 如果是0,跳转到结束逻辑
    stosw              ; 把AX(AL字符+AH属性)写入EDI指向的内存,EDI自动+2(跳过下一个字符位置)
    jmp .loop          ; 循环处理下一个字符
.done:
    hlt                ; 让CPU暂停,避免执行后续无效代码
    jmp .done          ; 防止hlt被唤醒后乱跑,无限循环

section .data
msg db 'Hello, My OS Kernel!', 0  ; 字符串必须以0结尾,作为循环终止标记

关键代码解释

  • org 0x100000:告诉NASM,编译后的二进制加载到内存0x100000处,这样代码里的地址才会对应正确的内存位置
  • bits 32:明确生成32位指令,因为保护模式下不能用16位实模式指令
  • lodsb和stosw:都是串操作指令,专门用来批量处理字符串/内存数据,比手动移动指针更简洁
  • test al, al:等价于检查字符是否为0,是判断字符串结束的常用方式

你之前尝试失败的常见原因

  1. 没切换到保护模式:如果还在实模式下用32位指令,或者保护模式没正确初始化,访问0xB8000会出问题
  2. 字符串没加结束符:循环没有终止条件,会一直往视频内存写垃圾数据,导致屏幕乱码
  3. 显示属性错误:比如把属性设成和背景色一致(比如黑底黑字),字符会完全看不见
  4. 内存地址错了:误写了单色文本模式的地址0xB0000,但大部分虚拟机默认用彩色文本模式(0xB8000)

验证步骤

用NASM编译:nasm -f bin kernel.asm -o kernel.bin,然后用QEMU加载测试:qemu-system-x86_64 -kernel kernel.bin,正常情况下就能看到屏幕上显示的字符串了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:40:42