實驗3 轉移指令跳轉原理及其簡單應用編程


實驗任務一

代碼:

 1 assume cs:code, ds:data
 2 data segment
 3 x db 1, 9, 3
 4 len1 equ $ - x ; 符號常量, $指下一個數據項的偏移地址,這個示例中,是3
 5 y dw 1, 9, 3
 6 len2 equ $ - y ; 符號常量, $指下一個數據項的偏移地址,這個示例中,是9
 7 data ends
 8 code segment
 9 start:
10 mov ax, data
11 mov ds, ax
12 mov si, offset x ; 取符號x對應的偏移地址0 -> si
13 mov cx, len1 ; 從符號x開始的連續字節數據項個數 -> cx
14 mov ah, 2
15 s1:mov dl, [si]
16 or dl, 30h
17 int 21h
18 mov dl, ' '
19 int 21h ; 輸出空格
20 inc si
21 loop s1
22 mov ah, 2
23 mov dl, 0ah
24 int 21h ; 換行
25 mov si, offset y ; 取符號y對應的偏移地址3 -> si
26 mov cx, len2/2 ; 從符號y開始的連續字數據項個數 -> cx
27 mov ah, 2
28 s2:mov dx, [si]
29 or dl, 30h
30 int 21h
31 mov dl, ' '
32 int 21h ; 輸出空格
33 add si, 2
34 loop s2
35 mov ah, 4ch
36 int 21h
37 code ends
38 end start

1. 理解運算符offset、偽指令equ、預定義符號$的靈活使用。

答:

運行結果如下:

offset的作用是取得標號的偏移地址。如本題定義一個數組x含有三個元素,則通過offset x可以取得x的起始地址,也就是0.

len1 equ相當於定義一個常量,常量名為equ,對應偏移地址為$-x相當於對應x最后一個元素的偏移量,也就是3.

2. 回答問題

① line27, 匯編指令 loop s1 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼, 分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得 到跳轉后標號s1其后指令的偏移地址的。

答:反匯編結果如下

 跳轉的位移量是1B-D=E=14

CPU首先取得目前正在執行的指令的地址加上本條指令所占用空間的地址,也就是001B,然后減去標號的地址000D得到結果E,然后向前移動E個單位。

 

② line44,匯編指令 loop s2 跳轉時,是根據位移量跳轉的。通過debug反匯編,查看其機器碼, 分析其跳轉的位移量是多少?(位移量數值以十進制數值回答)從CPU的角度,說明是如何計算得 到跳轉后標號s2其后指令的偏移地址的。

答:反匯編結果如下。

 跳轉的位移量是39-29=10=16

CPU首先取得目前正在執行的指令的地址加上本條指令所占用空間的地址,也就是0039,然后減去標號的地址0029得到結果10h,然后向前移動10h個單位。

 

③ 附上上述分析時,在debug中進行調試觀察的反匯編截圖

 

實驗任務二

 代碼:

 1 assume cs:code, ds:data
 2 data segment
 3 dw 200h, 0h, 230h, 0h
 4 data ends
 5 stack segment
 6 db 16 dup(0)
 7 stack ends
 8 code segment
 9 start:
10 mov ax, data
11 mov ds, ax
12 mov word ptr ds:[0], offset s1
13 mov word ptr ds:[2], offset s2
14 mov ds:[4], cs
15 mov ax, stack
16 mov ss, ax
17 mov sp, 16
18 call word ptr ds:[0]
19 s1: pop ax
20 call dword ptr ds:[2]
21 s2: pop bx
22 pop cx
23 mov ah, 4ch
24 int 21h
25 code ends

① 根據call指令的跳轉原理,先從理論上分析,程序執行到退出(line31)之前,寄存器(ax) = ? 寄存器 (bx) = ? 寄存器(cx) = ?

答:ax中值應該是s1的偏移地址,bx中值應該是s2的偏移地址,cx中值應該是cs存儲的地址。

首先ds:[0]指向的地址應該是s1的偏移地址,則call word ptr ds:[0]就是跳轉到ds:[0]指向的地址執行,並且將當前IP壓入棧中,當前的IP正好也是s1的偏移地址,所以ax對應s1指令的偏移地址。

bx是call dword ptr,所以會把cs和IP都壓入棧中,之后同理,因為下一條就是s2,執行pop bx會把s2的地址出棧,存儲給bx。

對於cx,由於棧中執行的操作是三次進棧,兩次出棧操作,所以棧中還存儲有cs的地址,出棧后cx對應棧中的地址。

 

② 對源程序進行匯編、鏈接,得到可執行程序task2.exe。使用debug調試,觀察、驗證調試結果與理論 分析結果是否一致。

 

 

 

實驗任務三

要求: 編寫子程序printNumber

功能:以十進制形式輸出一個兩位數

入口參數:寄存器ax(待輸出的數據 --> ax)

出口參數:無 編寫子程序

printSpace 功能:打印一個空格

入口參數:無

出口參數:無

在主體代碼中,綜合應用尋址方式和循環,調用printNumber和printSpace, 實現題目要求。

 

代碼:

 1 assume ds:data, cs:code
 2 
 3 data segment
 4     x db 99, 72, 85, 63, 89, 97, 55
 5     len equ $- x
 6 data ends
 7 
 8 code segment
 9 start:
