1. 程式人生 > >組合語言王爽(第二版)課後習題答案

組合語言王爽(第二版)課後習題答案

第一章 基礎知識

檢測點1.1(第8頁)
----------------------
(1) 13
(2) 1024,0,1023
(3) 8192,1024
(4) 2^30,2^20,2^10
(5) 64,1,16,4
(6) 1,1,2,2,4
(7) 512,256
(8) 二進位制 

注意:
1.第4題中的符號'^'指求冪運算(如: 2^30指2的30次方)

第二章 暫存器(CPU工作原理)

檢測點2.1(第18頁)
----------------------
(1)寫出每條彙編指令執行後相關暫存器中的值。
第一空:F4A3H
第二空:31A3H
第三空:3123H
第四空:6246H
第五空:826CH
第六空:6246H
第七空:826CH
第八空:04D8H
第九空:0482H
第十空:6C82H
第十一空:D882H
第十二空:D888H
第十三空:D810H
第十四空:6246H


(2)只能使用目前學過的彙編指令,最多使用4條指令,程式設計計算2的4次方。

解答如下:
mov ax,2
add ax,ax
add ax,ax
add ax,ax

檢測點2.2(第23頁)
----------------------
(1)00010H,1000FH
(2)1001H,2000H

第2題說明:
因為段的起始地址要為16的倍數。所以當段地址小於1001H或大於2000H時CPU都無法尋到。

檢測點2.3(第33頁)
----------------------
答:CPU修改了4次IP的值。
情況如下:
第1次:執行完mov ax,bx後
第2次:執行完sub ax,ax後
第3次:讀入jmp ax後
第4次:執行完jmp ax後
最後IP的值為0

實驗1 檢視CPU和記憶體,用機器指令和彙編指令程式設計(第33頁)
-----------------------------------------------------
1.預備知識:Debug的使用
<此部分略>

2.實驗任務(第43頁)
(1)
<此部分略>

(2)
<此部分略>

(3)
通過DEBUG中的D命令檢視到主機板的生產日期[以月、日、年,分隔符為'/'的格式]儲存在記憶體ffff:0005~ffff:000C(共8個位元組單元中)處。此生產日期不能被改變,因為其具有‘只讀’屬性。

(4)
通過向記憶體中的視訊記憶體寫入資料,使計算機根據寫入的資料進行ASCII轉換,並將轉換後且可列印的字元輸出到螢幕上。<注:關於視訊記憶體的詳細討論不在此題範圍>

第三章 暫存器(記憶體訪問)

檢測點3.1(第52頁)
----------------------
(1)(題目:略)
第一空:2662H
第二空:E626H
第三空:E626H
第四空:2662H
第五空:D6E6H
第六空:FD48H
第七空:2C14H
第八空:0000H
第九空:00E6H
第十空:0000H
第十一空:0026H
第十二空:000CH

提示:此題可在DEBUG中利用E命令在本機上按照題目中所給出的記憶體單元及其資料進行相應地修改,然後再用A命令進行寫入(題目中所給出的)相應的彙編指令,最後再進行T命令進行逐步執行,以檢視相應結果。


(2)
1.指令序列如下:
mov ax,6622h
jmp 0ff0:0100
mov ax,2000h
mov ds,ax
mov ax,[0008]
mov ax,[0002]

2.寫出CPU執行每條指令後,CS、IP和相關暫存器中的數值。

指令序列↓

暫存器→

CS

IP

DS

AX

BX

初始值→

2000H

0000

1000H

0

0

mov ax,6622h

2000H

0003

1000H

6622H

0000

jmp 0ff0:0100

1000H

0000

1000H

6622H

0000

mov ax,2000h

1000H

0003

1000H

2000H

0000

mov ds,ax

1000H

0005

2000H

2000H

0000

mov ax,[0008]

1000H

0008

2000H

C389H

0000

mov ax,[0002]

1000H

000B

2000H

EA66H

0000

  3.再次體會:資料和程式有區別嗎?如何確定記憶體中的資訊哪些是資料,哪些是程式?
答:(略)

檢測點3.2(第66頁)
----------------------
(1)
mov ax,2000H
mov ss,ax
mov sp,10H

(2)
mov ax,1000H
mov ss,ax
mov sp,0H

實驗2 用機器指令和彙編指令程式設計(第70頁)
---------------------------------------
1.預備知識:Debug的使用
<此部分略>


