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

VGA图形模式下字符输出正常但字符串输出失败问题求助

单个字符可正常输出,但字符串输出失败的VGA保护模式代码排查

核心问题排查与修复

1. 字符串位置计算错误

你的put_string函数中字符位置的计算逻辑存在错误:

put_char(s[i], (i+x)*8, y, 0x000f);

(i+x)*8会将起始坐标x与索引i相加后再乘以8,导致第一个字符的x坐标变为x*8而非预期的x(当i=0时),若x不为0,字符会被推到屏幕极右侧甚至超出显示范围。即使x=0,该逻辑也不符合“从x起始位置依次排列字符”的需求,正确的计算方式应为:

put_char(s[i], x + i*8, y, fgcolor); // 改为x加上每个字符的偏移量,同时使用传入的fgcolor参数

另外注意你之前硬编码了颜色值0x000f,未使用函数参数fgcolor,建议统一使用传入的参数以保证逻辑一致性。

2. 字符串指针的内存访问问题

单个字符输出正常,说明put_char与帧缓冲访问逻辑无问题,但字符串输出失败大概率是字符串常量的内存地址在保护模式下无法正确访问:

  • 字符串常量可能被编译器放置在未正确映射的段(比如仅可执行的代码段,无读权限)
  • 16位编译环境生成的字符串地址在32位保护模式下被符号扩展为错误的32位地址

验证与修复方案:

  • 先测试固定字符的循环输出,排除循环逻辑问题:
    void put_string(char* s, int x, int y, int fgcolor){
        // 测试固定字符输出
        for(int i = 0; i < 5; i++){
            put_char('h' + i, x + i*8, y, fgcolor);
        }
        // 执行原循环
        for(int i = 0; s[i]; i++){
            put_char(s[i], x + i*8, y, fgcolor);
        }
    }
    
    如果固定字符能正常显示,说明原循环逻辑无问题,问题出在字符串指针s的访问上。
  • 确保字符串常量被放置在可访问的数据段:使用编译器属性(如GCC的__attribute__((section(".data"))))强制将字符串放入数据段,或修改链接脚本指定数据段的地址与权限。
  • 检查保护模式的段描述符:确保数据段的基地址、限长覆盖字符串所在的内存区域,且段权限设置为可读。

3. 字体加载代码的潜在验证点

虽然单个字符显示正常,但可以验证字体数据是否正确加载到0x80000:

  • 加载字体的int 0x10功能调用(ax=0x1130)返回后,ES:BP指向BIOS字体数据,你的复制逻辑中push es; pop ds已将DS设置为字体所在段,mov si, bp的偏移量正确,rep movsd的次数(256*16/4=1024)也符合4字节复制的需求,这部分逻辑无明显错误,但可通过读取0x80000 + 'h'*16地址的内容,确认是否为'h'的字形数据。

其他注意事项

  • 32位保护模式下,确保栈指针设置正确,函数调用的参数传递符合编译器的调用约定(如cdecl),避免栈溢出导致参数(如字符串指针s)被篡改。
  • 字符串常量需以\0结尾,编译器通常会自动添加,但如果是手动构造的字符串,需确保终止符存在,避免循环越界访问非法内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:48:08