匯編語言(王爽第三版)實驗6 實踐課程中的程序


實驗6 實踐課程中的程序

(1)將課程中所有講解過的程序上機測試,用debug跟蹤其執行過程,並在過程中理解所講內容。

       問題7.6 將data段中每個單詞的頭一個字母改為大寫字母。

assume cs:code

data segment

    db '1. file         '

    db '2. edit         '

    db '3. search       '

    db '4. view         '

    db '5. options      '

    db '6. help         '

data ends

code segment

程序分析:

       1)數據段定義了6個字符串結構,長度一致都是16字節,並且字符都是連續的,並且頭一個字母在字符串中的位置都是第4個字符,在上面的尋址方式中,我們發現[bx+idata]方式比較適合這種情況,idata代表每個字符串起始地址,bx代表基本偏移地址,bx的偏移量也是有規律的16。

       2)在debug中,這6個字符串顯示的正好是6行16列的字符,是一個我們在C語言中講到的二維數組[6][16],其實它在內存中是線性單列排列的。

       3)遇到此種情況我們使用[bx+idata]的方式進行內存的尋址比較科學。

       完整的代碼如下:

assume cs:code

data segment

    db '1. file         '

    db '2. edit         '

    db '3. search       '

    db '4. view         '

    db '5. options      '

    db '6. help         '

data ends

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;將ds:bx指向data第一個單元

        mov cx, 6           ;需要修改6次

       

    s:  mov al, [bx+3]      ;使用[bx+idata]尋址方式,並送入al(單字節)

        and al, 11011111b   ;轉換為大寫字母

        mov [bx+3], al      ;回寫內存

        add bx, 16          ;6個字符串長度一致,都是16字節,增量為16

        loop s

       

        mov ax, 4c00H

        int 21H

code ends

end start

       結果分析:

       (1)在循環中,如遇到loop指令,首先我們要認識到,(cx)=(cx)-1;直到cx=0退出循環。

       問題7.7將data段中每個單詞的字母改為大寫字母。

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

       程序分析:

       (1)數據段定義了4個字符串,長度依然是16字節,並且是連續存儲的,這次是要求將每個字符串的小寫字母都給修改了,這樣[bx+idata]就不合適了,我們采用[bx+si]方式尋址。bx依然代表基本偏移地址,si代表了每個字符串每個字母的偏移地址。

       (2)一個循環肯定滿足不了要求了,這里需要二重循環,外層循環遞增bx的值;內存循環對每個字符串的字符進行變換操作。

       (3)對於loop循環來說,它判斷的是cx計數器,對於二重循環,一個cx值顯然滿足不了要求。書中代碼中的cx設置就有問題了。

       問題7.8 解決cx計數器重復設置的問題:

       程序分析:我們可以想法將外層循環計數器保存起來,待某一個內層循環執行完畢后,在恢復。這樣可以解決了cx計數器沖突的問題。

       改進的代碼:

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作為基本偏址變量

        mov cx, 4           ;需要外循環4次,修改4個字符串

   

    s0: mov dx, cx          ;將外層循環計數器cx保存到dx中

        mov si, 0           ;si作為每個字符串的偏址

       

        mov cx, 3           ;內存循環s1,需要循環3次

    s1: mov al, [bx+si]     ;使用[bx+si]尋址方式,並送入al(單字節)

        and al, 11011111b   ;轉換為大寫字母

        mov [bx+si], al     ;回寫內存

        inc si                 

        loop s1

       

        add bx, 16          ;6個字符串長度一致,都是16字節,增量為16

        mov cx, dx          ;將外層循環計數器cx從dx中恢復

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       結果分析:

       (1)我們通過將cx寄存器變量保存的方式,來解決多重循環cx變量沖突的問題。

       (2)此例中我們解決方式是將cx保存到dx中,在8086CPU中,寄存器本來就比較緊張,段寄存器肯定不能用,ip是程序的指針、dx一般用於結果的輸出,占用后又出現新的問題,sp是默認的ss棧段的指針;顯然,將臨時的數據保存在一個寄存器中的方式是不合適的。

       (3)既然不能講暫存的數據(它可能是寄存器變量的值,也可能是內存中單元的值)保存到一個寄存器中,那么使用內存作為暫存空間是可行的。我們將代碼繼續改進。

        改進后的代碼:

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

    dw 0                    ;定義一個字,用於暫存cx值

data ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作為基本偏址變量

        mov cx, 4           ;需要外循環4次,修改4個字符串

   

    s0: mov ds:[40H], cx    ;將外層循環計數器cx保存到data內存中

        mov si, 0           ;si作為每個字符串的偏址

       

        mov cx, 3           ;內存循環s1,需要循環3次

    s1: mov al, [bx+si]     ;使用[bx+si]尋址方式,並送入al(單字節)

        and al, 11011111b   ;轉換為大寫字母

        mov [bx+si], al     ;回寫內存

        inc si                 

        loop s1

       

        add bx, 16          ;6個字符串長度一致,都是16字節,增量為16

        mov cx, ds:[40H]    ;將外層循環計數器cx從data內存中恢復

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       結果分析:

       (1)在data段中定義了一個字單元空間,用於暫存cx的值。用直接尋址方式就行了。它在data段中偏移地址是40H,那么ds:[40H]==data:[40H]就代表了內存的那個字。

       (2)這種情況,如果需要暫存的數據多的情況下,比較混亂,你還得記住內存單元的地址。

       (3)一般來說,在需要暫存數據的時候,我們都應該使用棧。

       繼續改進代碼,使用人工創建的棧空間來暫存cx值。

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

stack segment

    db 16 dup (0)           ;人工定義一個棧段,空間16個字節,初始化為0

stack ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作為基本偏址變量

        mov cx, 4           ;需要外循環4次,修改4個字符串

       

        mov ax, stack          

        mov ss, ax          ;人工創建一個棧結構

        mov sp, 16          ;將ss:sp指向棧頂

       

    s0: push cx             ;將外層循環計數器cx保存到stack棧中

        mov si, 0           ;si作為每個字符串的偏址

       

        mov cx, 3           ;內存循環s1,需要循環3次

    s1: mov al, [bx+si]     ;使用[bx+si]尋址方式,並送入al(單字節)

        and al, 11011111b   ;轉換為大寫字母

        mov [bx+si], al     ;回寫內存

        inc si                 

        loop s1

       

        add bx, 16          ;6個字符串長度一致,都是16字節,增量為16

        pop cx              ;將外層循環計數器cx從stack棧中恢復

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       結果分析:

       (1)以后我們遇到越來越多的將暫存的數據存儲在棧空間中去。下面講到的子程序就大量使用棧。

       (2)此例中我們使用的是人工創建的棧結構,還是就是系統自動創建的棧結構,那個我們不需要在內存中定義棧空間所需的單元。

 

(2)編程完成7.9問題中的程序

問題 7.9編程將data段中每個單詞的前4個字母改為大寫字母。

assume cs:code

data segment

    db '1. display      '

    db '2. brows        '

    db '3. replace      '

    db '4. modify       '

data ends

stack segment

    db 16 dup (0)           ;人工定義一個棧段,空間16個字節,初始化為0

stack ends

       程序分析:

       (1)4個字符串,每個字符串長度都相同,都是16個字節,並且是連續的,此時我們可以把這種結構看成是一個二維數組。每個單詞字符長度都大於4.

       (2)需要改變的是每個字符串的第4個字符開始的4個字符,那么在每一行,我們表示內存單元可以使用[si+idata]的方式尋址,idata代表每個行(每個字符串)開始地址3.si作為每行的偏移地址,偏移量從0~3;由於是個二維數組結構,bx代表每行的偏移量,偏移量從0~3,最終我們采用[bx+si+idata]尋址的方式來定位每行的字符串。

       代碼如下:

assume cs:code

data segment

    db '1. display      '

    db '2. brows        '

    db '3. replace      '

    db '4. modify       '

data ends

stack segment

    db 16 dup (0)           ;人工定義一個棧段,空間16個字節,初始化為0

stack ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作為基本偏址變量

               

        mov ax, stack          

        mov ss, ax          ;人工創建一個棧結構

        mov sp, 16          ;將ss:sp指向棧頂

       

        mov cx, 4           ;需要外循環4次,修改4個字符串

    s0: push cx             ;將外層循環計數器cx保存到stack棧中

        mov si, 0           ;si作為每個字符串的偏址

       

        mov cx, 4           ;內存循環s1,需要循環4次

    s1: mov al, [bx+si+3]   ;使用[bx+si+3]尋址方式,並送入al(單字節)

        and al, 11011111b   ;轉換為大寫字母

        mov [bx+si+3], al   ;回寫內存

        inc si                 

        loop s1

       

        add bx, 16          ;4個字符串長度一致,都是16字節,增量為16

        pop cx              ;將外層循環計數器cx從stack棧中恢復

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       程序運行結果:

-d ds:0

0B65:0000  31 2E 20 44 49 53 50 6C-61 79 20 20 20 20 20 20   1. DISPlay

0B65:0010  32 2E 20 42 52 4F 57 73-20 20 20 20 20 20 20 20   2. BROWs

0B65:0020  33 2E 20 52 45 50 4C 61-63 65 20 20 20 20 20 20   3. REPLace

0B65:0030  34 2E 20 4D 4F 44 49 66-79 20 20 20 20 20 20 20   4. MODIfy

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM