引导加载程序中Int 10h ah=0eh输出异常,自定义OS打印函数故障排查
解决print_string函数输出乱码的问题
看起来你的字符串打印函数逻辑本身没问题,但输出的是乱码Wn=Wn=而不是预期的"hello",大概率是段寄存器不匹配或者DF标志异常导致的,我来帮你排查下:
首先,先看几个关键问题点:
1. 段寄存器DS和Msg所在段不匹配
实模式下内存地址是「段寄存器值左移4位 + 偏移量」,你只给SI设置了Msg的偏移量,但如果DS寄存器的段基址和Msg实际所在的段不一样,那DS:SI指向的就不是你定义的"hello",而是内存里的随机垃圾数据,自然输出乱码。
比如如果你的代码是bootloader(加载到0x7C00),启动时CS寄存器的值是0x07C0,但DS默认可能是0x0000,这时候你直接用SI指向Msg的偏移量,实际访问的是0x0000:offset,而不是0x07C0:offset(也就是0x7C00+offset),完全不是你定义的字符串。
解决方法:在调用print_string前,把DS设置成和Msg所在的段一致。如果Msg在代码段里,直接把CS的值传给DS就行:
mov ax, cs mov ds, ax ; 让DS和CS同段,确保偏移量正确
2. DF标志导致SI反向读取
lodsb指令的行为受DF方向标志影响:如果DF是0(默认应该是0),SI会自动+1,依次读取下一个字符;如果DF被不小心设成1,SI会-1,导致重复读取前面的字节,也会出现乱码。
保险起见,在调用函数前加一句cld来强制设置DF为0:
cld ; 确保SI按递增方向读取字符串
3. 确认Msg的终止符是否正确
你提到Msg内容是"hello",要确保定义时加了终止符0,不然lodsb会一直读内存直到碰巧遇到0,也可能输出乱码:
Msg db 'hello', 0 ; 必须加0作为字符串结束标记
修正后的完整示例代码
把这些修正点加进去,代码应该就正常了:
; 初始化段寄存器和方向标志 mov ax, cs mov ds, ax cld ; 调用打印函数 mov si, Msg call print_string ; 字符串打印函数 print_string: pusha mov ah, 0Eh ; int 10h的0Eh功能:Teletype输出 .repeat: lodsb ; 读取DS:SI指向的字节到AL,SI自动增减 cmp al, 0 ; 判断是否到字符串结束 je .done int 10h ; 调用BIOS中断打印字符 jmp .repeat .done: popa ret ; 定义字符串 Msg db 'hello', 0
这样调整后,应该就能正确输出"hello"了。
内容的提问来源于stack exchange,提问作者Gamer0010101
相关产品推荐
相关产品推荐