2.實驗任務
(1)使用Debug,將下面的程式段寫入記憶體,逐條執行,根據指令執行後的實際執行情況填空。
從第一空開始依次如下:
ax=5BEA
ax=5CCA
bx=30F0
bx=6029
sp=FE 220FE 5CCA
sp=FC 220FC 6029
sp=FE 6029
sp=100H 5CCA
sp=FE 220FE 30F0
sp=FC 220FC 2E39

說明:此題可能因機子軟、硬體環境不同而導致答案不一致!


(2)仔細觀察圖3.19的實驗過程,然後分析:為什麼2000:0~2000:f中的內容會發生改變?
答:因為用T指令進行除錯時,會產生中斷。而為了保護現場,CPU則先將標誌暫存器進棧、再把當前CS的值進棧,最後將IP的值進棧。<關於中斷的詳細內容的討論不在此題範圍>

第五章 [BX]和loop指令

實驗4 [BX]和loop的使用(第113頁)
------------------------------- 
(1) 程式設計,向記憶體0:200~0:23F依次傳送資料0~63(3FH)。

程式如下:

assume cs:codesg

codesg segment

mov ax,0020h

mov ds,ax

mov bx,0

mov dl,0

mov cx,40h

s: mov [bx],dl

inc dl

inc bx

loop s

mov ax,4c00h

int 21h

codesg ends

end

(2) 程式設計,向記憶體0:200~0:23F依次傳送資料0~63(3FH),程式中只能使用9條指令,9條指令中包括“mov ax,4c00h”和“int 21h”。

程式如下:

assume cs:codesg

codesg segment

mov ax,0020h

mov ds,ax

mov bl,0

mov cx,40h

s:mov [bx],bl

inc bl

loop s

mov ax,4c00h

int 21h

codesg ends

end

(3) 下面的程式的功能是將“mov ax,4c00h”之前的指令複製到記憶體0:200處,補全程式。上機除錯,跟蹤執行結果。

assume cs:code

code segment

mov ax,code  ;code為所填寫的資料

mov ds,ax

mov ax,0020h

mov es,ax

mov bx,0

mov cx,18h   ;18h為所填寫的資料

s:   mov al,[bx]

mov es:[bx],al

inc bx

loop s

mov ax,4c00h

int 21h

code ends

end

提示:
1.因為題目的要求是把程式碼段內的指令當作資料,複製到目的地址。所以,源資料段ds和程式碼段cs相同,通過 mov ax,code/mov ds,ax ('/'符號是指兩條指令的分隔)來設定源資料段。2.可以先假設要複製8位[1h~0ffh]資料(因為我們肉眼就可以看出此程式的長度不可能大於0ffh個位元組)的位元組數(如:10h),把程式補全,以便通過編譯。這時我們以準確的第一空所填內容code與假想的第二空內容10h將程式補充完整並將其編譯、連線、執行,接著進行DEBUG,在DEBUG時我們可用R命令檢視CX的值,這時我們可以看到CX的值為1D,由此我們可以算出該程式的長度[1Dh-5h]=18h,之所以減5是為了滿足題目的要求(因為mov ax,4c00h/int 21h這兩條指令的長度等於5)

第六章 包含多個段的程式

檢測點6.1(第119頁)
-------------------

(1)

assume cs:codesg

codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

start: mov ax,0

mov ds,ax

mov bx,0

mov cx,8

s: mov ax,[bx]

mov cs:[bx],ax    ;此條指令為所填指令

add bx,2

loop s

mov ax,4c00h

int 21h

codesg ends

end start

(2)

assume cs:codesg

codesg segment

dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

dw 0,0,0,0,0

start:

mov ax,cs     ;cs為所填第一空

mov ss,ax

mov sp,1ah    ;此條指令為所填第二空

mov ax,0

mov ds,ax

mov bx,0

mov cx,8

s:

push [bx]

pop cs:[bx]    ;此條指令為所填第三空

add bx,2

loop s

mov ax,4c00h

int 21h

codesg ends

end start

實驗5 編寫、除錯具有多個段的程式(第123頁)

-----------------------------------------

(1)

1.保持不變

2.<考慮不同機子環境不同,答案無法統一>

3.X-2,X-1

(2)

1.保持不變

2.<考慮不同機子環境不同,答案無法統一>

3.X-2,X-1

4.(N/16+1)*16 [說明:N/16只取整數部分]

(3)

1.保持不變

