【问题标题】:8086 assembly on DOSBox: Bug with idiv instruction?DOSBox 上的 8086 程序集:带有 idiv 指令的错误?
【发布时间】:2017-09-20 08:34:29
【问题描述】:

我正在帮助我的一个朋友调试他的程序,我们将其范围缩小到一个即使在这里也会出现的问题:

.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 行,无限地再次执行它。

有人对此有什么解释吗?

【问题讨论】:

  • 因为除法的有符号商无法放入 8 位寄存器 (AL),所以会出现算术溢出。 r16/r8 IDIV 的商的范围是 -128 到 +127 。您的除法得出的商为 207。
  • @MichaelPetch:是的。我正要提交这个作为答案,但你打败了我!
  • 那将是 INT 00h 中断处理程序。让我有点惊讶的是,它只是直接跳回到损坏的代码,导致无限循环。我原以为它会终止应用程序、打印错误消息或更明显的东西。您是这么多天来第二个对此感到困惑的人。
  • 除法溢出与除以零相同的异常。您应该设置异常处理或使用 16 位操作防止溢出。
  • 啊,是的,当然。我没有想到手术的那个方面。组装还是新手。简单地把它变成一个分词应该可以解决它吗?

标签: assembly x86 x86-16 tasm dosbox


【解决方案1】:

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


您的调试器似乎跳转到的明显随机代码是算术异常处理程序(也与除以零相同)。发生的事情是您的代码遇到了Division Overflow。您正在执行 16 位/8 位 IDIV。来自文档:

有符号的AX除以r/m8,结果存储在:AL←商,AH←余数。

您会注意到,对于使用 8 位除数(在您的情况下为 BL)的除法,商的范围是 -128 到 +127。 044c0h IDIV 85 是 207(十进制)。 207 不适合带符号的 8 位寄存器,因此您会出现除法溢出和意外问题的原因。

要解决此问题,您可以使用 16 位除数。因此,您可以将除数放在 BX(16 位寄存器)中。那将是mov bx, 85。不幸的是,事情并非如此简单。使用 16 位除数时,处理器假定被除数为 32 位,DX 为高 16 位,AX 为低 16 位。

有符号的DX:AX除以r/m16,结果存储在AX←商,DX←余数中。

要解决此问题,您必须对 AX 中的 16 位值进行符号扩展。这很简单,因为您只需要在将值放入 AX 后使用CWD 指令即可。来自指令集参考

DX:AX ← AX 的符号扩展。

如果 AX 的最高有效位 (MSB) 为 0,DX 将变为 0。如果 MSB 为 1,则 DX 将变为 0ffffh(所有位设置为 1)。数字的符号位是 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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多