1. 程式人生 > 實用技巧 >實驗二 彙編源程式編寫與彙編、除錯

實驗二 彙編源程式編寫與彙編、除錯

一、實驗目的 1. 理解並掌握彙編源程式組成與結構 2. 掌握組合語言源程式編寫→彙編→連結→除錯的工具和方法 3. 理解彙編源程式中地址表示、段暫存器的用法 4. 理解和掌握暫存器間接定址方式[bx] 5. 通過彙編指令loop的使用理解程式語言中迴圈的本質 二、實驗準備 1. 學習/複習第5章使用[bx]和loop實現迴圈的程式設計應用示例(教材5.5節,5.8節) 2. 複習第3章「棧」的知識 3. 結合第4章課件,複習完整彙編源程式編寫→彙編→連線→執行→除錯的方法 4. 複習8086彙編中記憶體單元地址的表示,以及段暫存器DS, SS, ES, CS的用途三、實驗內容 三、實驗內容
1. 實驗任務1 使用任意一款文字編輯器,編寫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

要求:

  • 使用8086彙編程式編寫、彙編、連結、執行、除錯方法,對ex1.asm進行彙編、連結、執行,使用debug工具除錯可執行檔案。

使用masm、link對ex1.asm進行彙編、連結,得到可執行檔案ex1.exe,執行並觀察結果。

  • 使用debug工具對程式進行除錯
    • 使用debug載入可執行檔案ex1.exe後,使用d命令檢視程式段字首PSP所佔的256個位元組。
    • 結合可執行檔案中暫存器CX的值,使用u命令對ex1.exe進行精確反彙編。
    • 使用g命令執行到程式退出執行之前(即原始碼檔案中line16之前),觀察結果。

2. 實驗任務2 使用任意一款文字編輯器,編寫8086彙編源程式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 ends
end

要求:使用8086彙編程式編寫、彙編、連結、執行、除錯方法,對ex2.asm進行彙編、連結、執行,使用debug工具除錯可執行檔案。

  • 使用masm、link對ex2.asm進行彙編、連結,得到可執行檔案ex2.exe,執行並觀察結果。
  • 使用debug工具對程式進行除錯。
    • 結合可執行檔案中暫存器CX的值,使用u命令對ex2.exe進行精確反彙編
    • 靈活使用t命令、p命令、g命令,對ex2.exe進行除錯。(不一定要單步,有些地方可以用g命令,一次執行多行彙編指令)


注意:單步除錯時,對於迴圈指令loop,中斷指令int,使用t命令和p命令單步除錯的區別。

  • 把ex2.asm中line9 mov cx, 4改成 mov cx, 8 ,儲存後重新彙編、連結、執行並觀察結果。
  • 結合上述實驗和觀察,分析、對比ex2.asm和ex1.asm,它們實現的是否是相同的功能和效果?在 具體實現上有什麼不同?

3. 實驗任務3

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

要求:

  • 編寫彙編源程式
  • 給出執行結果截圖

   如程式編寫正確,預期結果如圖所示。(執行前先使用 命令清屏,更便於觀察執行結果)


  • 把填充的字資料,從0237H改成0239H,再次儲存後,彙編、連結、執行,觀察結果。

把填充的字資料,從0237H改成0437H,再次儲存後,彙編、連結、執行,觀察結果。

猜測並分析,這個字資料中高位位元組裡存放的是什麼資訊,低位位元組裡存放的是什麼資訊。

4. 實驗任務4
  • 編寫完整彙編源程式,實現向記憶體0:200~0:23F依次傳送資料0~63(3FH)。
    • 必做
      • 綜合使用[bx]和loop,編寫彙編源程式靈活使用debug的t命令、g命令、p命令除錯。在程式退出前,用d命令檢視0:200~0:23F,確認是否將0~3F傳送至此段記憶體區域。
    • 選做*
      • 利用棧的特性,綜合使用loop,push實現(限定僅使用8086中已學過指令實現),編寫源程式
      • 靈活使用debug的t命令、g命令、p命令除錯。在程式退出前,用d命令檢視0:200~0:23F,確認是否將0~3F傳送至此段記憶體區域。

Tips:

這道練習,本質上就是把一組連續的位元組資料(常數),送到指定的連續的位元組單元。如果利用棧實現,藉助push和loop實現連續入棧操作。需要注意:

  1. 初始時ss和sp的設定
  2. 8086的入棧操作,是從高地址單元→低地址單元方向的;
  3. 8086的入棧操作,只能以字為單元。但這裡是位元組資料,如何靈活處理?

5. 實驗任務5 教材實驗4(3)(P121)
Tips:這道練習,本質仍然是複製,只不過複製的是自身程式碼。填空的關鍵是,如何確定複製多少位元組。
6. 實驗任務6(選做*)

在linux環境下,編寫、彙編、執行、除錯一個32位的Intel風格的x86彙編程式。

第1步,使用vim或其它任意文字編輯器,編寫一個32位的Intel風格的x86彙編源程式example.asm。


; example.asm
glogal _start
section .data
msg db "a simple test", 0xa len equ $ - msg
section .text _start:
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, len
    int 0x80 ; 呼叫linux下的int 0x80中斷的4號子功能,輸出字串
    mov eax, 1
    mov ebx, 0
    int 0x80 ; 呼叫linux下的int 0x80中斷的1號子功能,退出