2.<考慮不同機子環境不同,答案無法統一>

3.X+3,X+4

(4)

答:第3個仍然可以正確執行。因為如果把end指令後的標號start去掉後,編譯器便會順序執行程式。換句話說:當未給編譯器預先的通知,要求其從哪開始執行程式時,編譯器就自動以'至上向下'的順序進行編譯執行源程式。

(5)完整程式如下:

assume cs:code

a segment

        db 1,2,3,4,5,6,7,8

a ends

b segment

        db 1,2,3,4,5,6,7,8

b ends

c segment

        db 0,0,0,0,0,0,0,0

c ends

code segment

  start:mov ax,a

        mov es,ax

        mov ax,c

        mov ds,ax

        mov bx,0

        mov cx,8

     s1:mov ax,es:[bx]

        add [bx],ax

        add bx,2

        loop s1

        mov ax,b

        mov es,ax

        mov ds,ax

        mov bx,0

        mov cx,8

     s2:mov ax,es:[bx]

        add [bx],ax

        add bx,2

        loop s2

        mov ax,4c00h

        int 21h

code ends

  end start

(6)完整程式如下:

assume cs:code

a segment

        dw 1,2,3,4,5,6,7,8

a ends

b segment

        dw 0,0,0,0,0,0,0,0

b ends

code segment

start:

        mov ax,b

        mov ss,ax

        mov sp,10h

        mov ax,a

        mov ds,ax

        mov bx,0

        mov cx,8

s:      push [bx]

        add bx,2

        loop s

        mov ax,4c00h

        int 21h

code ends

end start

第七章 更靈活的定位記憶體地址的方法

實驗6 實踐課程中的程式(第147頁)
-------------------------------

(2)程式設計:完成問題中的程式。

問題7.9完整程式如下:

assume cs:codesg,ss:stacksg,ds:datasg

stacksg segment

        dw 0,0,0,0,0,0,0,0

stacksg ends

datasg segment

        db '1. display      '

        db '2. brows        '

        db '3. replace      '

        db '4. modify       '

datasg ends

codesg segment

start:

        mov ax,stacksg

        mov ss,ax

        mov sp,16

        mov ax,datasg

        mov ds,ax

        mov bx,0

        mov cx,4

s: ;外迴圈

        push cx

        mov si,3

        mov cx,4

        s0: ;內迴圈

                mov al,[bx+si]

                and al,11011111b

                mov [bx+si],al

                inc si

        loop s0

        add bx,16

        pop cx

loop s

mov ax,4c00h

int 21h

codesg ends

end start

第八章 資料處理的兩個基本問題

實驗7 定址方式在結構化資料訪問中的應用(第160頁)
----------------------------------------------

完整程式如下:

assume cs:codesg,ds:data,es:table

data segment

        db '1975','1976','1977','1978','1979','1980','1981','1982','1983'

        db '1984','1985','1986','1987','1988','1989','1990','1991','1992'

        db '1993','1994','1995'

        ;以上是表示21年的21個字串

        dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

        dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

        ;以上是表示21年公司總收的21個dword型資料

        dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226

        dw 11542,14430,45257,17800

        ;以上是表示21年公司僱員人數的21個word型資料

data ends

table segment

        db 21 dup('year summ ne ?? ')

table ends

codesg segment

start:

        mov ax,data

        mov ds,ax

        mov ax,table

        mov es,ax

        mov bx,0

        mov si,0

        mov di,0

        mov cx,21

        s:   ;進入迴圈

                mov al,[bx]

                mov es:[di],al

                mov al,[bx+1]

                mov es:[di+1],al

                mov al,[bx+2]

                mov es:[di+2],al

                mov al,[bx+3]

                mov es:[di+3],al

                ;以上8句的作用是存放年份

                mov ax,54h[bx]     ;第一個'年收入'的段基址為54H

                mov dx,56h[bx]

                mov es:5h[di],ax

                mov es:7h[di],dx

                ;以上4句的作用是存放公司總收入

                mov ax,0A8h[si]    ;第一個'人數'的段基址為0A8H

                mov es:0Ah[di],ax

                ;以上2句是存放公司的人數

                mov ax,54h[bx]

                div word ptr ds:0A8h[si]

                mov es:0dh[di],ax

                ;以上3句是存放人均收入

                add bx,4

                add si,2

                add di,16

                ;以上3句是為下一次迴圈時存放資料做準備

                ;3個暫存器遞增的速度決定了所要存取的資料的位置的偏移地址

        loop s  ;跳到標號s處

