1. 预备知识
首先介绍用 7ch 中断例程完成 loop 指令的循环功能。loop 的执行需要用到两个信息,循环次数和到标号的转移位移。如循环代码:
mov ax,1
mov cx,4
s:
add ax,ax
loop s
上述 loop s 指令的具体功能是:执行到 loop s 时,寄存器 CX 的值减一,如果为零则跳出循环执行后续程序;如果不为零,则 CS:IP 的值设置为标号 s 的地址继续执行循环体。在程序执行过程中,CS:IP 的值共设置 (cx) 次。
对于 int 7ch 中断例程,中断向量表的第 7ch 个表项为对应中断处理程序的入口地址。由 实验12 的内容,得到安装程序:
assume cs:code
code segment
start:
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset lp
mov cx,offset lpend-offset lp ;待安装程序的长度
cld ;设置传输方向为正
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h ;低地址写入偏移地址
mov word ptr es:[7ch*4+2],0 ;高地址写入段地址
mov ax,4c00h
int 21h
lp:
;待完成的中断处理程序
lpend:
nop
code ends
end start
如在屏幕中间显示 80 个绿色 ! 的字符的程序。首先,循环次数存放在寄存器 CX 中;对于转移位移,通过两标号间的位移得到,存放在寄存器 BX 中。得到调用代码:
assume cs:code
code segment
start:
mov ax,0b800h
mov es,ax ;段寄存器ES指向显示区域
mov di,160*12 ;变址寄存器DI指向显示区域的中部
mov bx,offset s-offset se ;设置从标号se到标号s的转移位移
mov cx,80 ;存放循环次数
s:
mov byte ptr es:[di],'!' ;将'!'写入显示缓冲区
mov byte ptr es:[di+1],2h ;字体颜色为绿色
add di,2 ;每次偏移两个字节
int 7ch ;调用7ch中断例程
se:
mov ax,4c00h
int 21h
code ends
end start
int 7ch 引用中断后,进入 7ch 中断例程。在中断过程中,当前的标志寄存器、CS、IP 都要入栈。此时,入栈的 CS:IP为调用程序的地址,即标号 s 的段地址为 CS、编号 se 的偏移地址为 IP。
又前面寄存器 BX 存放了标号 se 到标号 s 的转移位移,所以标号 s 的偏移地址等于 (bx) 加上标号 se 的偏移地址。以此,将 CS:IP 的内容设置为标号 s 的段地址和偏移地址即可实现跳转。
寄存器 BP 称为指针寄存器,和段寄存器 SS 配合使用访问栈中数据。由于在中断处理程序中后续会使用寄存器 BP,首先将其入栈。现考虑栈中的数据存放情况,首先栈顶是 se 的偏移地址,然后是 s 的段地址,然后是标志寄存器。
栈顶偏移地址存放在 SP 中,从栈顶往下数第二个为 se 的偏移地址,所以 se 的偏移地址可表示为 (sp)+2,即标号 s 的偏移地址可表示为 ss:((sp)+2)+(bx)。此时,栈中 se 的偏移地址变为 s 的偏移地址。后续执行 iret 恢复现场后,CS:IP 自动指向标号 s 的地址。则中断处理程序为:
lp:
push bp
mov bp,sp
dec cx
jcxz lpret ;如果(cx)等于0,则跳转到lpret,此时IP内容不变,执行标号se的代码
add [bp+2],bx ;否则,栈中se的偏移地址变为s的偏移地址,IP内容改变,执行标号s的代码
lpret:
pop bp
iret
得到 int7ch 的安装程序如下:
assume cs:code
code segment
start:
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset lp
mov cx,offset lpend-offset lp
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0h
mov ax,4c00h
int 21h
lp:
push bp
mov bp,sp
dec cx ;寄存器CX中存放着循环次数
jcxz lpret
add [bp+2],bx
lpret:
pop bp
iret
lpend:
nop
code ends
end start
安装结果如下:
中断向量表的设置情况如下:
调用结果如下:
2. 检测点 13.1
(1)在预备知识中,用 7ch 中断例程实现 loop 的功能,则上述 7ch 中断例程所能进行的最大转移位移是多少?
- 上述中断例程进行的位移存放在寄存器 BX 内:
mov bx,offset s-offset se
寄存器 BX 为 16 位寄存器,所表示的最大转移位移为 -32768~32767。
(2)用 7ch 中断例程完成 jmp near ptr s 指令的功能,用 bx 向中断例程传送转移位移。应用举例:在屏幕的第 12 行显式 data 段中,以 0 结尾的字符串。
assume cs:code
data segment
db 'conversation',0
data ends
code segment
start:
mov ax,data
mov ds,ax ;段寄存器DS指向data段
mov si,0
mov ax,0b800h
mov es,ax ;段寄存器ES指向显示区域
mov di,160*12
s:
cmp byte ptr [si],0
je ok ;如果上述比较等于零则跳转到标号ok处
mov al,[si]
mov byte ptr es:[di],al ;写入字符串内容
mov byte ptr es:[di+1],2h ;给字符加上绿色属性
inc si ;偏移1个字节从字符串取字符
add di,2 ;偏移2个字节得到下一个写入地址
mov bx,offset s-offset ok ;转移位移
int 7ch
ok:
mov ax,4c00h
int 21h
code ends
end start
- jmp near ptr s 实现段内近转移,段寄存器内容不变、(IP)=(IP)+16 位位移,相当于预备知识中的一次循环操作。
- 由预备知识的内容,由于在中断处理程序中后续会使用寄存器 BP,首先将其入栈。现考虑栈中的数据存放情况,首先栈顶是 ok 的偏移地址,然后是 s 的段地址,然后是标志寄存器。
- 栈顶偏移地址存放在 SP 中,从栈顶往下数第二个为 ok 的偏移地址,所以 ok 的偏移地址可表示为 (sp)+2,即标号 s 的偏移地址可表示为 ss:((sp)+2)+(bx)。此时,栈中 ok 的偏移地址变为 s 的偏移地址。后续执行 iret 恢复现场后,CS:IP 自动指向标号 s 的地址,完成段内短转移。
综上,程序安装部分和中断处理程序部分为:
assume cs:code
code segment
start:
mov ax,0
mov es,ax
mov di,200h
mov ax,cs
mov ds,ax
mov si,offset lp
mov cx,offset lpend-offset lp
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[7ch*4],200h
mov word ptr es:[7ch*4+2],0h
mov ax,4c00h
int 21h
lp:
push bp
mov bp,sp
add [bp+2],bx ;将IP的内容设置为标号s的偏移地址
pop bp
iret
lpend:
nop
code ends
end start
安装结果如下:
中断向量表的设置情况如下:
调用结果如下:
3. 检测点 13.2
判断下面说法的正误:
(1)我们可以编程改变 FFFF:0 处的指令,使得 CPU 不去执行 BIOS 中的硬件系统检测和初始化程序。
FFFF:0 处的指令为一条跳转指令:
使用 a 指令向 FFFF:0000 写入一条 mov 指令:
再次查看 FFFF:0 处的指令:
由图可知,该内存处的指令没有改变,表明该指令是一条可读指令,不可编程写入。
(2)int 19h 中断例程,可以由 DOS 提供。
BIOS 和 DOS 提供的中断例程的安装过程:
- 开机后,CPU 一加电,初始化 CS:IP=FFFF:0000,跳转执行 BIOS 中的硬件系统检测和初始化程序
- 将 BIOS 提供的中断例程的入口地址装入中断向量表
- 硬件系统检测和初始化完成后,调用 int 19h 进行操作系统引导,操作系统接收计算机控制权
- DOS 启动后,除完成其他工作外,还将它的中断例程装入内存,而 BIOS 的中断例程常驻内存
所以,int19h 不是由 DOS 提供的,因为在 DOS 装入中断例程前 int19h 已存在于内存中。
4. 总结
- 本文首先介绍了基于 int 7ch 中断实现循环指令的功能,并将其应用于在屏幕显式字符。
- 然后介绍基于 int 7ch 中断实现 jmp near ptr s 的功能,类似于一次循环的执行。
- 最后介绍了,BIOS 和 DOS 提供的中断例程的相关内容。