问题
So I am having this exact problem.
The solution given is to zero out DX
, but in my case it already is!
My program is to simply divide a 16 bit number by an 8 bit number.
My code is:
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
Any solution?
回答1:
You badly need to start using whitespace to separate your assembly code. This code is doing something extremely simple (dividing one number by another), yet it is extremely difficult to read. That should obviously not be the case: simple code should be simple to read! Why is it hard to read? Because you've got all of your boilerplate code jammed up against the code that's actually doing the division operation, and my eyes just glaze over. I'm not able to pick out the important bits from the boilerplate. Whitespace is free; don't be afraid of it. Your assembler doesn't mind.
Write it like this:
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
Now, isn't it substantially more clear what's what? Also, while MASM/TASM will let you get away with being sloppy, don't get into bad habits. That's another way to make your code unreadable and get the wrong results. There are two different ways that you can use symbols in your code: one way is to use the address/offset of that symbol, and the other way is to use the contents/value of that symbol. In MASM/TASM, when you want the address/offset, you need to use the OFFSET
keyword. When you use the contents/value, you don't technically need to, but you really should wrap the symbol in brackets to indicate that it is being dereferenced. In other words, instead of:
mov ax, num1
write it:
mov ax, [num1]
With that rant off my chest, let's look at what's wrong with your code. Michael Petch has already pointed out that this is another case where MASM/TASM's "do what I mean, not what I write" style is not doing you any favors. It is doing an 8-bit division because you've used an 8-bit operand (num2
) with the DIV
instruction. That means it's actually doing:
AX / [num2]
with the quotient in AL
and the remainder in AH
. If the quotient is larger than 8 bits, it won't fit in AL
and the division will overflow.
The workaround is to do a 16-bit division, in which case the quotient will be placed in AX
and the remainder will be placed in DX
.
To get that, write the code thusly:
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
(Since this is also clobbering BX
, you may want to save its original value by doing a push bx
at the top and a pop bx
at the end.)
The documentation for the DIV instruction contains a handy table summarizing how 8-bit, 16-bit, and 32-bit divisions work:
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
The "divisor" is the sole operand for the DIV
instruction. The "dividend" is implicit. Note that "r/m" means either a register or memory operand.
来源:https://stackoverflow.com/questions/43522230/div-instruction-jumping-to-random-location