DIV 指令跳转到随机位置?

DIV instruction jumping to random location?

所以我 this exact problem.

给出的解决方案是将 DX 归零,但在我的情况下它已经是!
我的程序是简单地将一个16位数除以一个8位数。

我的代码是:

data segment
num1 dw 0204h
num2 db 02h
quotient db ?
remainder db ?
data ends
code segment
assume cs:code,ds:data
start: mov ax,data
mov ds,ax
mov ax,num1
div num2
mov quotient,al
mov remainder,ah
mov ah,4ch
int 21h
code ends
end start

有什么解决办法吗?

您迫切需要开始使用空格来分隔您的汇编代码。这段代码做的事情极其简单(将一个数字除以另一个),但极其难以阅读。显然情况并非如此:简单的代码应该易于阅读!为什么读起来难?因为您的所有样板代码都与实际执行除法运算的代码相冲突,所以我的眼睛只是呆滞。我无法从样板文件中挑选出重要的部分。空格是免费的;不要害怕它。你的汇编程序不介意。

这样写:

data segment

num1      dw 0204h
num2      db 02h
quotient  db ?
remainder db ?

data ends


code segment
assume cs:code, ds:data

start:
    ; Initialize Data Segment (DS)
    mov ax, data
    mov ds, ax

    ; Do the division and save the results
    mov ax, num1
    div num2
    mov quotient, al
    mov remainder, ah

    ; Terminate process
    ; (Note that you should also be setting AL to a result code here!)
    mov ah, 4ch
    int 21h
end start

code ends

现在,是不是更清楚什么是什么了?此外,虽然 MASM/TASM 可以让你摆脱草率,但不要养成坏习惯。这是另一种使您的代码不可读并得到错误结果的方法。您可以通过两种不同的方式在代码中使用符号:一种方式是使用该符号的 address/offset,另一种方式方法是使用该符号的 contents/value。在MASM/TASM中,当你想要address/offset时,你需要使用OFFSET关键字。当您使用 contents/value 时,技术上不需要,但您确实 应该 将符号括在括号中以指示它正在被取消引用。换句话说,而不是:

mov ax, num1

写出来:

mov  ax, [num1]

抛开我的怒火,让我们看看您的代码有什么问题。 Michael Petch 已经指出,这是 MASM/TASM 的 "do what I mean, not what I write" 风格对您没有任何好处的另一个例子。它正在进行 8 位除法,因为您在 DIV 指令中使用了 8 位操作数 (num2)。这意味着它实际上在做:

AX / [num2]

商在AL,余数在AH。如果商大于 8 位,AL 装不下,除法会溢出。

解决方法是进行 16 位除法,在这种情况下,商将放在 AX 中,余数将放在 DX.

为了得到它,这样写代码:

mov  ax, [num1]      ; AX = [num1]
xor  dx, dx          ; DX = 0

xor  bx, bx          ; BX = 0
mov  bl, [num2]      ; BL = [num2], BH = 0

div  bx              ; DX:AX / BX

mov  [quotient],  ax
mov  [remainder], dx

(因为这也是破坏 BX,您可能希望通过在顶部执行 push bx 并在末尾执行 pop bx 来保存其原始值。)


documentation for the DIV instruction 包含一个方便的 table 总结了 8 位、16 位和 32 位除法的工作原理:

Operand Size        | Dividend  | Divisor   | Quotient  | Remainder | Maximum Quotient
--------------------------------------------------------------------------------------
Word/byte           | AX        | r/m8      | AL        | AH        | 2^8 - 1
Doubleword/word     | DX:AX     | r/m16     | AX        | DX        | 2^16 - 1
Quadword/doubleword | EDX:EAX   | r/m32     | EAX       | EDX       | 2^32 - 1

"divisor" 是 DIV 指令的唯一操作数。 "dividend" 是隐含的。请注意,"r/m" 表示寄存器或内存操作数。