基于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,是判断字符串结束的常用方式
你之前尝试失败的常见原因
- 没切换到保护模式:如果还在实模式下用32位指令,或者保护模式没正确初始化,访问0xB8000会出问题
- 字符串没加结束符:循环没有终止条件,会一直往视频内存写垃圾数据,导致屏幕乱码
- 显示属性错误:比如把属性设成和背景色一致(比如黑底黑字),字符会完全看不见
- 内存地址错了:误写了单色文本模式的地址
0xB0000,但大部分虚拟机默认用彩色文本模式(0xB8000)
验证步骤
用NASM编译:nasm -f bin kernel.asm -o kernel.bin,然后用QEMU加载测试:qemu-system-x86_64 -kernel kernel.bin,正常情况下就能看到屏幕上显示的字符串了。
内容的提问来源于stack exchange,提问作者user1234
相关产品推荐
相关产品推荐

