FASM汇编:使用CMOVG指令从内存向AX赋值时程序崩溃的解决
16位实模式FASM程序CMOVG指令崩溃问题解决
问题概述
使用FASM编写16位实模式程序(org 0100h),需在VGA图形模式12h下通过Graphic子程序重绘指定区域背景:遍历280-487列、368-385行像素,检测到黑色像素时,用CMOVG指令将全局变量barvy_kontrola的值加载到AX(AH固定为0Ch,AL为像素值),再调用BIOS中断int 10h的0Ch功能写入像素。程序首次执行CMOVG时崩溃,问题位于Graphic子程序.writePixel子标签内的第4、13、16行(原代码行236附近)。
测试代码(用于在80×25文本区23行35列输出text_b内容):
pusha mov si, text_b call print_string_end2 popa
核心原因分析
- 指令兼容性问题:
CMOVG属于IA-32架构的条件移动指令,仅在Pentium Pro及后续CPU支持,而16位实模式的传统DOS环境可能运行在不支持该指令的早期CPU上,执行时会触发非法指令异常导致崩溃。 - 操作数宽度不匹配:16位模式下
CMOVG要求源和目标操作数宽度完全一致,若代码中直接将字节型的barvy_kontrola赋值给AX(16位寄存器),或使用了不符合16位寻址规则的内存操作数,会触发操作数错误。
解决方案
方案1:用传统条件分支替代CMOVG(兼容所有16位CPU)
放弃CMOVG,改用CMP+JG的分支逻辑实现相同功能,这是16位实模式下最稳妥的做法:
; 假设此前已将当前像素颜色读取到AL中 cmp al, 0 ; 判断是否为黑色像素 jg .skip_write ; 非黑色则跳过写入 mov ah, 0Ch ; 设置BIOS写像素功能号 mov al, [barvy_kontrola] ; 加载目标像素值 int 10h ; 调用BIOS中断写入像素 .skip_write:
方案2:修正CMOVG操作数(仅适用于支持该指令的CPU)
若确认目标CPU支持CMOV系列指令,需严格保证操作数宽度匹配:
- 若
barvy_kontrola是字节型变量:
mov ah, 0Ch ; 固定AH为0Ch cmp al, 0 ; 检测当前像素是否为黑色 mov bl, [barvy_kontrola] ; 先将像素值加载到8位寄存器BL cmovg al, bl ; 条件满足时将BL赋值给AL(保持操作数宽度一致) int 10h ; 调用中断写入像素
- 若
barvy_kontrola是字型变量(高字节预存0Ch,低字节为像素值):
; 假设此前已将当前像素的完整颜色(AH=0, AL=像素值)读取到AX中 cmp ax, 0000h ; 判断是否为黑色像素 cmovg ax, [barvy_kontrola] ; 条件满足时直接替换AX值 int 10h ; 调用中断写入像素
内容的提问来源于stack exchange,提问作者user22969975
相关产品推荐
相关产品推荐

