1. 程式人生 > 實用技巧 >【題解】Acwing 89 a ^ b

【題解】Acwing 89 a ^ b

------------恢復內容開始------------

實驗任務一:

 1 assume cs:code, ds:data, ss:stack
 2 
 3 data segment
 4     db 'welcome to masm!'
 5     db 2h,24h,71h           ;三行文字的顏色
 6 data ends
 7 
 8 stack segment
 9     db 16 dup (0)
10 stack ends
11 
12 code segment
13 start:
14         mov ax,data
15         mov ds,ax          ;
程式碼段的段始址送到ds 16 17 mov ax,stack 18 mov ss,ax 19 mov sp,16 ;棧段的棧頂指標指向ss:16 20 21 mov ax,0B87Ch ;將字串顯示在螢幕中間的位置 22 mov es,ax 23 24 mov cx,3 ;三行的顯示程式碼是外層迴圈三次 25 mov bx,0 ;記錄當前是第幾行,也是外層迴圈的次數 26 27 s: push
cx 28 mov cx,16 ;每行顯示16個字元,記憶體迴圈16次 29 mov di,0 ;記錄記憶體迴圈的次數 30 31 s0: mov al,ds:[di] ;低位元組顯示文字 32 mov ah,ds:[bx+16] ;高位元組顯示顏色屬性 33 mov si,di 34 add si,si 35 mov es:[si],ax 36 inc di 37 loop s0 38 39 pop
cx 40 mov ax,es 41 add ax,00ah ;切換到下一行的位置 42 mov es,ax 43 inc bx 44 loop s 45 46 mov ax,4c00h 47 int 21h 48 code ends 49 end start

執行結果為:

在一頁顯示緩衝區中:

偏移000~09F對應顯示器上的第1行(80個字元佔160個位元組);

偏移0A0~13F對應顯示器上的第2行;

偏移140~1DF對應顯示器上的第3行;

以此類推,可知偏移780~81F對應顯示器上的第12行。

在一行中,一個字元佔兩個位元組的儲存空間(一個字),低位位元組儲存字元的ASCLL碼,高位位元組儲存字元的屬性。一行共有80個字元,佔160個位元組。

即在一行中:

00~01單元對應顯示器上的第1列;

02~03單元對應顯示器上的第2列;

04~05單元對應顯示器上的第3列;

依此類推,可知,40~41單元對應顯示器上的第30列。

因此字串首地址設為:B878*16+40=B87Ch

黑底綠字,屬性位元組為:00000010

綠底紅字,屬性位元組為:00100100

白底藍字,屬性位元組為:01110001

注意:在顯示緩衝區中,偶地址存放字元,奇地址存放字元的顏色屬性

實驗任務二:

 1 assume cs:code, ds:data
 2 data segment
 3     str db 'another try', 0          ;定義以0結尾的字串try
 4 data ends
 5 
 6 code segment
 7 start:  
 8     mov ax, data
 9     mov ds, ax
10 
11     mov si, offset str       ;offset操作符取得了str的偏移地址0
12     mov al, 4
13     call printStr            ;跳轉指令,跳轉到printStr處執行
14 
15     mov ah, 4ch
16     int 21h
17 
18 printStr:
19     push bx                  ;將暫存器壓入棧,子程式中可能會用到這些暫存器
20     push cx
21     push si
22     push di
23 
24     mov bx, 0b800H
25     mov es, bx
26     mov di, 0
27 s:              mov cl, [si]
28     mov ch, 0
29     jcxz over                 ;cx為0時,指令跳轉到over處執行
30     mov ch, al
31     mov es:[di], cx
32     inc si
33     add di, 2
34     jmp s
35 
36 over:   pop di                 ;將暫存器出棧,恢復暫存器原先的值
37     pop si
38     pop cx
39     pop bx
40     ret
41 
42 code ends
43 end start

執行結果為:

對源程式做如下修改: 把line3改為:str db 'another try', 0
把line12改為:mov al, 4 彙編,連結,觀察執行結果為: 基於執行結果,理解原始碼,以及,組合使用轉移指令call和ret實現子程式的原理與方法。具體地,在line18-40中: line19-22, line36-39,這組對稱使用的push、pop,這樣用的目的是什麼? 答:由於暫存器數量有限,子程式中可能會使用到這些暫存器,但是我們不確定這些暫存器中是否儲存了重要的資訊,因此先將暫存器bx,cx,si,di壓入棧,在子程式中就可以隨意使用這些暫存器,子程式執行完畢,將暫存器出棧,出棧的同時暫存器也會恢復原來的值。 line30的功能是什麼? 答:line 30行的內容是mov ch, al,在line 12中有一條指令mov al, 4,這兩條指令表示將4送入到ch中,根據之前的實驗可知,高位位元組存放的是資料的顏色屬性,因此line 30行的功能是改變資料的顏色屬性。 實驗任務三:
 1 assume cs:code, ds:data
 2 data segment
 3         x dw 1984               ;定義x為一個字變數賦初值為1984
 4         str db 16 dup(0)     ;定義str為一個byte陣列,存放16個位元組的0
 5 data ends
 6 
 7 code segment
 8 start:  
 9         mov ax, data