mov ax,4c00h

int 21h

codesg ends

end start

程式說明:此程式雖然可以達到預期效果(讀者可以自行除錯驗證),但實現方法比較簡單,讀者有興趣的話可以尋找一種更具結構化的設計方法來完成。

第九章 轉移指令的原理

檢測點9.1(第170頁)

----------------------

(1)若要使jmp指令執行後,CS:IP指向程式的第一條指令,在data段中應該定義哪些資料?

完整程式如下:

assume cs:code,ds:data

data segment

db 0,0,0

data ends

code segment

start: mov ax,data

mov ds,ax

mov bx,0

jmp word ptr [bx+1]   ;段內間接轉移

code ends

end start

;解題理由:為了使IP的值經跳轉後變為0,則需保證ds:[bx+1]處的字型單元資料為0000H,

;所以定義3個位元組型資料0就符合“應該”的要求

(2)補全程式,使jmp指令執行後,CS:IP指向程式的第一條指令。

完整程式如下:

assume cs:code,ds:data

data segment

dd 12345678h

data ends

code segment

start: mov ax,data

mov ds,ax

mov bx,0

mov [bx],bx      ;源運算元bx為所填內容

mov [bx+2],cs    ;源運算元cs為所填內容

jmp dword ptr ds:[0]

code ends

end start

(3)用Debug檢視記憶體,結果如下:

2000:1000 BE 00 06 00 00 00 ......

則此時,CPU執行指令:

mov ax,2000H

mov es,ax

jmp dword ptr es:[1000H]

後,(CS)=? , (IP)=?

提示:為了使本機環境[2000:1000至2000:1005]中的資料與題目中所給出的資料一致,可以通過編寫程式來完成,完整程式如下:

assume cs:code

code segment

start:

mov ax,2000h

mov ds,ax

mov bx,1000h

mov word ptr [bx].0,0BEH

mov word ptr [bx].2,6h

mov word ptr [bx].4,0

;執行完上6句則使2000:1000--2000:1005中的資料依次為:BE,00,06,00,00,00

;以上6句則按題目中的資料進行初始化,以便使執行環境符合題目要求

;mov ax,2000h

mov es,ax

jmp dword ptr es:[1000h]

code ends

end start

經上機除錯得出:CS=0006H,IP=00BEH

檢測點9.2(第172頁)

----------------------

從標號s處開始所要填寫的四條指令依次如下:

第一條指令:mov cl,[bx]

第二條指令:mov ch,0

第三條指令:jcxz ok

第四條指令:inc bx

檢測點9.3(第173頁)
----------------------

補全程式,利用loop指令,實現在記憶體2000H段中查詢第一個值為0的byte,找到後,將它的偏移地址儲存在dx中。

assume cs:code

code segment

start:

        mov ax,2000h

        mov ds,ax

        mov bx,0

        s:

                mov cl,[bx]

                mov ch,0

                inc cx    ;此條指令為題目要求補全的指令

                inc bx

        loop 

        ok:

                dec bx

                mov dx,bx

                mov ax,4c00h

                int 21h

code ends

end start

解答提醒:此題可用假設法來完成(比如2000:0000至2000:0003的內容依次為:1E 06 00 0A)。此題要注意loop指令的使用規則,同時要注意區別[記憶體單元]與[記憶體單元中的資料(或內容)]的不同。

實驗8 分析一個奇怪的程式(第174頁)
---------------------------------

分析下面的程式,在執行前思考:這個程式可以正確返回嗎?

執行後再思考:為什麼是這種結果?

通過這個程式加深對相關內容的理解。

assume cs:codesg

codesg segment

        mov ax,4c00h

        int 21h

start:

        mov ax,0

s:

        nop

        nop 

        mov di,offset s

        mov si,offset s2

        mov ax,cs:[si]

        mov cs:[di],ax

s0:

        jmp short s

s1:

        mov ax,0

        int 21h

        mov ax,0

s2:

        jmp short s1

        nop

codesg ends

end start

程式可以正常返回。

詳細分析:

在此題中較為深入地考察了‘段內直接短轉移’[形如:jmp short 標號]的概念。

我們知道程式中:

mov di,offset s

mov si,offset s2

mov ax,cs:[si]

mov cs:[di],ax

