DOSBox 上的 8086 程序集:带有 idiv 指令的错误? [英] 8086 assembly on DOSBox: Bug with idiv instruction?

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

问题描述

我正在帮助我的一个朋友调试他的程序,我们将其缩小到一个甚至在这里也发生的问题:

.MODEL 小.堆栈 16.代码开始:mov ax, 044c0hmov bl, 85伊迪文 bl出口:mov ax, 4c00h21 小时结束开始

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

有没有人对此有任何解释?

解决方案

这个问题是其他部门相关失败的变体.

您会注意到,对于使用 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 位值进行符号扩展.这很简单,因为您只需要使用 CWD 将值放入 AX 后的指令.来自指令集参考

<块引用>

DX:AX ← AX 的符号扩展.

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

考虑到所有这些,您的除法代码可以调整为采用 16 位除数:

mov ax, 044c0hcwd ;将 AX 符号扩展为 DX(DX:AX = 32 位被除数)移动 bx, 85 ;除数是 85idiv bx ;DX:AX 与 BX 的有符号除法

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

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?

解决方案

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


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:

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

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.

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.

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

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 ← sign-extend of AX.

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.

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天全站免登陆