汇编语言(王爽第三版) 第12章相关内容及实验12

本文深入探讨了计算机系统中的内中断概念,包括其产生、处理流程及中断向量表的作用。特别关注了0号中断(除法错误中断)的编程处理方法,通过实验详细展示了如何编写和安装中断处理程序,以及如何在除法溢出时显示错误信息。

第十二章 内中断

章节内容
概述

本章前半部分主要介绍了什么是内中断,包括中断的产生,中断的过程,中断的处理,中断向量表等。

后半部分为实验11"编写0号中断的处理程序"的思路和主要步骤(这里将放到实验部分描述),以及单步中断和响应中断的特殊情况。

内中断

CPU执行完指令后可以检测到来自CPU外部或内部的一种特殊信息,并且立即对所接收到的信息进行处理,称之为中断。

来自CPU内部的中断信息称之为内中断

内中断的产生

有以下情况会产生内中断

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

中断信息会给CPU提供一个字节的中断类型码(共256种),以反映中断来源(称为中断源),上述四种类型中断源的中断类型码分别是0,1,4和n(int 指令格式为int n,n为中断类型码)。

中断处理程序

CPU接收到中断信息后,查询中断向量表,找到相应中断处理程序的地址,将CS:IP指向它,从而跳转到中断处理程序处。

中断向量表

中断向量表在内存中保存,存放了256个中断源所对应的中断处理程序的入口(地址)。从内存0000:0000到0000:03FF的1024个单元依次存放了从0号到255号中断类型码对应的中断程序入口。

存储N号中断源对应的中断处理程序入口的偏移地址的内存单元地址为4N,段地址的内存单元地址为4N+2。

中断过程

CPU收到中断信息后按以下过程处理:

  1. 从中断信息中取得中断类型码;
  2. 标志寄存器的值入栈;
  3. 设置标志寄存器的第8位TF和第9位IF的值为0;
  4. CS的内容入栈;
  5. IP的内容入栈;
  6. 从内存地址为N*4和N*4+2(设中断类型码为N)的两个字单元中读取中断处理程序的入口地址设置IP和CS。

相当于:

  1. 取得中断类型码N
  2. pushf
  3. TF=0,IF=0
  4. push CS
  5. push IP
  6. (IP)=(N*4),(CS)=(N*4+2)

这里设置TF和IF两位标志寄存器的值后面再讲原因。

中断处理程序和iret指令

对于CPU,中断随时可能发生,故中断处理程序应一直存储在内存某段空间中,中断向量应存在对应中断向量表中。

中断处理程序的常规步骤:

  1. 保存用到的寄存器
  2. 处理中断
  3. 恢复用到的寄存器
  4. iret指令返回

iret 相当于:

  1. pop IP
  2. pop CS
  3. popf
编程处理0号中断(除法错误中断)

我们在实验11中详细给出。

单步中断

CPU提供了这样一个功能:执行完一条指令后,检测TF位是否为1,若TF位为1,则产生单步中断,终端类型码为1,引发中断,跳转到1号中断处理程序。

提供这样的单步中断功能,为单步跟踪程序执行过程提供了实现机制。

例如Debug程序,每次使用t命令,CPU就执行一条指令。实际就是Debug在执行t命令时将TF位置1,CPU判断TF位为1,就停止当前的程序转到1号中断处理程序,这里Debug提供的1号中断处理程序将所有寄存器的内容显示在屏幕上,并且等待下一个命令输入。

注意只要CPU执行完一条指令后TF为1,就会触发单步中断。而单步中断的中断处理程序也是一个由一条条指令组成的程序,过程中若TF一直为1,则会不断触发单步中断,程序陷入无限循环嵌套。所以在中断过程中,有将TF和IF置0的过程(IF涉及到外中断)。

响应中断的特殊情况

部分情况下,CPU执行完指令后,发生中断也不会触发响应。

其中一种便是向ss寄存器传送数据的指令。由于ss:sp联合指向栈顶,二者设置应连续完成。我们知道中断过程中有将标志寄存器、CS、IP的值压入栈的过程,若ss改变后发生中断,则会指向错误的栈顶,入栈地址错误。所以在向ss寄存器传送数据后,不响应中断。同时我们也应该将ss和sp的值连续的设置。

实验11 编写0号中断的处理程序

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

0号中断是除法错误中断,比如执行div指令发生了除法溢出。

执行以下程序时,会发生除法溢出:

assume cs:code
code segment
start:
	mov ax,1000h
	mov bh,1
	div bh
	
	mov ax,4c00h
	int 21h
code ends
end start

在这里插入图片描述

我们现在希望在发生除法溢出时,在屏幕中间显示字符串"divide error!",然后返回到DOS。

分析一下,首先按照中断处理过程,CPU获取中断类型码0,0号中断,将标志寄存器入栈置位再入栈CS:IP后,在0000:0002处找到0号中断处理程序的入口地址。

为了随时可执行0号中断处理程序(以下称do0),需将其放在一块固定的内存空间中。我们知道中断向量表有1K的空间,但实际上存放中断处理程序入口地址的空间远不到1K,后一大段内存单元(一般为0000:0200到0000:02FF的256个字节)为空。所以我们将do0程序存放在此处。

总的来说,分为3步:

  1. 编写do0程序,程序内容为在屏幕中间显示字符串"divide error!",然后返回到DOS。
  2. 将do0存放在0000:0200处。
  3. 将0000:0200这个地址存在中断向量表0号表项(0000:0002)处。

我们称将do0程序送入0000:0200处的过程称为安装。

编写完do0,安装然后设置中断向量后(编写do0和安装是在同一个程序中,顺序可以反过来,安装程序只是把do0代码复制到0000:0200处),再执行其他程序发生除法溢出后,就会看到我们想要的结果。

其他细节在代码注释中给出,代码:

assume cs:code
code segment
	start:
		;安装do0

		;这里使用rep和movsb复制do0
        ;ds:si为源地址
        mov ax,cs
        mov ds,ax
        mov si,offset do0
        ;es:di为目标地址
		mov ax,0
        mov es,ax
        mov di,200h
        ;用编译器配合offset计算传送的长度
        mov cx,offset do0_end-offset 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:
        ;程序从do0处进入,从do0_start处开始,所以跳转过去
        jmp short do0_start
    do0_data:
        ;将要显示的字符串也随程序一起记录在内存中,保证不会被覆盖
        db "overflow!"
    do0_start:
        ;设置ds:si指向字符串
        mov ax,cs
        mov ds,ax
        mov si,202h;这里si要设置成最后在内存中字符串的位置202h
        ;设置es:si指向显存位置
        mov ax,0b800h
        mov es,ax
        mov di,12*160+36*2;行号列号
        ;字符串长度
        mov cx,9
		;显示字符串
	    copy_start:
            mov al,[si]
            mov es:[di],al
            inc si
            add di,2
        loop copy_start
		;返回DOS
		mov ax,4c00h
		int 21h
    ;do0结束(方便计算传送长度)
    do0_end:nop
code ends
end start

结果对比:

在这里插入图片描述

在这里插入图片描述

这样设置的中断向量表,重启之后会被刷新重新指向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值