2017-04-23 139 views
5

我在幫我的一個朋友調試他的程序,我們把範圍縮小到這裏竟然出現了問題:DOSBox上的8086程序集:idiv指令的錯誤?

.MODEL small 
.STACK 16 
.CODE 
start: 
    mov ax, 044c0h 
    mov bl, 85 
    idiv bl 
exit: 
    mov ax, 4c00h 
    int 21h 

end start 

與TASM 4.1組裝完畢,並在DOSBox中0.74運行它,它進入一個無限循環。當用turbo調試器檢查時,可以看到它發生在idiv指令之後,該指令出於某種原因修改了csip寄存器,並且在兩條看似隨機的指令將它們恢復爲指向idiv行之後,再次無限次地執行它。

有沒有人有任何解釋?

+3

因爲你的部門的簽字商不能在8位寄存器(_AL_)嚴絲合縫你會得到算術溢出。 r16/r8 [IDIV](http://www.felixcloutier.com/x86/IDIV.html)上商的範圍是-128到+127。你的部門產量爲207. –

+1

@MichaelPetch:是的。我正要提交這個答案,但你打敗了我! – wallyk

+1

這將是INT 00h中斷處理程序。有點令我驚訝的是,它只是跳回到破損的代碼,導致無限循環。我本來會期望它終止應用程序,打印一條錯誤消息,或者更明顯一些。你是多少天裏第二個被這個困惑的人。 –

回答

7

這個問題是其他分裂相關失敗的變體。該x86 tag wiki有一些額外的鏈接:


明顯隨機代碼的調試器似乎跳到是算術異常處理程序(也同實施除以零)。發生什麼事是您的代碼正在經歷Division Overflow。你正在做一個16位/ 8位IDIV。從文檔:

簽署的鴻溝AX由r/m8,結果存儲在:AL←商,AH←餘數。

enter image description here

你會發現,爲師帶一個8位的除數(在你的情況BL)爲商範圍爲-128至+127。 044c0h IDIV 85是207(十進制)。 207不適合簽名的8位寄存器,因此會導致分區溢出並導致意外問題。

要解決這個問題,您可以移動一個16位的除數。因此,您可以將您的除數放入BX(16位寄存器)。那將是mov bx, 85。不幸的是,它並不那麼簡單。當使用16位分頻因子時,處理器假定分辨率爲32位,高位16位,DX,低位16位,AX

簽名除法DX:AX by r/m16,結果存儲在AX←商,DX←餘數中。

要解決此問題,您必須在AX上簽名擴展16位值。這很簡單,因爲在將值放入AX之後,您只需要使用指令。從指令設定的基準

DX:AX←AX的符號擴展。

有效如果AX的最高有效位(MSB)爲0 DX將成爲0。如果MSB爲1則DX將成爲0FFFFH(設置爲一個所有位)。數字的符號位是MSB。

有了這一切記住你的區劃代碼可以被調整,以一個16位除數:

mov ax, 044c0h 
cwd    ; Sign extend AX into DX (DX:AX = 32-bit dividend) 
mov bx, 85   ; Divisor is 85 
idiv bx   ; Signed divide of DX:AX by BX