DOSBox上的8086程序集:idiv指令的错误?

问题描述:

我在帮我的一个朋友调试他的程序,我们把范围缩小到这里竟然出现了问题:DOSBox上的8086程序集:idiv指令的错误?

.MODEL small 
.STACK 16 
.CODE 
start: 
    mov ax, 044c0h 
    mov bl, 85 
    idiv bl 
exit: 
    mov ax, 4c00h 
    int 21h 

end start 

与TASM 4.1组装完毕,并在DOSBox中0.74运行它,它进入一个无限循环。当用turbo调试器检查时,可以看到它发生在idiv指令之后,该指令出于某种原因修改了csip寄存器,并且在两条看似随机的指令将它们恢复为指向idiv行之后,再次无限次地执行它。

有没有人有任何解释?

+3

因为你的部门的签字商不能在8位寄存器(_AL_)严丝合缝你会得到算术溢出。 r16/r8 [IDIV](http://www.felixcloutier.com/x86/IDIV.html)上商的范围是-128到+127。你的部门产量为207. –

+1

@MichaelPetch:是的。我正要提交这个答案,但你打败了我! – wallyk

+1

这将是INT 00h中断处理程序。有点令我惊讶的是,它只是跳回到破损的代码,导致无限循环。我本来会期望它终止应用程序,打印一条错误消息,或者更明显一些。你是多少天里第二个被这个困惑的人。 –

这个问题是其他分裂相关失败的变体。该x86 tag wiki有一些额外的链接:


明显随机代码的调试器似乎跳到是算术异常处理程序(也同实施除以零)。发生什么事是您的代码正在经历Division Overflow。你正在做一个16位/ 8位IDIV。从文档:

签署的鸿沟AX由r/m8,结果存储在:AL←商,AH←余数。

enter image description here

你会发现,为师带一个8位的除数(在你的情况BL)为商范围为-128至+127。 044c0h IDIV 85是207(十进制)。 207不适合签名的8位寄存器,因此会导致分区溢出并导致意外问题。

要解决这个问题,您可以移动一个16位的除数。因此,您可以将您的除数放入BX(16位寄存器)。那将是mov bx, 85。不幸的是,它并不那么简单。当使用16位分频因子时,处理器假定分辨率为32位,高位16位,DX,低位16位,AX

签名除法DX:AX by r/m16,结果存储在AX←商,DX←余数中。

要解决此问题,您必须在AX上签名扩展16位值。这很简单,因为在将值放入AX之后,您只需要使用指令。从指令设定的基准

DX:AX←AX的符号扩展。

有效如果AX的最高有效位(MSB)为0 DX将成为0。如果MSB为1则DX将成为0FFFFH(设置为一个所有位)。数字的符号位是MSB。

有了这一切记住你的区划代码可以被调整,以一个16位除数:

mov ax, 044c0h 
cwd    ; Sign extend AX into DX (DX:AX = 32-bit dividend) 
mov bx, 85   ; Divisor is 85 
idiv bx   ; Signed divide of DX:AX by BX