32位保护模式下用变量偏移文本显存地址的异常问题
问题分析
代码存在两个直接导致显存访问错误的问题:
- 汇编语法错误:
add edx, CURSORX执行时,加到edx上的是CURSORX变量的内存地址,而非变量中存储的光标坐标值。x86汇编中要读取内存变量的内容,必须用方括号包裹内存操作数,正确写法是取[CURSORX]的值。 - 偏移计算逻辑错误:VGA文本模式下每个字符显示单元占2字节(1字节ASCII编码、1字节显示属性),水平偏移N个字符位置时,对应的字节偏移量是N * 2,直接加坐标值会导致地址错位,要么写到属性字节位置,要么跨单元覆盖显存数据。
如果CURSORX是单字节存储的坐标值(范围0-79),直接参与32位地址计算时还可能因为高位残留垃圾值导致地址完全越界,访问非显存区域触发CPU异常,这也是屏幕内容全部消失的核心原因——未注册异常处理的情况下,非法内存访问会直接导致CPU复位或跳转至不可预期位置,清空屏幕显示。
正确实现
32位保护模式版本(直接访问线性地址)
mov al, ' ' mov ah, 0xff ; 加载显存基址+第三行(从0开始计数)行偏移,每行80字符共占160字节 mov edx, 0xb8000 + 160*3 ; 零扩展读取单字节存储的X坐标,避免高位脏数据影响地址 movzx ecx, byte [CURSORX] ; 坐标转字节偏移(乘2)后计算最终目标地址 lea edx, [edx + ecx*2] ; 写入显存完成光标位置绘制/擦除 mov word [edx], ax
如果CURSORX定义为32位双字类型,去掉movzx的零扩展逻辑,直接写mov ecx, [CURSORX]即可。
实模式版本(段:偏移寻址)
如果是在16位实模式下开发,不能直接使用32位线性地址,需要通过段寄存器映射显存段:
; 配置附加段寄存器指向文本显存段基址 mov ax, 0xb800 mov es, ax mov al, ' ' mov ah, 0xff ; 计算行偏移 mov bx, 160*3 ; 读取X坐标 movzx cx, byte [CURSORX] ; 计算X对应的字节偏移(乘2) add bx, cx add bx, cx ; 段寻址写入显存 mov [es:bx], ax
运行效果参考
- 无偏移逻辑正常运行效果:

- 地址计算错误时的异常效果:

内容的提问来源于stack exchange,提问作者Markian
相关产品推荐
相关产品推荐

