【实验三】转移指令跳转原理及其简单应用编程

任务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=字符值
返回值: 无

image-20211123160740731

  1. 理解运算符offset、伪指令equ、预定义符号$的灵活使用。通过line4、line6,以及数据项的数据属性(字节、字、双字,等),可以方便计算出连续数据项的个数,而无需人工计数。
    注*: 符号常量len1, len2不占用数据段内存空间

  2. 回答问题

    ① line26, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s1其后指令的偏移地址的。

    image-20211123161500421
    E2F2中 位移量: F2(h) --> 11110010(b) --> 00001110(b) --> -12(d) (补码-->原码)
    位移量的计算: d(h) - 19(h) --> -12(d)
    CPU根据目标偏移地址减去当前偏移地址得到位移量

    ② line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s2其后指令的偏移地址的。

    image-20211123163549842
    分析同上, 跳转的位移量为 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行所在段基址

image-20211123170907118

image-20211123170024300

任务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

运行结果:

image-20211124185325749

任务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

运行结果:

image-20211124201416292

任务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

运行结果:

image-20211124214509454

posted @ 2021-11-24 21:47  庚瘤君  阅读(195)  评论(2编辑  收藏  举报