第十二章 内中断

任何一个通用的CPU,比如8086,都具备一种能力,可以执行完当前正在执行的指令后,检测到从CPU外部或内部产生的一种特殊信息,并且可以立即对所接收的信息进行处理。这种特殊的处理方式,我们称为中断信息。中断的意思就是CPU不在接着执行下面的代码,而是转去处理这个特殊的信息。

中断信息可以来源于外部或者是内部。

12.1内中断的产生

cpu主要的四种内中断

  1. 除法错误,比如执行div指令的时候产生的除法溢出。
  2. 单步执行
  3. 执行into指令
  4. 执行int指令

上面的中断类型码是:

  1. 除法错误0
  2. 单步执行1
  3. 执行into指令4
  4. 执行int指令,该指令的格式是 int n,指令中的n为字节型立即数,是提供给CPU的中断类型码

12.2中断处理程序

cpu收到中断信息之后,需要对中断信息进行处理,而如何对中断信息进行处理,可以由我们编程来决定,我们编写的,用来处理中断信息的程序被称为中断处理程序。一般来说,需要对不同的中断信息编写不同的处理程序。

CPU在收到中断信息之后,就应该转去执行该中断信息的处理程序,我们知道,若要8086CPU执行某处的程序,就要讲CS:IP指向它的入口(即程序的第一条指令的地址),可见,首要的问题就是如何根据中断信息确定其处理程序的入口。

12.3中断向量表

cpu用8位的中断类型码通过中断向量表找到相应的中断处理程序的入口地址。那么什么是中断向量表?中断向量表就是中断向量的列表。那么什么是中断向量?中断向量就是中断处理程序的入口地址。展开来说,就是中断处理程序入口地址的列表。

中断向量表在内存中,其中存放着256个中断类型所对应的中断处理程序的入口。

中断向量表指向内存地址0处。

在中断向量表中,一个表项存放一个中断向量,也就是一个中断处理程序的入口地址,对于8086cpu中,这个入口地址包含段地址和偏移地址,所以一个表项占两个字,高地址存放段地址,低地址存放偏移地址。

12.4中断过程

用中断类型码找到中断向量,并用它来设置cs和ip,这个工作是由cpu的硬件自动完成的。cpu硬件完成这个工作的过程称为中断过程。

cpu收到中断信息之后,要对中断信息进行处理,首先是引发中断过程。硬件在完成中断过程之后,cs:ip将指向中断处理程序的入口,cpu开始工作。

12.5中断处理程序和iref指令

iret通常和硬件自动完成的中断过程配合使用。

12.6除法错误中断的处理

mov ax,1000h
mov bh,1
div bh

执行之后将产生Divide overflow

12.7编程处理0号中断

程序框架如下:

assume cs:code
code segment
start :do0 安装程序
        设置中断向量表
        mov ax,4c00h
        int 21h
  do0:显示字符串"overflow!"
     mov ax,4c00h
     int 21h
 code ends
end start

从上面可以看出,程序主要分为两部分

  1. 安装do0程序,设置中断向量的程序
  2. do0

执行上面的程序的时候do0代码是不执行的。他只是作为do0安装程序索要传送的数据。首先是执行do0安装程序,将do0处的代码复制到内存0:200处,让后设置中断向量表,将do0处的入口地址,就是偏移地址是200H和段地址是0,保存到0号表项中。这部分完成之后,程序就开始返回。程序的目的就是在内存0:200处安装do0的代码,将0号中断处理程序的入口地址设置为0:200.do0的代码虽然在程序中,却不在这个程序执行的时候执行。它是在除法益处发生的时候才得以执行的中断处理程序。

我们来看看do0是如何变成0号的中断处理程序的。

(1)上面程序被执行的时候,被加载到内存中,此时do0的代码在上述程序的内存中,他只是存放在上述程序中的一段要被复制到其他单元的数据,我们不能说他是中断处理程序。

(2)上传do0的安装程序执行之后,do0的代码被从上述程序中复制到0:200处,此时我们也不能说它是0号中断的中断处理程序,它只不过是存放在0:200处的一些程序

(3)程序设置完中断向量表之后,在0号表项中填入了do0处的入口地址0:200,此时do0处的信息,就是do0处的代码,就变成了0号中断的中断处理程序。因为当除法溢出时(就0号中断)发生时,cpu讲执行0:200处的代码。

我们知道:

将一个内存单元的地址放在SS:SP中,这个内存单元将作为栈顶。

将一段程序的地址放在CS:IP,这段程序将被CPU当作程序来执行。

将一个入口程序的地址放在中断向量表的N号表项中,这段程序将变成N号中断的中断处理程序。

12.8安装

可以使用movsb将do0处的代码传送到0:200处。

可以使用编译器来为我们计算do0的长度。

assume cs:code
code segment
start:mov ax,cs
      mov ds,ax
      mov si,offset do0
      mov ax,0
      mov es,ax
      mov di,200h
      
      mov cs,offset do0end-offset do0
      cld
      rep movsb
      设置中断向量表
      mov ax,4c00h
      int 21h
  do0:显示字符串"overflow"
      mov ax,4c00h
      int 21h
  do0end:nop
 code ends
end start

12.9do0

do0的程序是用来显示,主要操作就是将需要显示的代码复制到显存空间里面。

assume cs:code
code segment
start:mov ax,cs
      mov ds,ax
      mov si,offset do0
      mov ax,0
      mov es,ax
      mov di,200h
      
      mov cs,offset do0end-offset do0
      cld
      rep movsb
      设置中断向量表
      mov ax,4c00h
      int 21h
  do0:jmp short do0start
        db 'overflow!'
  do0start:mov ax,cs
      mov ds,ax
      mov si,202h
      
      mov ax,0b800h
      mov es,ax
      mov di,12*160+36*2
      
      mov cx,9
    s:mov al,[si]
      mov es:[di],ax
      inc si
      add di,2
      loop s
      
      mov ax,4c00h
      int 21h
  do0end:nop
 code ends
end start

12.10设置中断向量

0号表项的地址为0:0,其中0:0字单元存放偏移地址,0:2存放字单元的段地址。

mov ax,0
mov es,ax
mov word ptr es:[0*4],200h
mov word ptr es:[0*4+2],0

12.11单步中断

基本上,如果cpu执行完一条指令之后,如果检测到标志位寄存器TF位为1的话,则产生单步中断,引发中断过程。单步中断的中断类型码是1。

所以在debug中执行-t的时候就是产生了单步中断,中断程序显示各个寄存器的状态,然后等待下一个指令的输入。

12.12相应中断的特殊情况

一般情况下,如果cpu检测到中断信息,就会响应中断,引发中断过程,可是在某一些特殊的情况下,cpu即使发生了中断,也不会相应。

比如在执行了mov ss,ax后,cpu不会相应中断的,这是因为中断的过程,标志位寄存器,cs和ip等值都要压入到栈中,如果中断,会导致错误

mov ax,1000h
mov ss,ax
mov sp,0

而不应该是

mov ax,1000h
mov ss,ax
mov ax,0
mov sp,0

共有 0 条评论

Top