1. 程式人生 > 實用技巧 >[Assembly Language] 實驗2 彙編源程式編寫與彙編、除錯

[Assembly Language] 實驗2 彙編源程式編寫與彙編、除錯

Task1 編寫8086彙編源程式並進行彙編、連結、除錯

ex1.asm 檔案的內容如下:

;ex1.asm
assume cs:code
code segment
    mov ax, 0b810h
    mov ds, ax

    mov byte ptr ds:[0], 1
    mov byte ptr ds:[1], 1
    mov byte ptr ds:[2], 2
    mov byte ptr ds:[3], 2
    mov byte ptr ds:[4], 3
    mov byte ptr ds:[5], 3
    mov byte ptr ds:[6], 4
mov byte ptr ds:[7], 4 mov ah, 4ch int 21h code ends end

在DOSBox中使用masm命令對ex1.asm檔案進行彙編,再對生成的.obj檔案使用link命令生成.exe檔案,具體指令為:

  • masm ex1.asm;
  • link ex1.obj;

(指令後面加分號可以略過一些細節引數的設定)

輸入ex1.exe執行,發現視窗上方出現蜜汁字元,出現的原因參考實驗1中相關內容。

在debug模式下,使用d命令檢視程式段字首PSP所佔的256個位元組。

根據暫存器CX中的值(CX=0031),得知彙編指令佔32位元組,使用命令-u 0 31,對exe檔案進行反彙編。

使用g命令執行該彙編程式,得到結果如下(與直接執行exe檔案效果相同):

(注:這裡可能會出現蜜汁字元不顯示的問題。原因是把字元打到指定位置後,由於-g命令的反饋資訊,介面向下滾動了3行,導致原來的字元也向上滾了3行,正好在介面外。通過檢視這些地址的值,發現已經被改變了,實際上這些值與介面中原字元對應位置的顯示內容有關。因此只要讓介面不滾動,就能完美地在指定位置輸出蜜汁字元。)

Task2編寫8086彙編源程式並進行彙編、連結、除錯(使用loop)

ex2.asm 檔案的內容如下:

; ex2.asm
assume cs:code
code segment
    mov ax, 0b810h
    
mov ds, ax mov bx, 0 mov ax, 101h mov cx, 4 s: mov [bx], ax add bx, 2 add ax, 101h loop s mov ah, 4ch int 21h code endss end

使用masm、link命令彙編連結,執行ex2.exe,與ex1.exe的執行效果相同。

對ex2.exe使用debug工具,輸入u命令進行精確反彙編。

loop指令的地址為0016,輸入-g 16,顯示迴圈體第一次執行結果。之後每個步驟的顯示由於介面上滾,無法顯示,因此對原始碼修改記憶體的位置做出一點改動(初始DS改成B840),重新生成ex2.exe.

交替使用 -t 和 -g 16,顯示出每一步列印在螢幕上的字元(不對齊的原因 task1 中已經說了)。

排除除錯時螢幕滾動重新整理的原因,直接執行ex1.asm和ex2.asm所產生的exe的效果是一致的。

程式碼書寫上,ex1.asm採用順序結構,ex2.asm採用迴圈結構。後者對於開發者而言書寫的效率更高,但同時也讓機器執行了更多的指令,時間上並不優於前者。

Task3綜合使用loop, [bx],實現向記憶體b800:07b8開始的連續16個字單元重複填充字資料 0237H

編寫程式 ex3.asm 如下:

assume cs:code
code segment
    mov ax, 0b800h
    mov ds, ax
    
    mov bx, 07b8h
    mov ax, 0237h
    mov cx, 16
m:  mov [bx], ax
    add bx, 2
    loop m
    
    mov ah, 4ch
    int 21h
code ends
end

使用 masm 和 link 對 ex3 進行彙編、連結,執行生成的exe檔案。

分別將填充的字資料改為 0239h 和 0437h,重新彙編連結過後,執行的結果如下:

猜測字資料的高位儲存的是字元的顏色,低位儲存的為字元的ASCII碼。

共256種顏色,其中後128種有閃爍效果。

共256種字元樣式,其中後128種為擴充套件ASCII碼。

Task4編寫完整彙編源程式,實現向記憶體0:200~0:23F依次傳送資料0~63(3FH)

(1)使用loop,[bx]實現

程式碼如下:

assume cs:code
code segment
    mov ax, 0020h
    mov ds, ax
    
    mov bx, 0h
    mov cx, 40h
m:  mov [bx], bl
    add bx, 0001h
    loop m
    
    mov ah, 4ch
    int 21h
code ends
end

執行結果如下:

Task5 補全程式碼並除錯

該程式的功能是將 "mov ax, 4c00h" 之前的指令複製到 0:200 處,待補全程式碼如下:

 1 assume cs:code
 2 code segment
 3     mov ax, _____
 4     mov ds, ax
 5 
 6     mov ax, 0020h
 7     mov es, ax
 8     mov bx, 0
 9     mov cs, _____
10 s:  mov al, [bx]
11     mov es:[bx], al
12     inc bx
13     loop s
14 
15     mov ax, 4c00h
16     int 21h
17 code ends
18 end

填入程式碼為:

(1)mov ax, cs

(2)mov cx, 17h

填入後在 debug 模式下執行,使用 -d 命令分別檢視 0:200 和 076A:0 開始的資料。

該程式的功能是把從 076A:0 開始的若干位元組資料放入 0:200 開始的若干地址,寫入資料的量與具體填入的空有關。

如果一開始填入 mov ax, 076A,則有18h個位元組資料;填入 mov ax, cs,則有17h個位元組資料。原因是,mov 指令後如果是兩個暫存器佔用 2 個位元組,如果是一個暫存器和一個立即數佔用 3 個位元組。(通過觀察 -u 指令後每條指令所佔空間可以推斷出)

得知位元組數量最簡單的方法是,根據 CX 的值減去最後兩條指令佔的 5 個位元組(再填入到第二個空中)。