10         mov ds, ax
11         mov ax, x
12         mov di, offset str
13         call num2str
14 
15         mov ah, 4ch
16         int 21h
17 
18 num2str:
19         push ax
20         push bx
21         push cx
22         push dx
23         
24         mov cx, 0
25         mov bl, 10
26 s1:      
27         div bl
28         inc cx
29         mov dl, ah
30         push dx
31         mov ah, 0
32         cmp al, 0
33         jne s1
34 s2:        
35         pop dx
36         or dl, 30h
37         mov [di], dl
38         inc di
39         loop s2
40         
41         pop dx
42         pop cx
43         pop bx
44         pop ax
45 
46         ret
47 code ends
48 end start

子任務一:

彙編,連結之後對該程式用u命令進行反彙編,用g命令執行到mov ah,4ch,用d命令檢視執行之後的結果,發現把轉換後的數字字串'1984'存放在資料段中str標號後面的單元。

子任務二:

 1 assume cs:code, ds:data
 2 data segment
 3         x dw 1984               ;定義x為一個字變數賦初值為1984
 4         str db 16 dup(0)     ;定義str為一個byte陣列,存放16個位元組的0
 5 data ends
 6 
 7 code segment
 8 start:  
 9         mov ax, data
10         mov ds, ax
11         mov ax, x
12         mov di, offset str
13         call num2str
14         mov si, offset str
15         call printStr
16 
17         mov ah, 4ch
18         int 21h
19 
20 num2str:
21         push ax
22         push bx
23         push cx
24         push dx
25         
26         mov cx, 0
27         mov bl, 10
28 s1:      
29         div bl
30         inc cx
31         mov dl, ah
32         push dx
33         mov ah, 0
34         cmp al, 0
35         jne s1
36 s2:        
37         pop dx
38         or dl, 30h
39         mov [di], dl
40         inc di
41         loop s2
42         
43         pop dx
44         pop cx
45         pop bx
46         pop ax
47 
48         ret
49 
50 printStr:
51     push bx
52     push cx
53     push si
54     push di
55 
56     mov bx, 0b800H
57     mov es, bx
58     mov di, 0
59 s:             
60                 mov cl, [si]
61     mov ch, 0
62     jcxz over
63     mov ch, al
64     mov es:[di], cx
65     inc si
66     add di, 2
67     jmp s
68 
69 over:       pop di
70     pop si
71     pop cx
72     pop bx
73     ret
74 code ends
75 end start

執行結果為:

將line3中的整數改為1234,彙編,連結,執行結果為:

將line3中的整數改為2020,彙編,連結,執行結果為:

通過實驗發現,修改數字之後,輸出的字元顏色及屬性都不相同。

實驗任務四:

 1 assume cs:code, ds:data
 2 data segment
 3         str db 80 dup(?)
 4 data ends
 5 
 6 code segment
 7 start:  
 8         mov ax, data
 9         mov ds, ax
10         mov si, 0
11 
12 s1:        
13         mov ah, 1
14         int 21h
15         mov [si], al
16         cmp al, '#'
17         je next
18         inc si
19         jmp s1
20 next:
21         mov cx, si
22         mov si, 0
23 s2:     mov ah, 2
24         mov dl, [si]
25         int 21h
26         inc si
27         loop s2
28 
29         mov ah, 4ch
30         int 21h
31 code ends
32 end start

執行結果為:

彙編、連結、執行程式,輸入一個字串並以#結束(比如,2020, bye#)觀察執行結果。結合執行結 果,理解程式功能,瞭解軟中斷指令。具體地: line12-19實現的功能是? 答:迴圈執行將輸入的單個字元寫入記憶體單元中,遇到#跳轉到next處執行。 line21-27實現的功能是? 答:迴圈執行輸出單個字元。 實驗內容五:

通過斷點設定,檢視反彙編程式碼,發現在c=sum(a,b)處的彙編指令先將b移到eax暫存器中,將eax壓棧,將a移到ecx暫存器中,將ecx壓棧,接著跳轉到048116Dh處執行,並將此時的add esp,8的偏移地址壓棧,被調函式也可以使用eax、edx、ecx這三個暫存器,所以規定呼叫者需儲存eax、edx和ecx,在從被調函式返回後先恢復這三個暫存器的值再繼續;被呼叫者儲存ebx、esi和edi這三個暫存器,對他們進行壓棧處理,執行完之後,進行出棧操作,遇到ret指令時,繼續回到call指令的下一條指令執行。

------------恢復內容結束------------