汇编代码中变量值意外变更问题排查求助(基于QEMU虚拟机)
问题分析与解决思路
核心原因推测
从你描述的现象和代码来看,cmdsize 莫名被修改的概率最高的两个方向:
- BIOS中断的寄存器破坏副作用:实模式下BIOS中断(如
int 0x10、int 0x16)不会保存所有通用寄存器,若你的代码依赖未被保护的寄存器,可能间接引发内存访问错误; - 变量地址与系统预留内存重叠:实模式低地址内存(0x0000~0xFFFF)是BIOS数据区、中断向量表等系统预留区域,若
cmdsize被定义在这些区域,会被BIOS操作意外覆盖。
具体排查与修复步骤
1. 修复寄存器保护问题
BIOS中断会修改部分寄存器,必须在调用前保存、调用后恢复,避免后续逻辑出错:
; 等待键盘输入前,保存所有通用寄存器到栈 push ax push bx push cx push dx push di mov ah, 0 int 0x16 ; 恢复寄存器 pop di pop dx pop cx pop bx pop ax cmp al, 0x0D je inputend
同时修改printChar函数,避免破坏bx寄存器(int 0x10 ah=0xe会用到bx指定页码):
printChar: push bx mov ah, 0x0e mov bh, 0 ; 强制指定视频页码为0,避免依赖BIOS默认值 int 0x10 pop bx ret
调用printChar前也记得保存ax(因为函数会修改ah):
mov ax, [cmdsize] add al, 0x30 push ax call printChar pop ax
2. 检查并更换变量内存位置
若cmdsize被定义在低地址(如0x0000~0xFFFF),大概率和BIOS预留区冲突。解决方法:
- 将变量移到0x07E00之后的内存(软盘引导扇区默认加载到0x7C00,0x7E00之后是安全区);
- 或者直接使用高地址段,比如用
org 0x1000指定代码加载基址,把变量放在这个段内; - 无调试器情况下,可手动打印
cmdsize的物理地址验证:
; 打印cs:cmdsize的物理地址(示例逻辑) mov ax, cs mov dx, cmdsize ; 自行实现十六进制打印函数,输出ax:dx组合的物理地址
对比实模式内存映射表,确认地址不在BIOS预留区(如0x0040~0x005F是BIOS数据区,绝对不能用)。
3. 排除内存写入的潜在错误
虽然你注释了mov di,cx到mov [di],al的代码,但要确认cx的初始值是否合法。如果之前逻辑中cx未被正确初始化,即使注释写入代码,后续若有其他依赖cx的操作,仍可能间接影响内存访问。
内容的提问来源于stack exchange,提问作者SCP-1762
相关产品推荐
相关产品推荐