第2步,使用nasm,對example.asm進行彙編。

nasm -f elf32 example.asm
  • 選項- f表示指定目標檔案格式。這裡指定目標檔案格式是elf32格式

如彙編成功,會生成目標檔案example.o。執行nasm命令後,可以使用ls命令檢視。

如果希望將來使用gdb工具對可執行檔案進行除錯,則使用nasm彙編時還需要增加一個選項-g,目的 是向目標檔案中增加符號和除錯的相關資訊。即:

nasm -f elf32 example.asm -g

第3步,使用ld,對example.o進行連結。

ld -m elf_i386 example.o -o example
  • 選項-m指定模擬模式。這裡指定模擬intel 32位的模式。
  • 選項-o用於指定可執行檔案的名稱。這裡指定生成的可執行檔名是example

如連結成功,會生成可執行檔案example。

第4步,執行可執行檔案example。

./example

執行後,可以在shell命令終端檢視返回值:

echo $?

顯示返回值0,對應原始碼檔案中line18暫存器ebx的值。

把example.asm中line18行中暫存器ebx的值改成別的數值,比如7。重新彙編、連結、執行。再次使用echo $?檢視返回值,觀察這次返回值是什麼。

注*:

1.彙編指令與硬體相關,因此,指令集有x86的彙編指令集,也有MIPS彙編指令集;書寫風格既有intel風格,也有AT&T風格。linux下預設是AT&T風格的。此外,可用的工具也種類繁多。這裡僅列出一個簡單示例,請根據個人情況自行探索實踐。

2.使用gdb除錯時,也需要掌握類似於debug下很多命令,比如list(檢視程式碼)、b(break,設定斷點)、r(run,執行)、檢視暫存器(info registers),等等。這裡沒有進一步提供使用gdb除錯的方法和步驟。請自行檢索相關工具文件,輔助嘗試。

四、實驗結論

1.實驗任務1

ex1.asm原始碼:

對原始碼進行彙編,連結,生成可執行檔案,執行結果為:

用debug對程式的執行過程進行跟蹤,用r命令檢視各暫存器的設定情況,根據CX的值用u命令進行反彙編,用d命令檢視程式段字首PSP所佔的256個位元組:

使用g命令執行到程式退出之前:

2.實驗任務2

ex2.asm原始碼:

使用masm,link對ex2.asm進行彙編,連結,執行,除錯:

使用debug工具對程式進行除錯,介乎額可執行檔案中暫存器CX的值,使用u命令進行精確返回百年,使用t命令,p命令,g命令,對ex2.exe進行除錯:

用g命令除錯到迴圈位置,緊接著用p命令直接執行完迴圈的內容,再用t去進行單步除錯,再遇到int 21時,用p命令退出該除錯:

用g命令除錯到迴圈位置,此時用t命令進行單步除錯,不會自動執行完迴圈的內容,而是一步步執行:

將ex2.asm中的mov cx,4改成mov cx,8,進行彙編,連結,執行,得到的結果為:

ex1.asm進行彙編,連結,執行的結果為:

顯示出的結果不相同,我將ex2.asm中的mov cx,8繼續改回到mov cx,4,進行彙編,連結,執行得到的結果為:

通過對比發現,ex2.asm和ex1.asm以及ex2.asm改變前後的結果不同可能是由於迴圈的次數不相同,mov cx,4所表示的意思是將迴圈進行4次,mov cx,8是將迴圈進行8次,一個得出的是4個圖案,另一個得出的是8個圖案,同樣的ex1.asm也迴圈了四次,因此出現的也是4個圖案。

3.實驗任務3

原始碼:

向記憶體b800:07b8開始的連續16個字單元重複填充字資料0237H:

向記憶體b800:07b8開始的連續16個字單元重複填充字資料0239H:

向記憶體b800:07b8開始的連續16個字單元重複填充字資料0437H:

猜想:字資料中高位位元組存放的是顏色,低位位元組存放的是內容

通過對比發現,當高位位元組改變時,執行結果的顏色進行了改變,當低位位元組改變時,執行結果的內容進行了改變。

4.實驗任務4

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

(1)必做:綜合使用[bx]和loop,編寫彙編源程式

程式碼:

對該源程式進行彙編,連結並用debug進行跟蹤除錯,用t命令,g命令,p命令進行除錯,並用d命令檢視是否將0~3F傳送到了0:200~0~23F中:

5.實驗任務5

原始碼為:

由於程式的起始地址由CS:IP指定,因此 mov ax,__處填寫CS,CS表示的是程式碼的段暫存器;

第九行填寫mov cx,16;

本題要求的是將mov ax,4c00h之前的程式碼段複製到0:200處,首先根據上述程式碼進行彙編,連結,並進行除錯

通過精確的反彙編可以發現,mov ax,4c00這條指令在076A:0017處,說明以上的指令是從076a:0~076a:0016,IP=IP+之前指令的位元組數為16h,因此填寫的內容為mov cx,16h.

用d命令檢視,發現已經mov ax, 4c00h之前的指令複製到指定記憶體