10     mov ax,data
11     mov ds,ax
12     mov si,0
13     mov cx,len;cx中存儲定義的字的個數,這也是循環會執行的次數
14     s:  call printNumber;打印一個兩位數
15     call printSpace;打印一個空格
16     inc si
17     loop s
18 
19     mov ax,4c00h
20     int 21h
21 
22     printNumber:
23     mov ah, 0
24     mov al, [si]
25         mov bl, 10
26     div bl
27     mov bl,al
28     mov bh,ah
29 
30     mov ah,2
31     mov dl,bl
32     add dl,30h
33     int 21h
34 
35     mov ah,2
36     mov dl,bh
37     add dl,30h
38     int 21h
39     ret
40 
41 
42     printSpace:
43     mov ah,2
44     mov dl,' '
45     int 21h
46     ret
47 code ends
48 end start

效果:

 

 

實驗任務四

要求: 編寫子程序printStr

功能:

在指定行、以指定顏色,在屏幕上顯示字符串

入口參數

字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏 移地址—> si)

字符串長度 --> cx

字符串顏色 --> bl

指定行 --> bh (取值:0 ~24)

出口參數:無

 

代碼:

 1 assume ds:data, cs:code
 2 
 3 data segment
 4 str db 'try'
 5 len equ $ - str
 6 data ends
 7 
 8 code segment
 9 start:
10     mov ax,data
11     mov ds,ax
12 
13     mov si,0
14     mov cx,len;字符串長度為len賦值給cx
15     mov bh,0
16     mov bl,00000010B;對應綠色
17     call printStr
18     
19     mov si,0
20     mov cx,len;字符串長度為len賦值給cx
21     mov bh,24
22     mov bl,00000100B;對應紅色
23     call printStr
24 
25     mov ax,4c00h
26     int 21h
27     
28 
29     printStr:
30     mov ax,0b800h;設置ax為顯存段地址
31     mov es,ax
32 
33     mov al,bh
34     mov bh,0a0h
35     mul bh
36     mov bp,ax
37     s:
38     mov ah,ds:[si];每次取出一個字節給ah
39     mov es:[bp],ah;把字母存給顯存地址低八位中
40     inc bp
41     mov es:[bp],bl;將顏色信息存入高八位
42     inc bp
43     inc si
44     loop s
45     ret
46 
47 code ends
48 end start

效果:

 

 

實驗任務五

代碼:

 1 assume ds:data, cs:code
 2 
 3 data segment
 4 stu_no db '20498329042'
 5 len = $ - stu_no
 6 data ends
 7 
 8 code segment
 9 start:
10     mov ax,0b800h
11     mov es,ax
12     mov bp,1
13     mov cx,8000h
14 
15     first:
16     mov byte ptr es:[bp],00011111B
17     add bp,2
18     loop first
19 
20     mov ax,data
21     mov ds,ax;ds作數據段
22     mov ax,0050h;一行的長度
23     sub ax,len;減去學號的長度
24     mov bh,02h;除以二得到橫線的長度
25     div bh
26     mov bl,al;商賦給bx,后面要用
27     mov bh,0
28 
29     mov ax,0b800h;顯存地址存給es
30     mov es,ax
31     mov bp,0F00h;首字母偏移量賦給bp
32     mov cx,bx
33 
34     s:
35     mov byte ptr es:[bp],'-'
36     inc bp
37     inc bp
38     loop s;打印橫杠
39 
40     mov cx,len
41     mov di,0
42 
43     s1:
44     mov al,ds:[di]
45     mov es:[bp],al
46     inc bp
47     inc bp
48     inc di
49     loop s1;打印學號
50 
51     mov cx,bx
52 
53     s2:
54     mov byte ptr es:[bp],'-'
55     inc bp
56     inc bp
57     loop  s2;打印橫杠
58 
59     mov ax,4c00h
60     int 21h
61 
62 code ends
63 end start

效果:

 

實驗總結:

本次實驗主要考察了兩部分的內容,一部分是對跳轉指令的理解和應用,另一部分是對顯存數據寫入的理解和應用。

首先實驗使用了equ指令定義常量len,這個常量因為是定義字符的下一個地址,字符的開始地址是從0開始的,所以就可以得到字符的長度。

CPU執行跳轉操作的時候,不是直接根據所給的地址進行跳轉,而是根據下一條指令的偏移量和給出的目標地址進行計算得到位移量進行回退的。執行call命令的時候需要利用棧來存儲跳躍前的指令的地址,這樣在執行ret的時候就可以快速跳轉回去,所以在此期間也不可以對棧段和棧偏移地址寄存器進行修改。offset指令通過獲得某個定義的代碼塊的偏移地址來達成和call類似的效果。

將字符顯示在屏幕上有兩種方法,第一種是通過int21h的二號指令,將想要打印的數傳給al來實現,因為會打印ASCII碼,所以對於打印數字來說需要進行一次or 30h或add 30h的運算,才可以將數字轉換成對應的碼值。

寫入顯存的時候需要知道顯存一行所占的字節數,顯存地址從0b800h開始,偏移000-09F對應第一行,總計24行以此類推。對於每一個字來說,低位存儲了想要打印的數字或字符,高位決定了數字的前景色和背景色,前四位決定背景色和高亮,后四位決定前景色和高亮,因此在顯存中打印字符的時候需要一次跳兩位。如果想像本題最后一題那樣把整個屏幕都變藍,我采取的方法是在開始的時候就把藍色背景色對應數字存入每一個單數的數字位中(高位),這樣整個屏幕就變藍了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM