1. 程式人生 > 其它 >【實驗三】轉移指令跳轉原理及其簡單應用程式設計

【實驗三】轉移指令跳轉原理及其簡單應用程式設計

目錄

任務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=字元值
返回值: 無

  1. 理解運算子offset、偽指令equ、預定義符號$的靈活使用。通過line4、line6,以及資料項的資料屬性(位元組、字、雙字,等),可以方便計算出連續資料項的個數,而無需人工計數。
    注*: 符號常量len1, len2不佔用資料段記憶體空間

  2. 回答問題

    ① 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

執行結果: