编写并安装int 7ch中断例程,功能为完成loop指令的功能。
参数:(cx)=循环次数,(bx)=位移。
以上中断例程安装成功后,对下面的程序进行单步跟踪,尤其注意观察int、iret指令执行前后CS、IP和栈中的状态。
在屏幕中间显示80个“!”。
应用程序代码(命名为“
show!.asm
”):
assume cs:code
code segment
start:mov ax,0b800h
mov es,ax
mov di,160*12
mov bx,offset s - offset se
mov cx,80
s:mov byte ptr es:[di],'!'
add di,2
int 7ch
se:nop
mov ax,4c00h
int 21h
code ends
end start
安装程序代码(命名为“
install.asm
”):
assume cs:code
code segment
start:mov ax,cs
mov ds,ax
mov si,offset lp
mov ax,0
mov es,ax
mov di,200h
mov cx,offset lpend - offset lp
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[4*7ch],200h
mov word ptr es:[4*7ch+2],0
mov ax,4c00h
int 21h
lp:
push bp
mov bp,sp
dec cx
jcxz lpret
add [bp+2],bx ;红色部分模拟了loop指令的功能
lpret:pop bp
iret
lpend:nop ;lp和lpend之间的红色代码并不执行,而是作为数据安装到0:200h及其之后的地址中。以响应int 7ch指令 引发的中断。
code ends
end start
Windows中,cmd命令进入虚拟8086模式的DOS,利用masm和link对以上两个代码编译连接生成各自的exe程序。
首先,输入debug install.exe命令,debug程序将install载入内存地址单元中,CS:IP指向start处。此时,输入d 0000:01f0 01f3查看到的数值为:00 00 00 00,这里是中断类型码7ch号对应的中断向量列表中的位置,0000:01f0中存储的是中断处理程序IP的值,0000:01f2中存储的是其CS的值:
用u命令查看debug中显示的代码
及其对应的内存单元地址。
如下图示:
现跟踪调试,而不是用t命令进行单步跟踪,输入命令:g 001a,从CS:IP开始指向的0ba0:0000处开始执行,一直到0ba0:001a为止。
此处debug中显示的代码为mov prt word [01F0],0200,右下角显示DS:01F0=0200,此处意为继续执行此处代码后,传送到在内存地址ds:[01f0]中的数据为0200,段寄存器竟然为DS。可是,源代码为mov word ptr es:[4*7ch],200h,在0BA0:0014和0BA0:0017地址处的代码(也就是前两行代码)设置了段寄存器为ES,已经非常明确段寄存器为ES了,这里的g命令为什么忽略它的存在而“自作主张”地设置在
DS中呢?应用程序执行的最终结果是引起不在意料之中的错误中断例程!奇怪啊。。哪位高手看到了这个问题,请指示!!
接着t命令继续执行,这时出现了正常的ES:0IF2=0000。如下图:
然后,d 0000:01f0 01f3 查看其中的数值是否为00 02 00 00,可是仍然还是00 00 00 00
而此时继续输入d 0000:01f0 01f1命令查看前一句代码: mov word ptr es:[4*7ch],200h是否正确执行了,结果却是正确的,es:[4*7ch]地址中的数值是预想中的0200。 如下图:
注:以上提到的问题,是给中断处理程序设置中断向量列表的,也就是把中断处理程序第一行代码所在的0:200h地址登记到中断类型码7c号中,其内存字单元地址为0:4*7ch和0:4*7ch+2,分别存储的是中断处理的偏移地址IP和段地址CS。