实验3 转移指令跳转原理及其简单应用编程
实验任务1
问题1.1
-
对程序进行反汇编,运行至
loop s1
处。loop s1
的机器码为E2F2。F2的八位二进制形式为11110010,补码为10001110,为-14。即位移量为14。 -
从执行角度分析:
- CS:IP指向0771:0019 ,下一条loop指令机器码E2 F2。
- E2 F2进入指令缓冲器。
- 此时CX不为零,所以执行该指令。
- $IP = IP + 所读取到的指令的长度$ ==$IP + 2 = 001B$ ,CS:IP指向
mov ah,2
- CPU执行缓冲器中指令
- 执行后IP = 000D,CS:IP指向
mov dl,[si]
。
问题1.2
-
运行至
loop s2
处。loop s2
的机器码为E2F0。F2的八位二进制形式为11110000,补码为10010000,为-16。即位移量为16。 -
与上题分析过程类似,略
实验任务2
问题2.1
call指令的跳转原理:
CPU 执行 call 指令时,进行两步操作:
- 将当前的 IP 或 CS 和 IP 压入栈中;
- 转移。
根据该原理进行分析:
- ax 应当等于其上一条指令
call word ptr ds:[0]
所压入栈中的IP,为21 - bx 应当等于其上一条指令
call dword ptr ds:[2]
所压入栈中的CS:IP中的IP,为26 - cx 应当等于
call dword ptr ds:[2]
所压入栈中的CS:IP中的CS,具体数值未知
问题2.2
使用DEBUG进行测试:
发现猜想正确。
实验任务3
代码
assume cs:code, ds:data
data segment
x db 99,72,85,63,89,97,55
len equ $-x
data ends
code segment
START:
mov ax,data
mov ds,ax
mov bl,byte ptr 10;这个除数10应该为8位的数据,故采用byte形式。
mov si,offset x
mov cx,len
dec cx
s: call printNumber
call printSpace
inc si
loop s
mov ax,4c00h
int 21
printNumber:
mov al,[si]
mov ah,0h
div bl;将al中的数除10,al中获得了商(实际上的十位数),ah中获得了余数(实际上的个位数)。
mov dh,ah;ah在中断显示中必须为2,所以先把数据放在dh中。
mov ah,2
mov dl,al
or dl,30h;将ascii转为ascii中对应的数字
int 21h;显示十位数
mov dl,dh
or dl,30h
int 21h;显示个位数
ret
printSpace:
mov ah,2
mov dl,' '
int 21h;输出一个空格
ret
code ends
end start
效果
实验任务4
代码
assume cs:code, ds:data
data segment
x db 'try'
len equ $ - x
data ends
code segment
start:
mov ax,0b800h
mov es,ax
mov ax, data
mov ds, ax
mov si,offset x
mov cx,len
mov bl,00001010b
mov bh,0;设定了首字符地址指向x,长度为len,颜色黑底绿字,指定第一行
call printStr
mov ax, data;直接初始化
mov ds, ax
mov si,offset x
mov cx,len
mov bl,00001100b
mov bh,24;设定了首字符地址指向x,长度为len,颜色黑底红字,指定第25行
call printStr;再次调用
mov ax, 4c00h
int 21h
printStr:
mov al,160
mul bh;在80*25显示模式中,屏幕上每行有160个字节,则将bh乘160即可让bh代表屏幕上第几行。
mov di,ax
s: mov al,[si]
mov es:[di],al;ascii码
mov es:[di+1],bl;这个字符的显示颜色
inc si
add di,2;转到两个字节后下一个显示字符的位置
loop s
ret
code ends
end start
效果
加强
如果将代码中 line 33 的 160 改为 1 ,则红色的 try 会显示在第一行的第 12(24/2)个字符位。
实验任务5
代码
assume cs:code, ds:data
data segment
stu_no db '201983290518'
len = $ - stu_no
data ends
code segment
start:
mov ax,data
mov ds,ax
mov ax,0b800h
mov es,ax
call printBlueScreen;先画蓝屏底子
mov di,0f00h;在最后一行的第一位开始画横线
call printLines
call printNum
call printLines
mov ax,4c00h
int 21h
printBlueScreen:
mov di,0h
mov cx,007d0h;整个屏幕可以显示2000个字符,换算成八进制就是07d。
mov al,00010000b
s: mov es:[di+1],al
add di,2
loop s
ret
printLines:
mov al,0002dh;横线的ascii码
mov ah,00011111b
mov cx,00022h;34次
s1: mov es:[di],al
mov es:[di+1],ah
add di,2
loop s1
ret
printNum:
mov cx,len
mov si,offset stu_no
mov ah,00011111b
s2: mov al,[si]
mov es:[di],al
mov es:[di+1],ah
inc si
add di,2
loop s2
ret
code ends
end start
效果
总结
-
本章实验主要复习了80*25显示模式以及常用的跳转命令。这些命令主要都是
jmp
命令的变体。 -
在80*25彩色显示模式中,每个字符占两个字节,第一个字节为ascii码,第二个字节为该字符显示在屏幕上的颜色。