16位fasm汇编编写的vmem视频驱动.twritezs功能异常求助
代码问题排查结果
通用问题
- 16位实模式下直接使用
0xb8000作为32位基地址访问VGA显存不符合实模式寻址规则:实模式下物理地址计算公式为段地址*16 + 偏移地址,VGA文本缓冲区的正确访问方式是设置段寄存器为0xb800,用段+16位偏移访问,直接用32位地址0xb8000在16位汇编环境下会触发地址截断或非法寻址。 - 所有涉及
eax操作的偏移计算如果预期是32位运算,需要确认是否开启了地址大小前缀,16位模式下默认操作数/地址长度都是16位,直接用eax会生成额外前缀,部分环境下可能不兼容。
单函数BUG排查
1. .treadbyte 栈不平衡错误
函数开头push eax ebx仅压入2个寄存器,结尾pop eax ebx di多弹出了未压入的di,会导致栈帧被破坏,ret时读取错误的返回地址,直接触发程序跑飞。
修正方案:将结尾的pop改为pop ebx eax(栈为先进后出结构,弹出顺序要和压入顺序相反)。
2. .twritebyte 地址计算错误
函数内偏移计算时imul eax,2操作的是32位eax,后续inc ax仅修改eax的低16位,当传入的ID值大于32767时,高16位不会同步更新,导致地址计算错误。
修正方案:将inc ax改为inc eax。
3. .twritezs 多重错误(当前测试异常的核心原因)
- 偏移计算逻辑被注释失效:注释了
imul eax,2,传入的POS是字符序号(每个字符占2字节显存),当前直接add ebx, eax相当于把字符序号当作字节偏移使用,地址完全偏离预期。 - 属性和字符写入顺序颠倒:VGA文本模式每个2字节单元的结构是
[低字节:ASCII字符,高字节:属性],当前先把dl(属性)写入ebx,再把al(字符)写入ebx+1,顺序完全颠倒,会导致显示乱码/颜色异常。 - 未保护
si寄存器:lodsb会自动修改si的值,函数开头未压入si,结尾也未恢复,会破坏调用方的si寄存器上下文,导致外层逻辑异常。 - 地址基址错误:同通用问题,16位模式下直接用
0xb8000作为基址不合法。
修正后的.twritezs参考(实模式环境)
.twritezs: ; in:eax=POS, [0 - 3440-len(ZS)]/si=ZS, offset[0 - 32512]/dl=BYTE; out:none push eax ebx si es mov bx, 0xb800 mov es, bx imul eax, 2 mov bx, ax .l: lodsb cmp al, 0x00 je .ret mov byte es:[bx], al ; 低字节写字符 mov byte es:[bx+1], dl ; 高字节写属性 add bx, 2 jmp .l .ret: pop es si ebx eax ret
内容的提问来源于stack exchange,提问作者Våñø Čhët
相关产品推荐
相关产品推荐

