0号中断是除法溢出中断

当某程序发生除法溢出错误时 则系统中的0号中断处理程序触发
显示提示信息"Divide overflow"并返回操作系统中

现编写程序处理0号中断 功能稍作修改字符串改为"overflow!"即可

1 分析

  当除法溢出时 cpu的工作
  1 取得中断类型码 0
  2 标志寄存器入栈  TF IF设置为0
  3 cs ip入栈
  4 ip=(0*4)  cs=(0*4+2)

2 我们所要做的几点

 1 编写一段子程序do0 完成 溢出时 我们想要的功能
   问题 此子程序放在哪?
  因为除法溢出 随时可以发生 所以do0 应存放于内存中
     那么放在哪块内存呢?
 
  由于我们是在操作系统之上使用计算机 所有的硬件资源 都在操作系统的管理之下。。

  所以我们想得到一块内存区域存放do0 应该向操作系统申请
 (王爽说: 偶们学习汇编的主要目的之一 就是要 获得对计算机底层的编程体验所以 在可能的情况下 我们不去理睬操作系统 而直接面向硬 件资源)所以我们只要找到一块 别的程序 不会用到 的内存区 将do0 复制到其中即可
 
  内存0000:0000---0000:03ff 大小为1kb的空间是系统存放
  中断处理程序入口地址 的中断向量表
    8086支持256个中断 但是 实际上系统中要 处理的中断事件 远没有达到256个
  所以在中断 向量表中 有许多单元是 空的

  中断向量表 是pc系统中 最重要的内存区 dos系统和其他应用程序都不会随便占用
  一般情况下 0000:0200---0000:02ff 的256个字节 所对应的中断向量表是空的
  而do0程序的长度不会超过256个字节(根据王爽的编程经验)

  所以 综上所述  :: do0程序 我们可以存放在内存0000:0200处

 2 我们还必须将 do0 程序的入口地址0000:0200 存储在中断向量表0号表项中

    到此 我们的程序框架已经有了:

 assume cs:code
 
 code segment
 start:
   安装do0程序
  (安装即 将下边的do0数据 复制到 0000:0200开始处)
   
  设置中断向量表
  (设置即 将 do0 程序的入口地址0000:0200 存储在中断向量表0号表项中 )

  mov ax,4c00h
  int 21h
  
 do0 :  显示字符串"overflow"
  mov ax,4c00h
  int 21h
 code ends
 end  start
  
 


3 分析到此 可以得知我们将程序 分为两部分
  1 安装 do0(即 复制do0程序)
  2 编写 do0 程序

 第一部分 安装do0
  上边的程序框架中 do0程序 是不执行的 它仅仅作为数据 复制到0000:0200处
  当 除法溢出时 才会触发
  安装的具体实现
 start:
   安装do0程序
  (安装即 将下边的do0数据 复制到 0000:0200开始处)
   (复制是用 rep movsb 指令)


  设置 es:di指向目的地址
  设置 ds:si 指向源地址
  设置 cx为传输长度
  设置传输方向为正
  rep movsb

  设置中断向量表
  
  mov ax,4c00h
  int 21h
  
 do0 :  显示字符串"overflow"
  mov ax,4c00h
  int 21h
 code ends
 end  start


  具体代码
 start:
  mov ax,cs
  mov ds,ax
  mov si,offset do0  ;设置 ds:si 指向源地址
  
  mov ax,0 
  mov es,ax
  mov di,200h        ;设置 es:di指向目的地址(0000:0200h)

  mov cx,offset do0end - offset do0
   ;得知 do0程序的长度的一个 简单方法(记住)

  cld     ;传输方向为正 
  rep movsb
  设置中断向量

  mov ax,4c00h
  int 21h
  
 do0 :  显示字符串"overflow"
  mov ax,4c00h
  int 21h

 do0end: nop         

 code ends
 end  start

至此 安装完毕

   第二部分 编写 do0 程序

   do0程序的主要内容是 显示字符串
 
  do0: 设置ds:si指向字符串
 mov ax,0b800h
 mov di,12*160+36*2  设置es:di指向显存空间的中间位置
 
 mov cx,9 ;字符串长度 "overflow!"

s: mov al,[si]
 mov ah,00000111b  ; 8闪765背景色4高亮321前景色
 mov es:[di],ax
 
 inc si
 add di,2
 loop s
 
 mov ax,4c00h
 int 21h
  do0end:nop

  程序写好了 现在有一个问题字符串 放哪啊?
  如果在本程序中 添加一个 data 段 放入我们要显示的"overflow!"
  这样是不对的
  因为当才程序完成后 此程序所占得内存空间被系统释放
  而其中存放的"overflow!"也将很可能被其他的信息覆盖

  而do0程序被放在0:0200处 随时都有可能因为除法溢出而被cpu执行
  很难保证do0程序从原来的程序(放字符串的程序) 所处的空间中取得的是要
  显示的字符串"overflow!"
 
  所以该字符串也应存放在一个不会被覆盖的空间中
 
  还有一部 设置中断向量:
 即将do0的入口地址放到0号表项中
 使do0成为0号中断的处理程序
 0:0 是0号表项的地址
  段地址在(0:2)
 偏移地址(0:0) 所以程序如下
 mov ax,0
 mov es,ax
 mov word ptr es:[0*4],200h
 mov word ptr es:[0*4+2],0 

  最终程序如下

     assume cs:code
 
 code segment
 start:
   mov ax,cs
  mov ds,ax
  mov si,offset do0  ;设置 ds:si 指向源地址
  
  mov ax,0 
  mov es,ax
  mov di,200h        ;设置 es:di指向目的地址(0000:0200h)

  mov cx,offset do0end - offset do0
   ;得知 do0程序的长度的一个 简单方法(记住)

  cld     ;传输方向为正 
  rep movsb
  
  mov ax,0
  mov es,ax
  mov word ptr es:[0*4],200h
  mov word ptr es:[0*4+2],0 
  

  mov ax,4c00h
  int 21h
  
 do0:    jmp short do0start
  db "overflow!"
 do0start:
  mov ax,cs
  mov ds,ax
  mov si,202h  ;设置ds:si指向字符串(jmp short do0start 占俩字节)

  mov ax,0b800h
  mov es,ax
  mov di,12*160+36*2  ;设置es:di指向显存空间的中间位置
 
  mov cx,9 ;字符串长度 "overflow!"

 s: mov al,[si]
  mov ah,01001001b  ;8闪765背景色4高亮321前景色(红底蓝字)
  mov es:[di],ax    ;记住是ax
 
  inc si
  add di,2
  loop s
 
  mov ax,4c00h
  int 21h
   do0end:nop

 code ends
 end  start
  
 
 0号中断编写完毕..