实验3 转移指令跳转原理及其简单应用编程
一、实验目的
1. 理解和掌握转移指令的跳转原理
2. 掌握使用call和ret指令实现子程序的方法,理解和掌握其参数传递方式
3. 理解和掌握80×25彩色字符模式显示原理
4. 综合应用寻址方式和汇编指令完成简单应用编程
二、实验准备
复习教材9-10章: 转移指令的跳转原理 汇编指令jmp, loop, jcxz, call, ret, retf的用法
三、实验内容
实验任务1:
task1.asm代码如下:
1 assume cs:code, ds:data 2 3 data segment 4 x db 1, 9, 3 5 len1 equ $ - x 6 7 y dw 1, 9, 3 8 len2 equ $ - y 9 data ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov si, offset x 17 mov cx, len1 18 mov ah, 2 19 s1:mov dl, [si] 20 or dl, 30h 21 int 21h 22 23 mov dl, ' ' 24 int 21h 25 26 inc si 27 loop s1 28 29 mov ah, 2 30 mov dl, 0ah 31 int 21h 32 33 mov si, offset y 34 mov cx, len2/2 35 mov ah, 2 36 s2:mov dx, [si] 37 or dl, 30h 38 int 21h 39 40 mov dl, ' ' 41 int 21h 42 43 add si, 2 44 loop s2 45 46 mov ah, 4ch 47 int 21h 48 code ends 49 end start
问题1:程序反汇编截图如下:
可以看到Loop处的机器码为E2F2,这里E2为Loop,而F2的含义是偏移量的补码形式,我们将F2的2进制(11110010)求补后得10001110,即10进制中的-14,代表向前偏移14个字节,而我们用Loop指令的偏移地址与s1的偏移地址相减时发现偏移量为-12,所以并非从Loop指令处计算,而是从它的下一个指令所在的偏移地址计算,在本题中是001B,用001B和000D相减,可以得到偏移量为-14。CPU应该是先取Loop指令的下一条指令的偏移地址,然后从Loop指令的机器码后两位中获得偏移量的补码形式,再求补得到偏移量,然后用下一条指令的偏移地址与偏移量相减得到跳转位置的偏移地址000D。
问题2:程序反汇编截图如下:
可以看到Loop处的机器码为E2F0,同问题1,由F0(11110000)求补得到10010000,即十进制中的-16,代表向前偏移16个字节,而此时CPU也是从Loop指令的下一条指令的偏移地址0039开始计算,将它与16相减,获得s2处的偏移地址0029。
实验任务2:
task2.asm源代码如下:
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
问题1:从理论上看:
(1)call word ptr将下一条指令的偏移地址压入栈,再跳转到相应地址执行命令
(2)call dword ptr 先将下一条指令的段地址压入栈,再将下一条指令的偏移地址压入栈,再跳转到相应地址执行命令。
(3)本题ds:[0]中存放的是s1的偏移地址,ds:[2]中存放的是s2的偏移地址,所以第一个call指令先将s1的偏移地址压入栈,在跳转到s1处执行pop ax,即将s1的偏移地址0021出栈并存放到ax。
(4)第二个call指令先将s2处的偏移地址压入栈,再将s2处的段地址压入栈,再跳转到ds:[2]即s2处执行pop bx,即将s2的偏移地址0026出栈并存放到bx,再执行pop cx,即将s2的段地址076C出栈并存放到cx中。
综上可得程序执行到line31之前,ax=0021,bx=0026,cx=076C
问题2:在debug中验证,反汇编截图如下:
执行到line31之前:
可以看到ax=0021,bx=0026,cx=076C,验证正确。
实验任务3:
task3.asm代码编写如下:
1 assume ds:data, cs:code 2 data segment 3 x db 99, 72, 85, 63, 89, 97, 55 4 len equ $- x 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov cx, len 13 mov byte ptr ds:[10], 10 14 15 s1: mov ah, 0 16 mov al, ds:[si] 17 18 div byte ptr ds:[10] 19 call printNumber 20 call printSpace 21 inc si 22 loop s1 23 24 mov ax, 4c00h 25 int 21h 26 27 printNumber:mov bx, ax 28 or bl, 30h 29 or bh, 30h 30 mov ah, 2 31 mov dl, bl 32 int 21h 33 mov dl, bh 34 int 21h 35 ret 36 37 printSpace:mov ah, 2 38 mov dl, ' ' 39 int 21h 40 ret 41 42 code ends 43 end start
在debug中调试截图如下:
实验任务4:
task4.asm代码编写如下:
1 assume ds:data, cs:code 2 data segment 3 str db 'try' 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov cx, len 12 mov si, offset str 13 mov ax, 0b800h 14 mov es, ax 15 mov di, 0 16 mov ah, 2 17 18 s: call printStr 19 inc si 20 add di, 2 21 loop s 22 23 mov di, 3840 24 mov si, offset str 25 mov cx, len 26 mov ah, 4 27 28 s1: call printStr 29 inc si 30 add di, 2 31 loop s1 32 33 mov ax, 4c00h 34 int 21h 35 36 printStr:mov al, [si] 37 mov es:[di], al 38 mov es:[di+1], ah 39 ret 40 41 code ends 42 end start
在debug中运行截图如下:
实验任务5:
task5.asm代码如下:
1 assume ds:data, cs:code 2 data segment 3 stu_no db '201983290205' 4 len = $ - stu_no 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov cx, 4000 12 mov si, offset stu_no 13 mov ax, 0b800h 14 mov es, ax 15 mov di, 0 16 mov ah,17h 17 18 s: mov al, 0 19 mov es:[di], al 20 mov es:[di+1], ah 21 inc si 22 add di, 2 23 loop s 24 25 mov di, 3840 26 mov si, offset stu_no 27 mov cx, 74 28 mov ah, 17h 29 s1: call printgang 30 add di, 2 31 loop s1 32 33 mov di, 3908 34 mov si, offset stu_no 35 mov cx, len 36 mov ah, 17h 37 s2: call printStu_no 38 inc si 39 add di, 2 40 loop s2 41 42 mov di, 3932 43 mov si, offset stu_no 44 mov cx, 74 45 mov ah, 17h 46 s3: call printgang 47 add di, 2 48 loop s3 49 50 mov ax, 4c00h 51 int 21h 52 53 printStu_no:mov al, [si] 54 mov es:[di], al 55 mov es:[di+1], ah 56 ret 57 58 printgang:mov al, 45 59 mov es:[di], al 60 mov es:[di + 1], ah 61 ret 62 63 code ends 64 end start
在debug中运行截图如下:
四.实验总结
经过本次上机实验,我学习并理解了转移指令的跳转原理,了解了Loop指令的机器码的含义以及如何计算跳转地址,学会了如何使用call和ret编写子程序并运用,学习了彩色字符是如何打印在屏幕上的,以及它们的属性字节中8个数字分别代表的含义,希望在以后能更深入地学习这方面。