Skip to content

Latest commit

 

History

History
157 lines (91 loc) · 5.9 KB

12.内中断.md

File metadata and controls

157 lines (91 loc) · 5.9 KB

王爽汇编第12章,内中断

[toc]

内中断概述

任何一个通用的CPU,比如8086,都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息,并且可以对立即所接收到的信息进行处理。这种特殊的信息,我们称其为:中断信息。

中断意思:CPU不再接着(刚执行完的指令)向下执行,而是转取处理这个特殊信息。(感觉和异常有点像?)

内中断的产生

当CPU内部有什么事情发生的时候,将产生需要马上处理的中断信息。

产生的中断信息如下:

  • 除法错误(0)
  • 单步执行(1)
  • into指令(4)
  • int指令(int n) n:中断类型码

终端信息中包含中断类型码,中断类型码为一个字节型数据,可以表示256种中断信息的来源(中断源

中断处理程序

CPU在收到中断信息后,需要对中断信息进行处理。而如何对中断信息进行处理,可以由我们编程决定,就像我们写高级语言产生异常后,可以在catch里面对抛出的异常进行处理。

  • 用来处理中断信息的程序被称为中断处理程序。

  • 根据CPU的设计,中断类型码的作用就是用来定位中断处理程序。比如CPU根据中断类型码4,就可以找到4号中断的处理程序

中断向量表

CPU是根据中断向量表来存放中断处理程序的入口地址的,里面放的是所有中断处理程序入口地址的列表。

CPU用8位的中断类型码通过中断向量表找到相应的中断处理程序的入口地址

image-20210925165409358

中断过程

中断的过程一共如下步骤:

  • 取得中断类型码 (N)
  • pushf (保存标志寄存器现场)
  • TF = 0, IF = 0
  • push cs (方便跳回来)
  • push ip
  • ip = N * 4
  • CS = N * 4 +2

在最后一步完成后,CPU就会跳到由程序员编写的中断处理程序入口处执行代码。

iret指令

中断处理程序的常规编写步骤,和函数差不多只不过用了(iret):

  • 保存用到的寄存器
  • 处理中断
  • 恢复用到的寄存器
  • 用iret指令返回

iret = poppopcspopf

除法错误的中断处理

image-20210925171706784

当CPU执行div bh时,发生了除法溢出错误,产生了0号中断信息,从而引发中断过程

CPU跳到0号中断处理程序执行代码

0号系统中断处理程序的功能:显示Divide overflow,返回到DOS中。(像极了异常处理)

image-20210925171731853

动手实践,重写除法溢出

需求:编写0号中断处理程序do0,当发生除法溢出时,在屏幕中间显示 "overflow!",返回DOS。

分析:

  1. 发送除法溢出时,产生0号中断信息,引发中断过程,CPU将进行中断过程小节中的过程。
  2. 按照如下步骤编写中断处理程序,当中断0发生时,即可显示Overflow!
  • 相关处理
  • 向显示缓冲区送字符串Overflow!
  • 返回DOS PS:(我们可以将段程序称为:do0)
  1. 现在的问题是:do0应该存放在内存中,因为除法溢出随时可能会发生,CPU随时可能将CS:IP指向do0的入口,执行程序。

之前有讲过,内存0000:0000~0000:03FF,大小为1KB空间,存放256个中断向量表的,但是一般情况,系统中要处理中断条件肯定不会有256个那么多,所以这时候很多中断表是空着的。我们可以选0000:0200~0000:02FF来存中断程序。

  1. 将中断处理程序do0放到0000:0200后,如果除法溢出后,CPU转去执行do0,则必须将do0的入口地址,存放到0号中断码向量表的偏移中,即0000:0000

  2. 经过上面的分析,总结如下:

1、0000:0200至0000:02FF的256个字节的空间所对应的中断向量表项都是空的,可以将中断处理程序do0传送到内存0000:0200处。

2、中断处理程序do0放到0000:0200,再将其地址登记在中断向量表对应表项

  • 0号表项的地址0:00:0字单元存放偏移地址,0:2字单元存放段地址
  • 将do0的段地址0存放在0000:0002字单元中,将偏移地址200H存放在0000:0000字单元

image-20210925175225766

单步中断

CPU在执行完一条指令后,如果检测到标志寄存器的TF位为1,则产生单步中断,中断类型码1

【思路扩展】:原来OD和x32dbg单步调试用的应该就是这种中断办法吧,改了TF,然后产生中断,单步执行代码

单步中断的过程:

  1. 取得中断类型码1
  2. pushf,TF=0、IF=0
  3. push cs、push ip
  4. ip=(1x4),cs=(1x4+2)

最后,CPU提供单步中断功能的原因是,为单步跟踪程序的执行过程,提供了实现机制。

响应中断的特殊情况

比如我们设置ss段寄存器,然后还没开始设置sp栈顶的时候,这时候如果发生中断过程,由于要进行一系列的pushf或者push cs等操作,这样会导致我们堆栈里面有数据,导致ss:sp指向的不是正确的栈顶,将引起错误。

所以CPU提供了一个机制,在设置完ss段寄存器后CPU不响应中断。(所以我们最好将ss和sp指令连续存放)

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

int中断指令

int指令的格式为:int n ,n为中断类型码,它的功能是引发中断过程

CPU执行int n指令,相当于引发一个n号中断的中断过程

比如:

int 2
int 3

参考资料:

《王爽汇编语言(第4版) 第12章:内中断》

https://blog.csdn.net/qq_39654127/article/details/88698911 王爽《汇编语言》笔记