四條指令的作用是將標號s2處的一條指令複製到標號s處。這時我們應該關心所複製的語句"jmp short s1"對程式的影響:我們知道在段內直接短轉移指令所對應的機器碼中,並不包含轉移的目的地址,而包含的是轉移的位移量(如對此概念還不太熟悉,請檢視書中第167頁的內容)。也就是說,在源程式的編譯過程中,編譯器遇到‘段內直接短轉移’[形如:jmp short 標號]時就會自動算出其要跳轉的位移量,以便程式在執行‘段內直接短轉移’的指令時就根據位移量進行(向前或向後)跳轉。通過除錯中的U命令我們可以看到指令's2:jmp short s1'所對應的機器碼是EBF6,F6h(-10d的補碼)就是跳轉的位移量[此位移量也可由指令's2:jmp short s1'處的偏移地址18h減去指令's2:jmp short s1'後一個位元組的偏移地址22h得出]。這時我們就知道了其實複製到標號s處的指令所對應的機器碼就是EBF6(剛好取代兩個nop所對應的機器碼),它的作用就是將當前IP向前移動10個位元組。當程式執行標號s0處的指令後,程式便跳到標號s處接著執行標號s處的指令。s處的指令的作用是向前跳10位元組,於是便跳到了程式碼中的第一條指令,繼續執行後便實現了程式的正常返回

[注意:此程式不會也不可能執行標號s1處後的指令。]

實驗9 根據材料程式設計(第175頁)
-------------------------------

assume cs:code,ds:data,ss:stack

data segment

        db 'welcome to masm!'  ;定義要顯示的字串(共16位元組)

        db 02h,24h,71h    ;定義三種顏色屬性

data ends

stack segment

        dw 8 dup(0)

stack ends

code segment

start:

        mov ax,data

        mov ds,ax

        mov ax,stack

        mov ss,ax

        mov sp,10h

        mov bx,0

        mov di,0

        mov ax,0b872h    ;算出螢幕第12行中間的視訊記憶體的段起始位置放入ax中

        mov cx,3     ;外迴圈為3次,因為要顯示三個字串

s3:     push cx        ;三個進棧操作為外迴圈s3儲存相關暫存器的值

        push ax        ;以防止它們的值在內迴圈中被破壞

        push di

        mov es,ax      ;此時es為螢幕第12行中間的視訊記憶體的段起始位置

        mov si,0

        mov di,0

        mov cx,10h     ;內迴圈為10h次,因為一個字串中含10h個位元組

s1:     mov al,ds:[bx+si]

        mov es:[bx+di],al

        inc si

        add di,2

        loop s1      ;此迴圈實現偶地址中存放字元

        mov si,1   ;si的值設為1,從而為在視訊記憶體奇地址中存放字元的顏色屬性做準備

        pop di        ;將di的值恢復成進入內迴圈之前的時候的值

        mov al,ds:10h[bx+di]    ;取顏色屬性[源OP定址方式:相對基址變址]

        mov cx,10h     ;第二個內迴圈也為10h次

s2:     mov es:[bx+si],al

        add si,2

        loop s2       ;此迴圈實現奇地址中存放字元的顏色屬性 

        ;以下4句為下一趟外迴圈做準備

        inc di

        pop ax

        add ax,0ah   ;將視訊記憶體的段起始地址設為當前行的下一行

                  ;[在段地址中加0ah,相當於在偏移地址中加了0a0h(=160d)]

        pop cx

        loop s3       

        mov ax,4c00h

        int 21h

code ends

end start

第十章 call和ret指令

檢測點10.1(第179頁)
----------------------

第一空:1000h

第二空:0

提示:此題等效於把CS的值改為1000H,把IP的值改為0。因為retf指令進行的操作是先將IP出棧,再將CS出棧,所以在進棧時應當進行相反的操作。

檢測點10.2(第181頁)
----------------------

ax=6

提示:在執行指令"call s"時,IP的值變為6,接著進棧。此時程式直接執行指令"s:pop ax",這就等於把棧中IP的值放入ax中。所以答案為6。關於更多的call指令的問題請看附註中的“錯誤指出”中的第6條。

檢測點10.3(第181頁)
----------------------

ax=1010

提示:

1.暫存器中存放的值為16進位制數

2.關於更多的call指令的問題請看附註中的“錯誤指出”中的第6條。

檢測點10.4(第182頁)

----------------------

ax=000B

提示:關於更多的call指令的問題請看附註中的“錯誤指出”中的第6條。

