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" 表示寄存器或内存操作数。
所以我 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" 表示寄存器或内存操作数。