第十二章:内中断02
让编程改变世界
Change the world by program
中断处理程序
由于CPU随时都可能检测到中断信息,也就是说,CPU 随时都可能执行中断处理程序,所以中断处理程序必须一直存储在内存某段空间之中。 而中断处理程序的入口地址,即中断向量,必须存储在对应的中断向量表表项中。中断处理程序的编写方法和子程序的比较相似,下面是常规的步骤:
(1)保存用到的寄存器。 (2)处理中断。 (3)恢复用到的寄存器。 (4)用 iret 指令返回。 iret指令的功能用汇编语法描述为:pop IP
pop CS
popf
iret通常和硬件自动完成的中断过程配合使用。 可以看到,在中断过程中,寄存器入栈的顺序是标志寄存器、CS、IP ,而iret的出栈顺序是 IP、CS、标志寄存器,刚好和其对应,实现了用执行中断处理程序前的CPU现场恢复标志寄存器和CS、IP的工作。 iret指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序。除法错误中断的处理
下面的内容中,我们通过对 0号中断,即除法错误的中断处理,来体会一下前面所讲的内容。 当CPU执行div等除法指令的时候,如果发生了除法溢出错误,将产生中断类型码为 0 的中断信息,CPU将检测到这个信息,然后引发中断过程,转去执行 0 号中断所对应的中断处理程序。 实例:相关代码下载编程处理 0 号中断
现在我们考虑改变一下0号中断处理程序的功能,即重新编写一个0号中断处理程序,它的功能是在屏幕中间显示“Welcome to Fishc.com!”的 广告语,然后返回到操作系统。 演示:相关代码下载程序分析一步步:
一)、当发生除法溢出的时候,产生0号中断信息,从而引发中断过程。
此时,CPU将进行以下工作:① 取得中断类型码0;
② 标志寄存器入栈,TF、IF设置为0;
③ CS、IP入栈;
④ (IP) = (0*4),(CS) = (0*4+2)
二)、可见 ,当中断 0 发生时,CPU将转去执行中断处理程序。
只要按如下步骤编写中断处理程序,当中断0发生时,即可显示“Welcome to Fishc.com!”。① 相关处理。
② 向显示缓冲区送字符串“Welcome to Fishc.com!”。
③ 返回DOS
我们将这段程序称为do0。三)、现在的问题是:do0 应放在内存中。
因为除法溢出随时可能发生,CPU随时都可能将 CS:IP指向 do0的入口,执行程序。那么do0应该放在哪里呢?
由于我们是在操作系统之上使用计算机,所有的硬件资源都在操作系统的管理之下,所以我们要想得到一块内存存放do0,应该向操作系统申请。但在这里出于两个原因我们不想这样做:
原因之一:过多地讨论申请内存将偏离问题主线; 原因之二:我们学习汇编的一个重要目的就是要获得对计算机底层的编程体验。 所以,在可能的情况下,我们不去理会操作系统,而直接面向硬件资源。 问题变得简单而直接,我们只需找到一块别的程序不会用到的内存区,将do0传送到其中即可。 前面讲到,内存0000:0000~0000:03FF,大小为1KB的空间是系统存放中断处理程序入口地址的中断向量表。 一般情况下,从0000:0200至0000:02FF的256个字节的空间所对应的中断向量表项都是空的,操作系统和其他应用程序都不占用。 根据以前的编程经验,我们可以估计出,do0的长度不可能超过256个字节。 结论:我们可以将do0传送到内存0000:0200处。四)、我们将中断处理程序do0放到 0000:0200 后,若要使得除法溢出发生的时候,CPU转去执行do0,则必须将do0的入口地址。
即0000:0200登记在中断向量表的对应表项中。 因为除法溢出对应的中断类型码为0,它的中断处理程序的入口地址应该从0×4地址单元开始存放,段地址存放在 0×4+2 字单元中,偏移地址存放在0×4字单元中。 也就是说要将do0的段地址0存放在 0000:0002 字单元中 ,将偏移地址200H存放在0000:0000字单元中。总结上面的分析,我们要做以下几件事情:
(1)编写可以显示“Welcome to Fishc.com!”的中断处理程序:do0; (2)将do0送入内存0000:0200处; (3)将do0的入口地址0000:0200存储在中断向量表0号表项中。程序框架:
[codesyntax lang="asm"]assume cs:code code segment start: do0安装程序 设置中断向量表 mov ax,4c00h int 21h do0: 显示字符串“Welcome to Fishc.com!” mov ax,4c00h int 21h code ends end start[/codesyntax]