檢測點10.5(第183頁)

----------------------

(1)答:ax中的數值為3

提示:不能利用T命令進行除錯,則改用UG命令來除錯。可用U命令先檢視指令"mov ax,4c00h"處的偏移地址,然後用G命令直接執行到指令"mov ax,4c00h"的偏移地址處。

(2)

ax=1

bx=0

提示:關於更多的call指令的問題請看附註中的“錯誤指出”中的第6條。

實驗10 編寫子程式(第194頁)
--------------------------

1.顯示子程式

完整程式如下:

data segment

        db 'Welcome to masm!',0

data ends

code segment

        assume cs:code,ds:data

start:

        mov dh,1              ;dh裝行號(範圍:1--25)

        mov dl,1              ;dl裝列號(範圍:1--80)[注:每超過80等於行號自動加1]

        mov cl,0cah           ;cl中存放顏色屬性(0cah為紅底高亮閃爍綠色屬性)

        mov ax,data

        mov ds,ax

        mov si,0

        call show_str

        mov ax,4c00h

        int 21h

show_str:   ;顯示字串的子程式[定義開始]

        push cx

        push si

        mov al,0A0h

        dec dh          ;行號在視訊記憶體中下標從0開始,所以減1

        mul dh

        mov bx,ax

        mov al,2

        mul dl

        sub ax,2       ;列號在視訊記憶體中下標從0開始,又因為偶位元組存放字元,所以減2

        add bx,ax      ;此時bx中存放的是行與列號的偏移地址

        mov ax,0B800h

        mov es,ax      ;es中存放的是視訊記憶體的第0頁(共0--7頁)的起始的段地址

        mov di,0

        mov al,cl

        mov ch,0

s:      mov cl,ds:[si]

        jcxz ok

        mov es:[bx+di],cl       ;偶地址存放字元

        mov es:[bx+di+1],al     ;奇地址存放字元的顏色屬性

        inc si

        add di,2

        jmp short s

ok:     pop si

        pop cx

        ret    ;顯示字串的子程式[定義結束]

code ends

end start

2.解決除法溢位的問題(第197頁)

完整程式如下:

assume cs:code,ss:stack

stack segment

        dw 8 dup(0)

stack ends

code segment

start:

        mov ax,stack

        mov ss,ax

        mov sp,10h

        mov ax,4240h

        mov dx,0fh

        mov cx,0ah

        call divdw        

        mov ax,4c00h

        int 21h

divdw:  ;子程式定義開始

        push ax

        mov ax,dx

        mov dx,0

        div cx

        mov bx,ax

        pop ax

        div cx

        mov cx,dx

        mov dx,bx

        ret   ;子程式定義結束        

code ends

end start

3.數值顯示(第198頁)

完整程式如下:

assume cs:code,ds:data

data segment

        db 10 dup (0)

data ends

code segment

start:

        mov ax,12666

        mov bx,data

        mov ds,bx

        mov si,0

        call dtoc

        mov dh,8

        mov dl,3

        mov cl,0cah

        call show_str

        mov ax,4c00h

        int 21h

dtoc:  ;數值顯示的子程式定義

        push dx

        push cx

        push ax

        push si

        push bx

        mov bx,0

s1:     mov cx,10d

        mov dx,0

        div cx        

        mov cx,ax

        jcxz s2

        add dx,30h

        push dx

        inc bx

        jmp short s1

s2:     add dx,30h

        push dx

        inc bx     ;再進行一次棧操作(補充當"商為零而餘數不為零"時的情況)

        mov cx,bx

        mov si,0

s3:     pop ax

        mov [si],al

        inc si

        loop s3

okay:   pop bx

        pop si

        pop ax

        pop cx

        pop dx

        ret   ;數值顯示的子程式定義結束

show_str:  ;顯示字串的子程式已經在第一題中說明,在此不再贅述。

        push bx push cx

        push si

        mov al,0A0h

        dec dh

        mul dh

        mov bx,ax

        mov al,2

        mul dl

        sub ax,2

        add bx,ax

        mov ax,0B800h

        mov es,ax

        mov di,0

        mov al,cl

        mov ch,0

s:      mov cl,ds:[si]

        jcxz ok

        mov es:[bx+di],cl

        mov es:[bx+di+1],al

        inc si

        add di,2

        jmp short s

ok:     pop si

        pop cx

        pop bx

        ret

code ends

end start