2017-04-20 61 views
2

所以我有this exact problem跳轉到隨機位置的DIV指令?

給出的解決方案是將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 

任何解決方案?

+4

您使用[DIV](http://www.felixcloutier.com/x86/DIV.html)指令的形式是'由R/M8無符號除法,AX,與存儲在AL←商數,AH結果←剩下的。這是因爲MASM/TASM默認'num1'是一個8位內存操作數,因爲定義爲'num2 db 02h'。在這種情況下,不使用_DX_(因此它的值無關緊要)。什麼是錯誤的是0x204除以2是0x102。 0x102不能放在一個字節中(字節爲0x00到0xff),因爲商不能放入8個字節的寄存器(_AL_),所以會導致除法異常(溢出)。 –

+1

爲了得到這個工作,你就必須比0淘汰16位寄存器,MOV'num2'到該寄存器的低8位,設置_DX_爲零,並做了16位除法運算(而不是8)。從我的第一條評論的鏈接中,指令的形式是'無符號除法DX:AX by r/m16,結果存儲在AX←商數,DX←餘數。當師完成0x102應該在_AX_ –

回答

3

您非常需要開始使用空格來分隔您的彙編代碼。這段代碼正在做點什麼極其簡單(將一個數字除以另一個數字),但它是極端難以閱讀。這顯然不應該是這樣的:簡單的代碼應該很容易閱讀!爲什麼很難閱讀?因爲你已經將所有的樣板代碼擠在了實際上正在進行分區操作的代碼上,而且我的眼睛只是咕gla着。我無法從樣板中挑出重要的部分。空白是免費的;不要害怕它。你的彙編器不介意。

寫這樣的:

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會讓你擺脫sl,,但不要陷入不良習慣。這是讓您的代碼無法閱讀並獲得錯誤結果的另一種方法。有跡象表明,你可以在你的代碼中使用符號兩種不同的方式:一種方式是使用地址/偏移符號的,而另一種方法是使用內容/該符號的價值。在MASM/TASM中,當您想要地址/偏移量時,您需要使用OFFSET關鍵字。當你使用內容/值時,你在技術上並不需要,但是如果應該將括號中的符號包裝起來以表示它被解除引用。換句話說,而不是,:

mov ax, num1 

寫它:

mov ax, [num1] 

隨着那誇誇其談了我的胸口,讓我們來看看什麼是你的代碼錯誤。邁克爾佩奇已經指出,這是MASM/TASM的「做我的意思,而不是我寫的」風格的另一種情況是沒有任何好處。它正在做一個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包含一個方便的表格,概括的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 

「除數」是爲DIV指令的唯一操作數。 「分紅」是隱含的。請注意,「r/m」表示寄存器或內存操作數。

+0

也許一個好主意,也表明了*商*和* *餘下的定義需要從'分貝改變?''到DW?'提出的解決方案不寫的話! –