(二十一)《汇编语言(王爽)》 | 实验 12:编写 0 号中断的处理程序


1. 预备知识

  • 前面提到,CPU 用 8 位中断类型码通过中断向量表找到相应的中断处理程序的入口地址。找到段地址和偏移地址后,用它来设置 CS 和 IP,CPU 会自动运行中断处理程序。该过程可概括为:
    (1)取得中断类型码 N
    (2)pushf,将各标志寄存器的内容入栈
    (3)TF=0,IF=0(该设置后续章节介绍)
    (4)push CS,保存原 CS 的值
    (5)push IP,保存原 IP 的值
    (6)(IP)=(4N),(CS)=(4N+2)
  • 中断处理程序和子程序类似,主要分为以下步骤:保存用到的寄存器,处理中断,恢复用到的寄存器,用 iret 指令返回。iret 指令包含恢复 CS:IP 的内容和恢复标志寄存器的内容。

2. 实验任务

编写 0 号中断的处理程序,使得在除法溢出发生时,在屏幕中间显式字符串“divide error!”,然后返回 DOS。

根据预备知识的内容,编写 0 号中断的处理程序流程为:编写中断处理程序 do0将 do0 的代码放入内存 0000:0200 处(该区域 CPU 很少用到),将 do0 代码的入口地址 0000:0200 存储在中断向量表 0 号表项中

2.1 编写中断处理程序 do0

由于在运算时随时会发生除法溢出,CPU 去执行 0 号中断处理程序时,待显式字符串必须放在 CPU 不使用的区域而防止被覆盖。可以考虑将该字符串放到 do0 程序中,do0start 为真正开始的程序:

do0:
	jmp short do0start
	db "divide error!"
do0start:
	;中断处理程序

2.2 将 do0 代码放入内存 0000:0200 处

借助 movsb 指令,将 do0 的代码送入 0000:0200 处:

assume cs:code
code segment
start:
	;设置es:di指向目的地址
	;设置ds:si指向源地址
	;设置cx为传输长度
	;设置传输方向为正
	rep movsb
	;设置中断向量表
	mov ax,4c00h
	int 21h
do0:
	;显式字符串"overflow"
	mov ax,4c00h
	int 21h
code ends 
end start

传输长度为 do0 代码部分的长度,可通过 offset do0end-offset do0 计算得到,其中减号实现两个常数的减法。do0end 为仅包含空的段:

do0end:
	nop

2.3 设置中断向量

将 do0 程序入口地址写入中断向量表的 0 号表项中:

mov ax,0
mov es,ax
mov word ptr es:[0],200h	;低地址写入偏移地址
mov word ptr es:[2],0		;高地址写入段地址

综上,整体程序为:

assume cs:code
code segment
start:
	mov ax,0
	mov es,ax 
	mov di,200h						;设置es:di指向目的地址
	mov ax,cs 
	mov ds,ax 
	mov si,offset do0				;设置ds:si指向源地址
	mov cx,offset do0end-offset do0 ;设置cx为传输长度
	cld								;设置传输方向为正
	rep movsb
	mov ax,0
	mov es,ax
	mov word ptr es:[0],200h	;低地址写入偏移地址
	mov word ptr es:[2],0		;高地址写入段地址(设置中断向量表完成)
	mov ax,4c00h
	int 21h
do0:
	jmp short do0start 
	db "divide error!"			;将字符串存放到do0内
do0start:
	mov ax,cs 
	mov ds,ax
	mov si,202h			;指令jmp short do0start的长度为2字节,代码真正开始的位置为0000:0202h
	mov ax,0b800h
	mov es,ax			;B8000H~BFFFFH为显式缓冲区
	mov di,12*160+36*2	;在屏幕中间显式字符串"divide error!"
	mov cx,13			;设置cx为字符串长度
	
	s:	
		mov al,ds:[si]
		mov es:[di],al		;字符
		mov ah,02h			
		mov es:[di+1],ah	;字符属性,绿色字体
		inc si 
		add di,2			;每次偏移2字节写入字符
		loop s
		
		mov ax,4c00h
		int 21h
do0end:
	nop
code ends 
end start

编译链接生成可执行文件,运行可执行文件后,首先查看中断向量表的第 0 项,地址为 0000:0000。

请添加图片描述
此时,中断向量表的第 0 号项内容为 00 02 00 00,对应的地址为 0000:0200,然后查看 0000:0200 处的内容。
请添加图片描述

红色部分和蓝色部分分别为字符串的 16 进制表示和 ASCII 码。红色部分前面的内容 EB 0D 对应于源代码中的 jmp short do0start 共两个字节。do0start 部分的代码从 0000:020F 处开始,将对应的机器码翻译为汇编代码。

请添加图片描述

红色部分和蓝色部分分别为机器码和汇编代码的一一对应,即 do0start 部分的代码。

2.4 测试

编写除法溢出代码测试上述 0 号中断处理程序。

assume cs:code
code segment
start:
	mov ax,1000h
	mov bh,1
	div bh	
	;除数为8位,被除数默认放在ax中,
	;此时结果中al存储商,ah存储余数,结果1000h对于存储商的寄存器al溢出
code ends 
end start

编译链接生成可执行文件,运行可执行文件后,屏幕中间位置处显式绿色字体的 divide error!。

请添加图片描述


3. 总结

  • 本文介绍了编写 0 号中断处理程序的内容,编写中断的处理程序主要分为以下步骤:编写中断处理程序,如本文的显式除法溢出的错误信息提示;将中断处理程序的代码放入 CPU 很少访问的内存区域,如本文将其放入内存 0000:0200 处;将中断处理程序的入口地址放入中断向量表的对应表项中,如本文处理 0 号中断将中断处理程序的入口地址放入内存的 0000:0000 处。
  • 为了显示显式信息被覆盖,将显示字符串放入中断处理程序中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值