unsigned/signed 分部的汇编程序

Assembly program with unsigned/signed division

我正在尝试编写一个将 1000 除以 5 的简单汇编程序,但我的程序冻结了系统。

程序如下,

include pcmac.inc   
.model Small
.586

.stack 100h

.data
const db 5

Main PROC
    _Begin  

    mov AX, 1000  
    idiv const  // Problem line

    _Exit 0 
Main ENDP
    End Main

如果我使用无符号除法 div 而不是有符号除法 idiv,问题就会消失。

谁能解释为什么?

我知道除法的唯一条件是被除数必须是除数的两倍。还有什么我想念的吗?

const是一个字节。当您执行 IDIV byte_divisor 时,商将放在 AL 中,范围为 -128 到 127。1000 / 5 为 200,这不在允许范围内。如果您使用 DIV,商的范围是 0 到 255,这就是您的示例在这种情况下有效的原因。

如果您想 IDIV 1000 乘以 5,您应该改用 16 位除数。但是您需要记住,在使用 IDIV r/m16 时,您实际上是在划分由 DXAX 组成的 32 位双字(DX 持有最高有效位,AX 最低有效位)。

来自英特尔的手册:

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

IF OperandSize = 16 (* Doubleword/word operation *)
THEN
    temp ← DX:AX / SRC; (* Signed division *)
    IF (temp > 7FFFH) or (temp < 8000H)
    (* If a positive result is greater than 7FFFH
    or a negative result is less than 8000H *)
    THEN
        #DE; (* Divide error *) 
    ELSE
        AX ← temp;
        DX ← DX:AX SignedModulus SRC;

因此,在 IDIV 之前,您应该根据 AX 中的值在 DX:AX 中创建一个带符号的双字。有一条名为 CWD 的指令正是这样做的:

The CWD instruction copies the sign (bit 15) of the value in the AX register into every bit position in the DX register.

即:

.data
const dw 5   ; now a word

.code
mov ax,1000
cwd          ; sign-extend ax into dx
idiv const
; quotient is in ax, remainder in dx