文章目录
前言
本文是王爽老师《汇编语言》(第四版) 第十三章 检测点13.1 使用7CH中断例程实现loop指令功能与jmp near ptr s指令功能 的分析及代码。
一、7CH中断例程的安装
这个检测点的两个任务,都与7CH中断例程有关。要实现这些功能,首先需要写一个通用的7CH中断例程的安装程序。这与上一篇写过的实验12中的安装程序几乎是一样的,只不过这次用一个install子程序封装了。代码如下。
assume cs:code
code segment
start: ;第13章检测点13.1
call install ;安装7CH中断例程
int 7CH ;调用7CH中断例程
mov ax,4c00H
int 21H
install: ;功能:将7CH中断例程安装在0:200H处
;参数:无
;返回:无
push ax
push ds
push si
push es
push di
push cx
;将7CH中断例程(即do7c)复制到0:200H处
mov ax,cs ;设置源地址的段地址
mov ds,ax
mov si,offset do7c ;设置源地址的偏移地址
mov ax,0 ;设置目标地址的段地址
mov es,ax
mov di,200H ;设置目标地址的偏移地址
mov cx,offset do7cend - offset do7c ;设置复制长度
cld ;设置DF标志位为0,正向传送
rep movsb ;循环传送数据
;设置中断向量表
mov ax,0 ;设置ds指向7CH中断例程的段地址存储地址
mov ds,ax
mov si,7cH*4 ;设置si指向7CH中断例程的偏移地址存储地址
mov ds:[si],200H ;将7CH中断例程的偏移地址存入中断向量表
mov ds:[si+2],0 ;将7CH中断例程的段地址存入中断向量表
pop cx
pop di
pop es
pop si
pop ds
pop ax
ret
;7CH中断例程如下
do7c: ;do7c中断例程
;随便写的一段测试代码,效果是在屏幕中显示一个绿色的字符A
push ax
push es
mov ax,0B800H
mov es,ax
mov es:[2152],0241H
pop es
pop ax
iret
do7cend:nop
code ends
end start
二、编写7CH中断例程
接下来,完成两个检测点中的功能。
1.实现loop指令的功能
(1)先放上代码
assume cs:code
code segment
start: ;第13章 检测点13.1(1) 实现loop指令的功能
call install ;安装7CH中断例程
mov ax,0B800H ;设置es:di指向显存区显示地址
mov es,ax
mov di,160*12
mov bx,offset s-offset se ;bx是标号se到标号s的转移位移
mov cx,80 ;循环次数
s:
mov byte ptr es:[di],'!'
add di,2
int 7cH ;调用7CH中断例程,实现loop指令的功能
se:nop
mov ax,4c00H
int 21H
install: ;功能:将7CH中断例程安装在0:200H处
;参数:无
;返回:无
push ax
push ds
push si
push es
push di
push cx
;将7CH中断例程(即do7c)复制到0:200H处
mov ax,cs ;设置源地址的段地址
mov ds,ax
mov si,offset do7c ;设置源地址的偏移地址
mov ax,0 ;设置目标地址的段地址
mov es,ax
mov di,200H ;设置目标地址的偏移地址
mov cx,offset do7cend - offset do7c ;设置复制长度
cld ;设置DF标志位为0,正向传送
rep movsb ;循环传送数据
;设置中断向量表
mov ax,0 ;设置ds指向7CH中断例程的段地址存储地址
mov ds,ax
mov si,7cH*4 ;设置si指向7CH中断例程的偏移地址存储地址
mov ds:[si],200H ;将7CH中断例程的偏移地址存入中断向量表
mov ds:[si+2],0 ;将7CH中断例程的段地址存入中断向量表
pop cx
pop di
pop es
pop si
pop ds
pop ax
ret
;7CH中断例程如下
do7c: ;功能:loop指令
;参数:cx是循环次数
; bx是转移位移
;返回:无
;在调用中断例程前,CPU已经依次将flag、cs、ip压入栈
push bp ;这个中断例程中用到bp,压入栈暂存
mov bp,sp ;
dec cx ;实现cx-1的功能
jcxz do7c_ok ;若cx≠0,则跳转完成循环,否则什么也不做
add [bp+2],bx ;将栈中存放的调用程序的IP,修改为转移后后的IP
do7c_ok:
pop bp
iret ;将ip、cs、flag依次pop出栈
do7cend:nop
code ends
end start
(2)接下来分析
这个中断例程中所能进行的最大转移位移,关键代码就是下面这一条。
add [bp+2],bx
[bp+2]是栈中存放的调用程序的IP,bx是调用程序传入的参数,表示转移位移。这里的bx理论上可以最大可以支持FFFFH;经过实践检验,若bx=FFFFH ,这个中断例程也可以正常运行。代码如下。
结论:这个中断例程能进行的最大转移位移是FFFFH,也就是 -32768-32767 。
do7c: ;功能:loop指令
;参数:cx是循环次数
; bx是转移位移
;返回:无
mov bx,0FFFFH ;测试bx的最大值
push bp ;这个中断例程中用到bp,压入栈暂存
mov bp,sp ;
dec cx ;实现cx-1的功能
jcxz do7c_ok ;若cx≠0,则跳转完成循环,否则什么也不做
add [bp+2],bx ;将栈中存放的调用程序的IP,修改为转移后后的IP
do7c_ok:
pop bp
iret ;将ip、cs、flag依次pop出栈
do7cend:nop
2.实现jmp near ptr s指令的功能
(1)实验任务
实验任务:用7CH中断例程完成jmp near ptr s指令的功能,用bx向中断例程传送转移位移。
应用举例:在屏幕的第12行,显示data段中以0结尾的字符串。
代码如下。
assume cs:code
data segment
db 'conversation',0
data ends
code segment
start: ;第13章 检测点13.1(2) 实现jmp near ptr s指令的功能
call install ;安装7CH中断例程
mov ax,data ;设置ds:si指向源地址
mov ds,ax
mov si,0
mov ax,0B800H ;设置es:di指向显存目标地址
mov es,ax
mov di,160*12
s: ;循环传送每个字符
cmp byte ptr ds:[si],0
je ok
mov al,ds:[si]
mov es:[di],al
inc si
add di,2
mov bx,offset s-offset ok ;设置bx为转移位置=标号ok至标号s的转移位移
int 7CH ;功能相当于: jmp near ptr s
ok:
mov ax,4c00H
int 21H
code ends
end start
(2)实现功能
首先分析一下,jmp near ptr s实现的是近转移,转移位移不超过FFFFH,正好用16位的bx来存放。
要实现跳转,就要对栈中存储的调用程序的IP进行修改。代码如下。
do7c: ;功能:实现jmp near ptr s指令
;参数:bx是转移位移
;返回:无
;在调用中断例程前,CPU已经依次将flag、cs、ip压入栈
push bp
mov bp,sp
add ss:[bp+2],bx
pop bp
iret ;将ip、cs、flag依次pop出栈
do7cend:nop
这与第一个实验任务(实现loop指令)的中断例程很相似,只是更简单一些(不用判断cx是否等于0)。注意使用bp寄存器要push和pop,以及注意[bp+2]是栈中存放的IP的值。
效果如下。
总结
本文是王爽老师《汇编语言》(第四版) 第十三章 检测点13.1 使用7CH中断例程实现loop指令功能与jmp near ptr s指令功能 的分析及代码。