第02組 每週小結 (2/3)
一、實驗目的
1. 理解80×25彩色字元模式顯示原理
2. 理解轉移指令jmp, loop, jcxz的跳轉原理,掌握使用其實現分支和迴圈的用法
3. 理解轉移指令call, ret, retf的跳轉原理,掌握組合使用call和ret/retf編寫彙編子程式的方法,掌握 引數傳遞方式
4. 理解標誌暫存器的作用
5. 理解條件轉移指令je, jz, ja, jb, jg, jl等的跳轉原理,掌握組合使用匯編指令cmp和條件轉移指令實 現分支和迴圈的用法
6. 瞭解在visual studio/Xcode等環境或利用gcc命令列引數反彙編c語言程式的方法,理解編譯器生成 的反彙編程式碼
7. 綜合應用定址方式和彙編指令完成應用程式設計
二、實驗內容
1.程式設計:在螢幕中間分別顯示綠色、綠底紅色、白底藍色的字串'welcome to masm!'。
程式碼實現:
assume cs:codesg, ds:datasg, ss:stacksg datasg segment db 'welcome to masm!' db 2h,24h,71h datasg ends stacksg segment stack db 16 dup (0) stacksg ends codesg segment start: mov ax,datasg mov ds,ax mov ax,stacksg mov ss,ax mov sp,16 mov ax,0B872h mov es,ax mov cx,3 mov bx,0 s: push cx mov cx,16 mov si,0 mov di,0 s0: mov al,ds:[di] mov ah,ds:[bx+16] mov es:[si],ax add si,2 inc di loop s0 pop cx mov ax,es add ax,00ah mov es,ax inc bx loop s mov ax,4c00h int 21h codesg ends end start
結果顯示:
程式碼簡析:首先借助PPT可知,8086下視訊記憶體空間的大小為25*80個字,開始地址為b800H,想要顯示在螢幕中間,偏移地址所佔的行數應該從第11行開始,查表可得對應的十
進位制偏移地址為1760,又因為視訊記憶體單元高位位元組控制顏色,低位位元組控制內容,所以“welcome to masm!”和其對應的顏色欄位共佔16個字,從而開始地址應該為第11行往後,
(80-16)/2=36,第36列。所以,最終的偏移地址:1760+36*2=1832;轉為十六進位制:0720H。由於要顯示三行且顏色不同,因此採用雙層迴圈實現,利用棧空間來使暫存器CX的值
依據迴圈層次的不同變化,除此之外,其基本實現原理與實驗三中類似。
2.編寫子程式printStr,實現以指定顏色在螢幕上輸出字串。呼叫它,完成字串輸出。
程式碼實現:
assume cs:code, ds:data data segment str db 'try', 0 data ends code segment start: mov ax, data mov ds, ax mov si, offset str mov al, 2 call printStr mov ah, 4ch int 21h printStr: push bx push cx push si push di mov bx, 0b800H mov es, bx mov di, 0 s: mov cl, [si] mov ch, 0 jcxz over mov ch, al mov es:[di], cx inc si add di, 2 jmp s over: pop di pop si pop cx pop bx ret code ends end start
結果顯示:
對源程式做如下修改,將line3改為str db 'another try', 0將line12改為mov al, 4,再次彙編,觀察執行結果。
- line19-22, line36-39,這組對稱使用的push、pop,這樣用的目的是什麼?
- 答:line19-22中將可能用到的暫存器bx,cx,si,di壓棧,以防止在子程式執行過程中改變了某些重要資料。line36-39將它們出棧,恢復進入子程式前的環境。
- line30的功能是什麼?
- 答:將字元以及對應的顏色資訊儲存到
3.使用任意文字編輯器,錄入彙編源程式task3.asm。
程式碼如下:
assume cs:code, ds:data data segment x dw 1984 str db 16 dup(0) data ends code segment start: mov ax, data mov ds, ax mov ax, x mov di, offset str call num2str mov ah, 4ch int 21h num2str: push ax push bx push cx push dx mov cx, 0 mov bl, 10 s1: div bl inc cx mov dl, ah push dx mov ah, 0 cmp al, 0 jne s1 s2: pop dx or dl, 30h mov [di], dl inc di loop s2 pop dx pop cx pop bx pop ax ret code ends end start
子任務1:task3.asm進行彙編、連結,得到可執行程式後,在debug中使用u命令反彙編,使用g命令執行 到line15(程式退出之前),使用d命令檢視資料段內容,觀察是否把轉
換後的數字字串'1984'存放 在資料段中str標號後面的單元。
觀察可得:1984被轉為了字元,存放在076a:2-076a:f中,對應的ASCLL碼分別是31,39,38,34。
子任務2:對task3.asm原始碼進行修改、完善,把task2.asm中用於輸出以0結尾的字串的子程式加進來, 實現對轉換後的字串進行輸出。
4.使用任意文字編輯器,錄入彙編源程式task4.asm。
assume cs:code, ds:data data segment str db 80 dup(?) data ends code segment start: mov ax, data mov ds, ax mov si, 0 s1: mov ah, 1 int 21h mov [si], al cmp al, '#' je next inc si jmp s1 next: mov cx, si mov si, 0 s2: mov ah, 2 mov dl, [si] int 21h inc si loop s2 mov ah, 4ch int 21h code ends end start
執行截圖:
- line12-19實現的功能是?
- 答:迴圈讀入從鍵盤輸入的字元,遇到‘#’停止,最大長度不得超過80。
- line21-27實現的功能是?
- 答:把si的值賦給cx,表明迴圈次數,然後把讀入的字元再重新輸出在螢幕上。
5.在visual studio整合環境中,編寫一個簡單的包含有函式呼叫的c程式。程式碼如下:
#include <stdio.h> int sum(int, int); int main() { int a = 2, b = 7, c; c = sum(a, b); return 0; } int sum(int x, int y) { return (x + y); }
總結對這個簡單的c程式碼反彙編後,你對反彙編出來的彙編指令分析的內容總結。
通過觀察反彙編程式碼,引數的入棧順序是先定義的後入棧,在呼叫sum函式之前,將a,b的值分別儲存到eax和ecx中,併入棧儲存現場,然後通過call命令轉到sum子程式執行,
引數的傳遞和返回值都是藉助暫存器實現的,sub esp,0c0h 是為了生成一段新的棧空間,lea edi,[ebp-0c0h]是將esp的地址存放在edi中,在執行完畢後,會將之前儲存的暫存器
的狀態出棧,恢復現場,執行ret操作回到主程式。