x86-16位ISA下16位DIV指令触发程序崩溃的原因分析
16位DIV指令崩溃问题排查
示例代码的溢出点定位
本次代码的崩溃是寄存器配置错误直接导致的,和你预期计算的10/2简单运算无关:
16位宽度的DIV指令,默认被除数是DX与AX拼接组成的32位无符号数——执行时会自动把DX的值作为被除数的高16位,AX的值作为被除数的低16位参与运算。
你的代码执行流程:
- 给AX赋值10
- 给DX赋值2
- 执行
div dx指令
此时实际参与计算的被除数是(DX << 16) + AX = (2 << 16) + 10 = 131082,除数是源操作数DX的值2,计算得到的商为65541。而AX寄存器仅能存储16位无符号数(最大范围0~65535),这个商已经超出AX的存储上限,直接触发除法溢出崩溃。
DIV指令的结果存储规则
16位操作数宽度的DIV执行完成后,结果确实拆分存储在DX和AX寄存器中,但分工是固定的:
AX存放除法运算的商DX存放除法运算的余数
不存在两个寄存器混合存储完整结果的逻辑。
DIV指令触发溢出异常的具体条件
满足以下任意一种情况,就会触发x86的0号除法错误中断,直接导致程序崩溃:
- 除数的值为0,无有效运算意义
- 无符号除法计算得到的商值,超过对应商寄存器的最大可表示范围:
- 执行8位宽度DIV(r/m8)时,商存入AL寄存器,只要商值>255(8位无符号最大值)就触发异常
- 执行16位宽度DIV(r/m16)时,商存入AX寄存器,只要商值>65535(16位无符号最大值)就触发异常
- 执行32位宽度DIV(r/m32)时,商存入EAX寄存器,只要商值>4294967295(32位无符号最大值)就触发异常
修正提示:如果目标是计算10除以2的结果,需要在执行DIV前将作为被除数高位的DX寄存器清零(可用
xor dx,dx实现),再把除数放到不涉及DX、AX的寄存器中(比如BX、CX)作为DIV的源操作数,避免污染被除数的高位段。
内容的提问来源于stack exchange,提问作者mattstack
相关产品推荐
相关产品推荐

