【實驗三】轉移指令跳轉原理及其簡單應用程式設計
任務1
task1.asm
assume cs:code, ds:data data segment x db 1, 9, 3 len1 equ $ - x ; 符號常量, $指下一個資料項的偏移地址,這個示例中,是3 y dw 1, 9, 3 len2 equ $ - y ; 符號常量, $指下一個資料項的偏移地址,這個示例中,是9 data ends code segment start: mov ax, data mov ds, ax mov si, offset x ; 取符號x對應的偏移地址0 -> si mov cx, len1 ; 從符號x開始的連續位元組資料項個數 -> cx mov ah, 2 s1: mov dl, [si] or dl, 30h ; 數值轉為字元 int 21h mov dl, ' ' int 21h ; 輸出空格 inc si loop s1 mov ah, 2 mov dl, 0ah int 21h ; 換行 mov si, offset y ; 取符號y對應的偏移地址3 -> si mov cx, len2/2 ; 從符號y開始的連續字資料項個數 -> cx mov ah, 2 s2: mov dx, [si] or dl, 30h int 21h mov dl, ' ' int 21h ; 輸出空格 add si, 2 loop s2 mov ah, 4ch int 21h code ends end start
int 21h
功能2:在標準輸出上顯示一個字元並將游標前進一個位置。
接收引數:AH=2
DL=字元值
返回值: 無
-
理解運算子offset、偽指令equ、預定義符號$的靈活使用。通過line4、line6,以及資料項的資料屬性(位元組、字、雙字,等),可以方便計算出連續資料項的個數,而無需人工計數。
注*: 符號常量len1, len2不佔用資料段記憶體空間 -
回答問題
① line26, 彙編指令 loop s1 跳轉時,是根據位移量跳轉的。通過debug反彙編,檢視其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進位制數值回答)從CPU的角度,說明是如何計算得到跳轉後標號s1其後指令的偏移地址的。
E2F2
中 位移量: F2(h) --> 11110010(b) --> 00001110(b) --> -12(d) (補碼-->原碼)
位移量的計算: d(h) - 19(h) --> -12(d)
CPU根據目標偏移地址減去當前偏移地址得到位移量② line44,彙編指令 loop s2 跳轉時,是根據位移量跳轉的。通過debug反彙編,檢視其機器碼,分析其跳轉的位移量是多少?(位移量數值以十進位制數值回答)從CPU的角度,說明是如何計算得到跳轉後標號s2其後指令的偏移地址的。
分析同上, 跳轉的位移量為 FO(h).
任務2
task2.asm
assume cs:code, ds:data data segment dw 200h, 0h, 230h, 0h data ends stack segment db 16 dup(0) stack ends code segment start: mov ax, data mov ds, ax mov word ptr ds:[0], offset s1 mov word ptr ds:[2], offset s2 mov ds:[4], cs mov ax, stack mov ss, ax mov sp, 16 call word ptr ds:[0] s1: pop ax call dword ptr ds:[2] s2: pop bx pop cx mov ah, 4ch int 21h code ends end start
根據call指令的跳轉原理,先從理論上分析,程式執行到退出(line31)之前,暫存器(ax) = ? 暫存器(bx) = ? 暫存器(cx) = ?
分析:
call word ptr ds:[0] 短轉移, 將下一條指令偏移地址(ip)壓入棧, 並轉移至 ds:[0]地址即 s1 處, 此後的 pop ax 將該內容出棧給ax;
call dword ptr ds:[2] 段間轉移, 將下一條指令基址和偏移地址(cs 和 ip)壓入棧, 並轉移至 ds:[2] 起始的雙字指向的地址即 s2 處, 此後的 pop bx 將ip出棧給ax, pop cx 將 cs 出棧給 cx.
即:
ax = s1 bx = s2 cx = s2行所在段基址
任務3
針對8086CPU,已知邏輯段定義如下:
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
編寫8086彙編源程式task3.asm,在螢幕上以十進位制形式輸出data段中這一組連續的資料,資料和資料之間以空格間隔。
要求:
- 編寫子程式printNumber
功能:以十進位制形式輸出一個兩位數
入口引數:暫存器ax(待輸出的資料 --> ax)
出口引數:無 - 編寫子程式printSpace
功能:列印一個空格
入口引數:無
出口引數:無
在主體程式碼中,綜合應用定址方式和迴圈,呼叫printNumber和printSpace, 實現題目要求。
task3.asm
assume cs:code, ds:data
data segment
x db 99, 72, 85, 63, 89, 97, 55
len equ $- x
data ends
code segment
main:
mov ax, data
mov ds, ax
mov cx, len
mov si, offset x
print:
mov al, [si]
mov ah, 0
call printNumber
call printSpace
inc si
loop print
mov ah, 4ch
int 21h
;功能:以十進位制形式輸出一個兩位數
;入口引數:暫存器ax(待輸出的資料 --> ax)
;出口引數:無
printNumber:
mov bl, 10
div bl
mov bx, ax
mov ah, 2
mov dl, bl ; 列印商(10位)
or dl, 30h
int 21h
mov dl, bh ; 列印餘數(個位)
or dl, 30h
int 21h
ret
printSpace:
mov ah, 2
mov dl, ' '
int 21h
ret
code ends
end main
執行結果:
任務4
針對8086CPU,已知邏輯段定義如下:
data segment
str db 'try'
len equ $ - str
data ends
編寫8086彙編源程式task4.asm,在螢幕上以指定顏色、指定行,在螢幕上輸出字串。
要求:
- 編寫子程式printStr
- 功能:在指定行、以指定顏色,在螢幕上顯示字串
- 入口引數
- 字串首字元地址 --> ds:si(其中,字串所在段的段地址—> ds, 字串起始地址的偏移地址—> si)
- 字串長度 --> cx
- 字串顏色 --> bl
- 指定行 --> bh (取值:0 ~24)
- 出口引數:無
- 在主體程式碼中,兩次呼叫printStr,使得在螢幕最上方以黑底綠字顯示字串,在螢幕最下方以黑
底紅色顯示字串
task4.asm
assume cs:code
data segment
str db 'try'
len equ $ - str
data ends
code segment
main:
mov ax, 0b800h
mov es, ax
first_print:
mov ax, data
mov ds, ax
mov si, offset str
mov cx, len
mov bl, 00000010b ; 黑底綠字
mov bh, 0 ; 第0行
call printStr
second_print:
mov si, offset str
mov cx, len
mov bl, 00000100b ; 黑底紅字
mov bh, 24 ; 第24行
call printStr
mov ah, 4ch
int 21h
; 入口引數:
; 字串首字元地址 --> ds:si(其中,字串所在段的段地址—> ds, 字串起始地址的偏移地址—> si)
; 字串長度 --> cx
; 字串顏色 --> bl
; 指定行 --> bh (取值:0 ~24)
printStr:
push bp ; 因為要用到bp和di, 先儲存現場
push di
mov ah, 0
mov al, 160
mul bh
mov bp, ax ; 計算行數偏移地址儲存在bp
mov di, si ; di儲存視訊記憶體中每個字元偏移地址
printChar:
mov al, ds:[si]
mov es:[bp+di], al ; 字元
mov es:[bp+di+1], bl ; 顏色
inc si
inc di
inc di ; di要加兩次
loop printChar
pop bp ; 還原現場
pop di
ret
code ends
end main
執行結果:
任務5
針對8086CPU,針對8086CPU,已知邏輯段定義如下:
data segment
stu_no db '20498329042'
len = $ - stu_no
data ends
在80×25彩色字元模式下,在螢幕最後一行正中間顯示學號。要求輸出視窗藍底,學號和兩側折線,以
白色前景色顯示。
task5.asm
assume cs:code, ds:data
data segment
stu_no db '201983300514'
len = $ - stu_no
data ends
code segment
main:
call print_blue_screen
call print_stu_no
mov ah, 4ch
int 21h
print_blue_screen:
push ax ; 儲存現場
push es
push si
mov ax, 0b800h
mov es, ax
mov cx, 2000
mov si, 1
single_blue:
mov byte ptr es:[si], 00010000b
inc si
inc si
loop single_blue
pop si ; 還原現場
pop es
pop ax
ret
print_stu_no:
push ax
push es
push si
push ds
push di
prefix:
mov ax, 0b800h
mov es, ax
mov cx, 34
mov si, 3840 ; si存放每次視訊記憶體輸出的偏移地址
call print_dash
content:
mov ax, data
mov ds, ax
mov cx, len
mov di, 0 ; di存放data中每個字元的偏移地址
single_no:
mov al, ds:[di]
inc di
mov byte ptr es:[si], al
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_no
postfix:
mov cx, 34
call print_dash
pop di
pop ds
pop si
pop es
pop ax
ret
; 輸入引數:
; 顯示的基地址si
; 輸出長度cx
; 輸出:
; 迭代後的基地址si
print_dash:
single_dash:
mov byte ptr es:[si], '-'
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_dash
ret
code ends
end main
執行結果: