2017-07-22 62 views
1

我的任務是設計一個dword分區子程序(divdw),它不會在8086程序集中溢出(我在MS-DOS中使用masm5.0/masm.exe和masm5.0/link.exe和debug.exe )。 AXCXDX用於保存divdw的結果。以下代碼無法運行。在8086程序集中,如何在子程序中使用堆棧?

這裏是任務:

輸入:

(AX)=低16位的雙字被除數
(DX)=雙字被除數的高16位的
(CX) = 16位除數

輸出:

(AX)=結果的低16位
(DX)=高16位的結果的
(CX)=剩餘

我以前calc下divdw式中:

被除數/除數= QUOT(被除數/除數的高16位)+
(REM(被除數/除數的高16位)* 2^16 + 16低位被除數的)/除數

這裏是我的代碼:

assume cs:code 

     code segment 
start: mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bx 
     push dx     ;ss:[0ch] 

     mov ax,dx 
     mov dx,0 
     div cx 
     mov ax,0    ;rem, only need dx 
     mov bx,ss:[0ch] 
     div bx 

     ;; finish 1 
     push dx 
     push ax 

     ;; get dx, into ax 
     mov ax,ss:[0ch] 
     div cx 
     ;; finish 2 
     push ax 

     pop dx     ;ax after 2 
     pop ax     ;ax after 1 
     pop cx     ;dx after 1 

     ;; recover bx 
     pop bx 
     pop bx 
     ret 


     code ends 
     end start 

在這段代碼中,我試圖用poppush,但沒有定義堆棧段。這是否允許? (在調試器中,我發現給出了SS:SP,但push無法正常工作。)
如果沒有,我應該在哪裏定義堆棧以及如何使用它?

如果我在主程序中定義一個堆棧段,似乎我需要在過程的開始時保存SSSP值,但我應該在哪裏保存它們?我可以將它們保存在堆棧中,還是必須將它們保存在內存中的某個位置?

開始主要程序是爲了測試而給出的。

謝謝!


編輯

謝謝兩位!在你的幫助下,我完成了這項任務。現在的代碼如下:

assume cs:code,ss:stack 

     stack segment 
     dw 8 dup (0) 
     stack ends 

     code segment 
start: 
     mov ax,stack 
     mov ss,ax 
     mov sp,16 

     mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bx 
     push dx     ;ss:[0ah] 
     push ax     ;ss:[08h] 

     mov ax,dx    ;ax=0fh 
     mov dx,0    ;dx=0 
     div cx     ;ax=1,dx=5 
     push ax     ;1, quot, should be dx when ret, as the high 16 bit of result 
     ;; use dx=5 and 4240h to do div 
     mov ax,ss:[08h]   ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax 
     div cx     ;ax=86a0h,dx=0h 

     ;ax already is low 16bits of quot 
     mov cx,dx    ;rem, store in cx 
     pop dx     ;1, high 16 bits of quot 

     pop bx     ;discard original ax 
     pop bx     ;discard original dx 
     pop bx     ;recover original bx 
     ret 


     code ends 
     end start 

編輯在20170724

另一個版本中擺脫的SS:[08H],以及使用其他3個寄存器來存儲。我不確定這是否更好,但它有效。

assume cs:code,ss:stack 

     stack segment 
     db 16 dup (0) 
     stack ends 

     code segment 
start: 
     mov ax,stack 
     mov ss,ax 
     mov sp,16 

     mov ax,4240h 
     mov dx,000fh 
     mov cx,0ah 
     call divdw 
     mov ax,4c00h 
     int 21h 

divdw: push bp 
     mov bp,sp 
     push si 
     push bx 
     push dx 
     push ax 
     mov si,sp 

     mov ax,dx    ;ax=0fh 
     mov dx,0    ;dx=0 
     div cx     ;ax=1,dx=5 
     push ax     ;1, quot, should be dx when ret, as the high 16 bit of result 
     ;; use dx=5 and 4240h to do div 
     mov ax,ss:[si]   ;ax=4240h. rem, only need dx of last result, use low 16bit of dividend, ie. ax, as ax 
     div cx     ;ax=86a0h,dx=0h 

     ;ax already is low 16bits of quot 
     mov cx,dx    ;rem, store in cx 
     pop dx     ;1, high 16 bits of quot 

     pop bx     ;discard original ax 
     pop bx     ;discard original dx 
     pop bx     ;recover original bx 
     pop si 
     mov sp,bp 
     pop bp 
     ret 


     code ends 
     end start 
+0

這是如何加載/鏈接?該堆棧應該由加載程序準備 –

+0

我在MS-DOS中使用masm5.0/masm.exe和masm5.0/link.exe和debug.exe。 – cmal

+1

只有16個字節的堆棧?你一定是在開玩笑! – Fifoernik

回答

3

您不必只要PUSH數量等於POP數量來拯救他們。

這並不總是方便,但它是你的情況,它應該沒問題。

除了在最後彈出保存的DX值到BX,這可能是一個問題。

編輯:

我不明白,你需要在這種情況下,但一般可以做到這一點,以恢復BPSP

push bp ; first statement of subroutine 
mov bp, sp 

... 

mov sp, bp 
pop bp 
ret 

在你的子程序,你就必須BP用作調用前壓入堆棧的任何參數的基地址。同樣,你的例子並不表明,但也似乎並沒有使用你把AX寄存器中的值和聲明

mov bx, ss:[0ch] 

是有點混亂。你怎麼知道那個地址是什麼?

+0

FYI BP是備份堆棧寄存器。 mov bp,sp –

+0

是的,我只需要保存bx; ax,cx,dx用於保存divdw的結果。 – cmal

+0

啊,謝謝你。我應該使用mov bp,sp在兒童還是主要程序中?如果在子程序中,我應該先備份bp嗎?我的任務是設計一個divdw子程序。 – cmal

3

如果不是,我應該在哪裏定義棧以及如何使用它?

您如何定義堆棧段取決於彙編程序。 排序的segment stack和/或assume ss:stack。除了.com/model tiny程序之外,無需在啓動時直接修改SS:SP

看來我需要在過程開始時保存ss和sp值,但我應該在哪裏保存它們?

典型的程序只使用單個堆棧段,所以不需要保存/修改SS寄存器。關於SP,不,你顯然不能(不應該)將它保存到堆棧中。通常的技巧是:

push bp 
mov bp, sp 
... ; use [bp+4] to address the first argument on the stack 
.... ; ss segment is assumed by default when [bp] used 
mov sp, bp ; if sp was modified by some push/sub instructions 
pop bp 
ret 

然而,它只是有用的,如果你真的需要處理過程中的基於堆棧的參數。否則,根據需要只使用push/pop

+0

謝謝@Matt。 「假設ss:堆棧」確實有幫助。我會繼續我的學習,看看'.com/model tiny'的意思。 – cmal

+0

對不起,我的錯誤!我不敢相信我寫了那個愚蠢的替代'SS:IP'。道歉。 – Fifoernik

相關問題