DOSBox上的8086汇编:idiv指令出错? [英] 8086 assembly on DOSBox: Bug with idiv instruction?

查看:220
本文介绍了DOSBox上的8086汇编:idiv指令出错?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当时正在帮助我的一个朋友调试他的程序,我们将其范围缩小到甚至在这里出现的问题:

I was helping a friend of mine debug his program, and we narrowed it down to an issue which occurs even here:

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

After assembling it with tasm 4.1, and running it on DOSBox 0.74, it goes into an infinite loop. When inspecting it with turbo debugger one can see it happens after the idiv instruction, which for some reason modifies the cs and ip registers, and after two seemingly random instructions restores them to point to the idiv line, executing it again ad infinitum.

有人对此有任何解释吗?

Does anyone have any explanation for this?

推荐答案

此问题是与其他部门相关的失败的变体. x86标签Wiki 具有一些其他链接:

This question is a variation on other division related failures. The x86 tag wiki has some additional links:

  • idiv/div问题:
  • idiv / div problems: Zero edx first, or sign-extend eax into it.. 32bit div faults if the 64b/32b => 32b quotient doesn't actually fit in 32b.


您的调试器似乎跳转到的看似随机的代码是算术异常处理程序(与除以零"相同).发生的情况是您的代码遇到Division Overflow.您正在执行16位/8位 IDIV .从文档中:


The apparently random code your debugger seems to jump to is the Arithmetic Exception handler (also the same one as Divide by Zero). What is happening is that your code is experiencing a Division Overflow. You are doing a 16-bit/8-bit IDIV. From the documentation:

用AX除以r/m8,结果存储在:AL←商,AH←余数.

Signed divide AX by r/m8, with result stored in: AL ← Quotient, AH ← Remainder.

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

You will notice that for division with an 8-bit divisor (in your case BL) the range for the quotient is -128 to +127. 044c0h IDIV 85 is 207 (decimal). 207 doesn't fit in a signed 8-bit register so you get division overflow and the cause of your unexpected problem.

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

To resolve this you can move up to a 16-bit divisor. So you can place your divisor in BX (16-bit register). That would be mov bx, 85. Unfortunately it isn't so simple. When using a 16-bit divisor the processor assumes the dividend is 32-bits with high 16-bits in DX and lower 16-bits in AX.

用DX/AX除以r/m16,然后将结果存储在AX←商,DX←余数中.

Signed divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder.

要解决此问题,必须签名扩展 AX 中的16位值.这很简单,因为您只需要使用 CWD 指令放置在 AX 中.从指令集参考

To resolve this you have to sign extend the 16-bit value in AX. This is simple as you only need to use the CWD instruction after placing the value in AX. From the instruction set reference

DX:AX←AX的符号扩展.

DX:AX ← sign-extend of AX.

有效地,如果 AX 的最高有效位(MSB)为0,则 DX 将变为0.如果MSB为1,则 DX 变为0ffffh(所有位设置为1).数字的符号位是MSB.

Effectively if the Most Significant Bit (MSB) of AX is 0 DX will become 0. If the MSB is 1 then DX would become 0ffffh (all bits set to one). The sign bit of a number is the MSB.

请牢记所有这些,您的除法代码可以调整为采用16位除数:

With all this in mind your division code could be adjusted to take a 16-bit divisor:

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

这篇关于DOSBox上的8086汇编:idiv指令出错?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