实验3 转移指令跳转原理及其简单应用编程
实验任务1
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
tip:理解运算符offset、伪指令equ、预定义符号$的灵活使用。 通过line5、line8,以及数据项的数据属性(字节、字、双字,等),可以方便计算出连续数据项的个数,而无需人工计数。
注*: 符号常量len1, len2不占用数据段内存空间
问题①
① line27, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s1其后指令的偏移地址的。
跳转的位移量是14,CPU通过loop指令下一条指令的地址减去s1所在地址得到偏移地址。
问题②
② line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明 是如何计算得到跳转后标号s2其后指令的偏移地址的。
位移量是16,CPU通过loop指令下一条指令的地址减去s1所在地址得到偏移地址。
问题③
③ 附上上述分析时,在debug中进行调试观察的反汇编截图
见上述截图。
实验任务2
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
问题①
① 根据call指令的跳转原理,先从理论上分析,程序执行到退出(line31)之前,寄存器(ax) = ? 寄存器(bx) = ? 寄存器(cx) = ?
call在跳转之前,会把当前ip或者cs和ip先做入栈操作,然后再跳转。
所以,ax里是pop ax的地址,bx里是px bx的地址,cx里是cs的值。
问题②
② 对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试 结果与理论分析结果是否一致。
实验任务3
针对8086CPU,已知逻辑段定义如下:
1 data segment 2 x db 99, 72, 85, 63, 89, 97, 55 3 len equ $- x 4 data ends
编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据 之间以空格间隔。
要求:
编写子程序printNumber
功能:以十进制形式输出一个两位数
入口参数:寄存器ax(待输出的数据 --> ax)
出口参数:无
编写子程序printSpace
功能:打印一个空格
入口参数:无
出口参数:无
在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
tip:int 21h中的2号子功能说明如下
; 功能:输出单个字符
mov ah, 2
mov dl, ×× ; ××是待输出的字符,或其ASCⅡ码值
int 21h
代码如下:
1 assume cs:code, ds:data 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,ax13
12 mov bx,0
13 mov cx,len 14 mov byte ptr ds:[len],10 15 16 s: mov ax,0 17 mov al,ds:[bx] 18 call printNumber 19 call printSpace 20 inc bx 21 loop s 22 23 mov ah,4ch 24 int 21h 25 26 printNumber: 27 div byte ptr ds:[len] 28 mov dx,ax 29 or dl,30h 30 mov ah,2 31 int 21h 32 33 mov dl,dh 34 or dl,30h 35 mov ah,2 36 int 21h 37 38 ret 39 40 printSpace: 41 mov dl,' ' 42 mov ah,2 43 int 21h 44 ret 45 46 code ends 47 end start
实验任务4
针对8086CPU,已知逻辑段定义如下:
1 data segment 2 str db 'try' 3 len equ $ - str 4 data ends
编写8086汇编源程序task4.asm,在屏幕上以指定颜色、指定行,在屏幕上输出字符串。
要求:
编写子程序printStr
功能:在指定行、以指定颜色,在屏幕上显示字符串
入口参数 字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏 移地址—> si) 字符串长度 --> cx 字符串颜色 --> bl 指定行 --> bh (取值:0 ~24)
出口参数:无
在主体代码中,两次调用printStr,使得在屏幕最上方以黑底绿字显示字符串,在屏幕最下方以黑底红色显示字符串
代码如下:
1 assume cs:code, ds:data 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 15 mov bl,00000010b 16 mov bh,0 17 call printStr 18 19 mov si,0 20 mov cx,len 21 mov bl,00000100b 22 mov bh,24 23 call printStr 24 25 mov ah,4ch 26 int 21h 27 28 printStr: 29 mov ax,0b800h 30 mov es,ax 31 mov ax,0 32 mov al,bh 33 mov dx,160 34 mul dx 35 mov di,ax 36 s: mov al,ds:[si] 37 mov es:[di],al 38 inc si 39 inc di 40 mov es:[di],bl 41 inc di 42 loop s 43 ret 44 code ends 45 end start
实验任务5
针对8086CPU,针对8086CPU,已知逻辑段定义如下:
1 data segment 2 stu_no db '20498329042' 3 len = $ - stu_no 4 data ends
在80×25彩色字符模式下,在屏幕最后一行正中间显示学号。
要求输出窗口蓝底,学号和两侧折线,以 白色前景色显示。
tips:
1. 80×25彩色字符模式显示缓冲区结构,参见教材「实验9 根据材料编程」里的说明。
2. 编写程序实现时,将data段的学号换成自己的学号。
代码如下:
1 assume cs:code, ds:data 2 3 data segment 4 stu_no db '201983290075' 5 len = $ - stu_no 6 data ends 7 8 code segment 9 start: 10 mov ax,data 11 mov ds,ax 12 13 mov ax, 0b800h 14 mov es, ax 15 mov di, 0 16 mov bl, 17h 17 mov cx, 80 * 25 18 19 s1: 20 mov al, ' ' 21 mov es:[di], al 22 inc di 23 mov es:[di], bl 24 inc di 25 loop s1 26 27 mov di, 160 * 24 28 mov cx, 34 29 s2: 30 mov al, '-' 31 mov es:[di], al 32 inc di 33 mov es:[di], bl 34 inc di 35 loop s2 36 37 mov di, 160 * 24 + 34 * 2 38 mov cx, 12 39 mov si, 0 40 s3: 41 mov al, [si] 42 mov es:[di], al 43 inc di 44 mov es:[di], bl 45 inc di 46 inc si 47 loop s3 48 49 mov di, 160 * 24 + 46 * 2 50 mov cx, 34 51 s4: 52 mov al, '-' 53 mov es:[di], al 54 inc di 55 mov es:[di], bl 56 inc di 57 loop s4 58 59 mov ax, 4c00h 60 int 21h 61 code ends 62 end start