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号中断编写完毕..