1. 程式人生 > 實用技巧 >組合語言程式設計第三次實驗 多個段的彙編源程式編寫與除錯

組合語言程式設計第三次實驗 多個段的彙編源程式編寫與除錯

一、實驗目的

1. 理解和掌握將資料、程式碼、棧放入不同邏輯段的程式的編寫和除錯

2. 理解具有多個段的彙編源程式對應的目標程式執行時,記憶體分配方式

3. 掌握大小寫字元的轉換方法、數字字元和數值之間的轉換方法

4. 理解並掌握各種定址方式的靈活應用

5. 掌握彙編指令loop, and, or,div, mul的用法

二、實驗準備

複習教材chapter 6-8章。

chapter 6 包含多個段的程式

chapter 7 更靈活的定位記憶體地址的方法

chapter 8 資料處理的兩個基本問題

三、實驗內容

1. 實驗任務1

(1)原始碼檔案task.asm

 1 assume cs:
code, ds:data 2 data segment 3 db 'Nuist' 4 db 5 dup(2) 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 12 mov ax, 0b800H 13 mov es, ax 14 15 mov cx, 5 16 mov si, 0 17 mov di, 0f00h 18 s: mov al, [si]
19 and al, 0dfh 20 mov es:[di], al 21 mov al, [5+si] 22 mov es:[di+1], al 23 inc si 24 add di, 2 25 loop s 26 27 mov ah, 4ch 28 int 21h 29 code ends 30 end start

(2)從理論上分析原始碼的功能。

  mov cx, 5        //將cx暫存器賦值為5,設定迴圈次數
  mov si, 0        //設定資料段偏移地址為0
  mov di, 0f00h      //設定es段的偏移地址為0f00h s: mov al, [si]       //將記憶體單元ds:[si]中的資料傳入al   and al, 0dfh       //將al中的字母變成大寫   mov es:[di], al     //將al中的資料賦值給es:[di]   mov al, [5+si]      //將ds:[5*si]中的資料傳給al   mov es:[di+1], al    //將al中的資料傳給es:[di+1]   inc si          //將ds的偏移地址si加1   add di, 2        //將es的偏移地址di加2
  loop s          //轉移到s:的開始位置,cx-1,在cx大於0的情況下繼續迴圈

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

(4)使用debug工具對程式進行除錯,執行到程式返回前,觀察結果。

(5)修改line裡5個位元組單元的值,重新彙編、連線、執行,觀察結果。

 1 assume cs:code, ds:data
 2 data segment
 3         db 'Nuist'
 4         db 2,3,4,5,6
 5 data ends
 6 
 7 code segment
 8 start:
 9         mov ax, data
10         mov ds, ax
11 
12         mov ax, 0b800H
13         mov es, ax
14 
15         mov cx, 5
16         mov si, 0
17         mov di, 0f00h
18 s:      mov al, [si]
19         and al, 0dfh
20         mov es:[di], al
21         mov al, [5+si]
22         mov es:[di+1], al
23         inc si
24         add di, 2
25         loop s
26 
27         mov ah, 4ch
28         int 21h
29 code ends
30 end start

觀察到數值的顏色發生了變化,猜測這裡5個位元組單元的值的作用是設定字型的顏色。

2.實驗任務2

(1)已知資料段data中定義位元組資料如下:

1 data segments
2   db 23, 50, 66, 71, 35
3 data ends

編寫程式,在螢幕上以十進位制整數形式列印輸出這5個兩位數。

提示: 1個兩位數如何輸出

思路如下:

具體處理步驟如下:

第1步,利用除法指令div,計算出每個數位上的數值。

第2步,利用數值和數字字元之間ascⅡ碼的關係,把數值→數字字元。

第3步,利用系統功能呼叫int 21h中的2號子功能,輸出單個字元。

int 21h中的2號子功能說明如下:

功能:輸出單個字元

用法:

1 mov ah, 2
2 mov dl, ×× ; ××是待輸出的字元,或其ASCⅡ碼值
3 int 21h

5個兩位數如何輸出?:利用loop指令,以及,靈活的定址方式。

(2)原始碼檔案task2.asm

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3     db 23, 50, 66, 71, 35
 4 data ends
 5 
 6 stack segment
 7     db 2 dup(0)
 8 stack ends
 9 
10 code segment
11 start:    
12     mov ax, data
13     mov ds, ax
14     
15     mov ax, stack
16     mov ss, ax
17     mov sp, 10h
18 
19     mov cx, 5
20     mov si, 0
21 s:    mov ah, 0    ;ah存放餘數,al存放商
22     mov al, ds:[si]
23     mov bl, 10
24     div bl
25     push ax        ;8086彙編進行push、pop只對字操作
26 
27     pop bx
28     mov ah, 2
29     mov dl, bl
30     add dl, 30h
31     int 21h
32 
33     mov ah, 2
34     mov dl, bh
35     add dl, 30h
36     int 21h
37 
38     mov ah, 2
39     mov dl, " "
40     int 21h
41 
42     inc si
43     loop s
44 
45     mov ah, 4ch
46     int 21h
47 code ends
48 end start

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

