一、實驗目的
1. 理解和掌握轉移指令的跳轉原理
2. 掌握使用call和ret指令實現子程序的方法,理解和掌握其參數傳遞方式
3. 理解和掌握80×25彩色字符模式顯示原理
4. 綜合應用尋址方式和匯編指令完成簡單應用編程
二、實驗准備
復習教材9-10章: 轉移指令的跳轉原理 匯編指令jmp, loop, jcxz, call, ret, retf的用法
三、實驗內容
實驗任務1:
task1.asm代碼如下:
1 assume cs:code, ds:data 2 3 data segment 4 x db 1, 9, 3 5 len1 equ $ - x 6 7 y dw 1, 9, 3 8 len2 equ $ - y 9 data ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov si, offset x 17 mov cx, len1 18 mov ah, 2 19 s1:mov dl, [si] 20 or dl, 30h 21 int 21h 22 23 mov dl, ' ' 24 int 21h 25 26 inc si 27 loop s1 28 29 mov ah, 2 30 mov dl, 0ah 31 int 21h 32 33 mov si, offset y 34 mov cx, len2/2 35 mov ah, 2 36 s2:mov dx, [si] 37 or dl, 30h 38 int 21h 39 40 mov dl, ' ' 41 int 21h 42 43 add si, 2 44 loop s2 45 46 mov ah, 4ch 47 int 21h 48 code ends 49 end start
問題1:程序反匯編截圖如下:
可以看到Loop處的機器碼為E2F2,這里E2為Loop,而F2的含義是偏移量的補碼形式,我們將F2的2進制(11110010)求補后得10001110,即10進制中的-14,代表向前偏移14個字節,而我們用Loop指令的偏移地址與s1的偏移地址相減時發現偏移量為-12,所以並非從Loop指令處計算,而是從它的下一個指令所在的偏移地址計算,在本題中是001B,用001B和000D相減,可以得到偏移量為-14。CPU應該是先取Loop指令的下一條指令的偏移地址,然后從Loop指令的機器碼后兩位中獲得偏移量的補碼形式,再求補得到偏移量,然后用下一條指令的偏移地址與偏移量相減得到跳轉位置的偏移地址000D。
問題2:程序反匯編截圖如下:
可以看到Loop處的機器碼為E2F0,同問題1,由F0(11110000)求補得到10010000,即十進制中的-16,代表向前偏移16個字節,而此時CPU也是從Loop指令的下一條指令的偏移地址0039開始計算,將它與16相減,獲得s2處的偏移地址0029。
實驗任務2:
task2.asm源代碼如下:
1 assume cs:code, ds:data 2 3 data segment 4 dw 200h, 0h, 230h, 0h 5 data ends 6 7 stack segment 8 db 16 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov word ptr ds:[0], offset s1 17 mov word ptr ds:[2], offset s2 18 mov ds:[4], cs 19 20 mov ax, stack 21 mov ss, ax 22 mov sp, 16 23 24 call word ptr ds:[0] 25 s1: pop ax 26 27 call dword ptr ds:[2] 28 s2: pop bx 29 pop cx 30 31 mov ah, 4ch 32 int 21h 33 code ends 34 end start
問題1:從理論上看:
(1)call word ptr將下一條指令的偏移地址壓入棧,再跳轉到相應地址執行命令
(2)call dword ptr 先將下一條指令的段地址壓入棧,再將下一條指令的偏移地址壓入棧,再跳轉到相應地址執行命令。
(3)本題ds:[0]中存放的是s1的偏移地址,ds:[2]中存放的是s2的偏移地址,所以第一個call指令先將s1的偏移地址壓入棧,在跳轉到s1處執行pop ax,即將s1的偏移地址0021出棧並存放到ax。
(4)第二個call指令先將s2處的偏移地址壓入棧,再將s2處的段地址壓入棧,再跳轉到ds:[2]即s2處執行pop bx,即將s2的偏移地址0026出棧並存放到bx,再執行pop cx,即將s2的段地址076C出棧並存放到cx中。
綜上可得程序執行到line31之前,ax=0021,bx=0026,cx=076C
問題2:在debug中驗證,反匯編截圖如下:
執行到line31之前:
可以看到ax=0021,bx=0026,cx=076C,驗證正確。
實驗任務3:
task3.asm代碼編寫如下:
1 assume ds:data, cs:code 2 data segment 3 x db 99, 72, 85, 63, 89, 97, 55 4 len equ $- x 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov cx, len 13 mov byte ptr ds:[10], 10 14 15 s1: mov ah, 0 16 mov al, ds:[si] 17 18 div byte ptr ds:[10] 19 call printNumber 20 call printSpace 21 inc si 22 loop s1 23 24 mov ax, 4c00h 25 int 21h 26 27 printNumber:mov bx, ax 28 or bl, 30h 29 or bh, 30h 30 mov ah, 2 31 mov dl, bl 32 int 21h 33 mov dl, bh 34 int 21h 35 ret 36 37 printSpace:mov ah, 2 38 mov dl, ' ' 39 int 21h 40 ret 41 42 code ends 43 end start
在debug中調試截圖如下:
實驗任務4:
task4.asm代碼編寫如下:
1 assume ds:data, cs:code 2 data segment 3 str db 'try' 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov cx, len 12 mov si, offset str 13 mov ax, 0b800h 14 mov es, ax 15 mov di, 0 16 mov ah, 2 17 18 s: call printStr 19 inc si 20 add di, 2 21 loop s 22 23 mov di, 3840 24 mov si, offset str 25 mov cx, len 26 mov ah, 4 27 28 s1: call printStr 29 inc si 30 add di, 2 31 loop s1 32 33 mov ax, 4c00h 34 int 21h 35 36 printStr:mov al, [si] 37 mov es:[di], al 38 mov es:[di+1], ah 39 ret 40 41 code ends 42 end start
在debug中運行截圖如下:
實驗任務5:
task5.asm代碼如下:
1 assume ds:data, cs:code 2 data segment 3 stu_no db '201983290205' 4 len = $ - stu_no 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov cx, 4000 12 mov si, offset stu_no 13 mov ax, 0b800h 14 mov es, ax 15 mov di, 0 16 mov ah,17h 17 18 s: mov al, 0 19 mov es:[di], al 20 mov es:[di+1], ah 21 inc si 22 add di, 2 23 loop s 24 25 mov di, 3840 26 mov si, offset stu_no 27 mov cx, 74 28 mov ah, 17h 29 s1: call printgang 30 add di, 2 31 loop s1 32 33 mov di, 3908 34 mov si, offset stu_no 35 mov cx, len 36 mov ah, 17h 37 s2: call printStu_no 38 inc si 39 add di, 2 40 loop s2 41 42 mov di, 3932 43 mov si, offset stu_no 44 mov cx, 74 45 mov ah, 17h 46 s3: call printgang 47 add di, 2 48 loop s3 49 50 mov ax, 4c00h 51 int 21h 52 53 printStu_no:mov al, [si] 54 mov es:[di], al 55 mov es:[di+1], ah 56 ret 57 58 printgang:mov al, 45 59 mov es:[di], al 60 mov es:[di + 1], ah 61 ret 62 63 code ends 64 end start
在debug中運行截圖如下:
四.實驗總結
經過本次上機實驗,我學習並理解了轉移指令的跳轉原理,了解了Loop指令的機器碼的含義以及如何計算跳轉地址,學會了如何使用call和ret編寫子程序並運用,學習了彩色字符是如何打印在屏幕上的,以及它們的屬性字節中8個數字分別代表的含義,希望在以后能更深入地學習這方面。