• 内中断02 零基础入门学习汇编语言61


    第十二章:内中断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]  

    我们可以看到,上面的程序分为两部分:

    (1)安装do0,设置中断向量的程序 (2)do0   程序执行时,do0的代码是不执行的,它只是作为do0安装程序所要传送的数据。 执行do0安装程序,将 do0 的代码拷贝到内存 0:200处,然后设置中断向量表,即偏移地址200H和段地址0,保存在0号表项中。这两部分工作 完成后,程序就返回了。   程序的目的就是在内存0:200处安装do0 的代码,将0号中断处理程序的入口地址设置为0:200。 do0的代码虽然在程序中,却不在程序执行的时候执行。它是在除法溢出发生的时候才得以执行的中断处理程序。 do0部分代码的最后两条指令是依照我们的编程要求,用来返回DOS的。 [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://kuai.xunlei.com/d/LFLCOQAYXGWT']视频下载[/Downlink]
  • 相关阅读:
    Serilog 动态添加自定义属性
    C# 序列化与反序列化
    幂等设计
    服务无状态
    vue 显示 mysql 数据库表 Demo
    C# 调用 linux 函数 —— Linux 头文件目录位置
    创建可以在 Zynq 上运行的动态库
    C# 获取所在函数名
    Linux 关闭终端不结束进程
    C# 自动生成版本号
  • 原文地址:https://www.cnblogs.com/LoveFishC/p/3847052.html
Copyright © 2020-2023  润新知