3.實驗任務3

(1)原始碼檔案task3.asm

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0, 0, 0, 0, 0, 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start

(2)教材上的①②③三個問題

①data段中的資料是:23 01 56 04 89 07 bc 0a ef 0d ed 0f ba 0c 87 09

觀察到的結果和理論分析一致。

②cs=0766,ss=0765,ds=0764

③程式載入後,code段的段地址為X,則data段的段地址為X-2,stack段的段地址為X-1。

4.實驗任務4

(1)原始碼task4.asm

 1 assume cs:code, ds:data, ss:stack
 2 data segment
 3   dw 0123h, 0456h
 4 data ends
 5 
 6 stack segment
 7   dw 0, 0
 8 stack ends
 9 
10 code segment
11 start:  mov ax,stack
12         mov ss, ax
13         mov sp,16
14         
15         mov ax, data
16         mov ds, ax
17         
18         push ds:[0]
19         push ds:[2]
20         pop ds:[2]
21         pop ds:[0]
22         
23         mov ax,4c00h
24         int 21h
25 
26 code ends
27 end start

(2)回答教材中①②③④四個問題

①CPU執行程式,程式返回前,data段中的資料是23 01 56 04。

②CPU執行程式,程式返回前,cs=0766,ss=0765,ds=0764。

③程式載入後,code段的段地址為X,則data段的段地址為X-2,stack段的段地址為X-1。

④對於如下定義的段:

name segment
……
name ends

如果段中的資料佔N個位元組,則程式載入後,該段實際佔有的空間為int(N/16+1)*16。

5.實驗任務5

(1)原始碼檔案task5.asm

 1 assume cs:code, ds:data, ss:stack
 2 
 3 code segment
 4 start:  mov ax,stack
 5         mov ss, ax
 6         mov sp,16
 7         
 8         mov ax, data
 9         mov ds, ax
10         
11         push ds:[0]
12         push ds:[2]
13         pop ds:[2]
14         pop ds:[0]
15         
16         mov ax,4c00h
17         int 21h
18 
19 code ends
20 data segment
21   dw 0123h, 0456h
22 data ends
23 
24 stack segment
25   dw 0,0
26 stack ends
27 end start

(2)回答教材中①②③三個問題

①CPU執行程式,程式返回前,data段中的資料為 23 01 56 04.

②CPU執行程式,程式返回前,cs=076A,ss=076E,ds=076D。

③程式載入後,code段的段地址為X,則data段的段地址為X+4,stack段的段地址為X+3。

6.實驗任務6

(1)回答教材中提出的問題,並按要求說明原因。

問:如果將task3.asm、task4.asm、task5.asm中的最後一條偽指令“end start”改為“end”(也就是說不指明程式的入口),則哪個程式仍然可以正常執行?請說明原因。

答:task5.asm在彙編、連結之後可以執行。因為程式段在最前面,在不指明的情況下,預設程式段從頭開始。

7.實驗任務7

(1)原始碼檔案task7.asm

 1 assume cs:code
 2 a segment
 3   db 1,2,3,4,5,6,7,8
 4 a ends
 5 
 6 b segment
 7   db 1,2,3,4,5,6,7,8
 8 b ends
 9 
10 c1 segment   
11   db 8 dup(0)
12 c1 ends
13 
14 code segment
15 start:
16     mov ax,a
17     mov ds,ax
18 
19     mov ax,c1
20     mov es,ax
21 
22     mov si,0
23     mov cx,8
24     mov ax,0
25 
26 s:    mov ax,ds:[si]
27     add ax,ds:[si+10h]
28     mov es:[si],ax
29 
30     inc si
31     mov ax,0
32     loop s
33 
34     mov ax,4ch
35     int 21h
36 code ends
37 end start

(2)附上在debug環境中,執行到程式返回前,檢視邏輯段c的資料的截圖,以此驗證所編寫的程式正 確實現了題目要求。

8.實驗任務8

(1)原始碼檔案task8.asm

 1 assume cs:code
 2 a segment
 3   dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
 4 a ends
 5 
 6 b segment
 7   dw 8 dup(0)
 8 b ends
 9 
10 code segment
11 start: 
12     mov ax, a
13     mov ds, ax
14 
15     mov cx, 8
16     mov si, 0
17 s:    push ds:[si]
18     add si, 2
19     loop s
20 
21     mov ax, b
22     mov ds, ax
23 
24     mov cx, 8
25     mov si, 0
26 s1:    pop ds:[si]
27     add si, 2
28     loop s1
29 
30     mov ax, 4ch
31     int 21h
32 code ends
33 end start

(2)附上在debug環境中,執行到程式返回前,檢視邏輯段c的資料的截圖,以此驗證所編寫的程式正 確實現了題目要求。

五、實驗總結

1、將資料段和棧段放在程式碼段後邊的時候,計算精確反彙編的時候出現了問題,使用d命令檢視後得知,如果不是最後一個段,那麼它所佔的位元組數一定是16的倍數,因此程式碼段後邊會有一部分空間儲存的不是程式碼資料。