彙編語言(王爽)第十二章 內中斷

第十二章

CPU可以在執行完當前正在執行的指令之後,檢測到從CPU外部或內部產生的一種特殊信息,並且可以立即對所接收到的信息進行處理,這種特殊的信息稱爲中斷信息,其向所要進行的該種處理提供了必備的參數的通知信息

中斷:CPU不在接着剛執行完的指令向下執行,而是轉去執行這個特殊信息

12.1 內中斷的產生

對於8086CPU,當CPU內部有下面的情況發生的時候,將產生中斷信息

1、除法錯誤,比如,執行div指令產生的除法溢出

2、單步執行

3、執行into指令

4、執行int指令

CPU首先要知道,所接受到的中斷信息的來源,所以中斷信息中必須包含識別來源的編碼,稱爲中斷類型碼,爲一個字節型數據,可以表示256種中斷信息的來源,我們將產生中斷信息的事件,即中斷信息的來源,簡稱爲中斷源

上述4種中斷源的中斷類型碼如下

1、除法錯誤:0

2、單步執行:1

3、執行into指令:4

4、執行int指令,該指令的格式爲int n,指令中的n爲字節型立即數,是提供給CPU的中斷類型碼

12.2 中斷處理程序

如何對中斷信息進行處理,可以由我們編程決定,用來處理中斷信息的程序被稱爲中斷處理程序,不同的中斷信息編寫不同的處理程序

CPU收到中斷信息後,應該轉去執行相應的中斷處理程序,即設置CS:IP指向該程序的入口,所以需要在中斷信息和其處理程序的入口地址之間建立某種聯繫

中斷信息中包含有標識中斷源的類型碼,中斷類型碼的作用就是定位中斷處理程序,那麼如何根據8位中斷類型碼得到中斷處理程序的段地址和偏移地址?

12.3 中斷向量表

CPU用8位的中斷類型碼,通過查找中斷向量表找到相應中斷處理程序的入口地址

中斷向量就是中斷處理程序的入口地址,中斷向量表,就是中斷處理程序入口地址的列表

中斷向量表在內存中保存,其中存放着256箇中斷源所對應的中斷處理程序的入口,在8086PC機中,中斷向量表指定放在內存地址0處,從0000:0000到0000:03FF共1024個單元

中斷向量表中一個表項存放一個入口地址,佔兩個字,高地址字存放段地址,低地址字存放偏移地址

中斷向量表(內存中)
0號中斷源對應的中斷處理程序的入口地址
1號中斷源對應的中斷處理程序的入口地址
2號中斷源對應的中斷處理程序的入口地址
3號中斷源對應的中斷處理程序的入口地址
……

用Debug查看內存,情況如下:

0000:0000 68 10 A7 00 8B 01 70 00-16 00 9D 03 8B 01 70 00

則3號中斷源對應的中斷處理程序的入口地址爲:0070:018B

12.4 中斷過程

用中斷類型碼找到中斷向量,並用它設置CS和IP,這個工作由CPU的硬件自動完成。這個過程稱爲中斷過程,硬件完成中斷過程後,CPU開始執行CS:IP指向的中斷處理程序

CPU在指向玩中斷處理程序後,還要返回原來的執行點繼續執行下面的指令,所以在中斷過程中,設置CS:IP之前,要將原來的CS和IP保存起來(CPU在取完一條指令後,執行這條指令前,IP指向下一條指令)

具體過程:

1、(從中斷信息中)取得中斷類型碼

2、標誌寄存器的值入棧(中斷過程要改變標誌寄存器的值) pushf

3、設置標誌寄存器的第8位TF和第9位IF的值爲0

4、CS的內容入棧 push CS

5、IP的內容入棧 push IP

6、從內存中讀取中斷處理程序的入口地址

最後一步完成後,CPU開始執行由程序員編寫的中斷處理程序

12.5 中斷處理程序和iret指令

CPU隨時都可能檢測到中斷信息,也就是說。CPU隨時都可能執行中斷處理程序,所以中斷處理程序必須一直存儲在內存某段空間之中(CPU可以直接訪問內存)

中斷處理程序的編寫方法和子程序的比較相似

1、保存用到的寄存器

2、處理中斷

3、恢復用到的寄存器

4、用iret指令返回 pop IP pop CS popf

iret通常和中斷過程配合使用

12.6 除法錯誤中斷的處理

當CPU執行div等除法指令時,如果發生了除法溢出錯誤,將產生中斷類型碼爲0的中斷信息,引發中斷過程,執行相應中斷處理程序

mov ax,1000h
mov bh,1
div bh

該中斷處理程序會顯示提示信息"Divide overflow",返回到操作系統中

12.7 編程處理0號中斷

重新編寫一個0號中斷處理程序,當除法溢出時,在屏幕中間顯示"overflow",返回DOS

這裏我們跳過操作系統,直接面向硬件

在內存儲存中斷向量表的空間中,有很多單元(0000:0200至0000:02FF)是空的,可以存放我們的程序

同時,在中斷向量表對應的表項中設置新的地址

程序框架爲

assume cs:code

code segment

	start:	do0安裝程序
			設置中斷向量表
			
			mov ax,4c00h
			int 21h
			
	  do0:	顯示字符串"overflow!"
	  		mov ax,4c00h
	  		int 21h
	  		
code ends
end start

該程序執行時do0部分是不執行的,而是作爲中斷處理程序被複制到內存0:0200處,最後兩行代碼是根據要求返回DOS

do0部分的代碼只有在被複制到0:200處,且設置中斷向量表完畢後,才成爲0號中斷的中斷處理程序

即:讓一段程序成爲N號中斷的中斷處理程序,需要將它的入口地址放入中斷向量表的N號表項中

12.8 安裝

可以使用movsb指令,將do0的代碼送入0:200處,因此我們需要知道原始位置和目的位置,以及do0代碼的長度,我們利用編譯器來計算do0的長度,具體做法見代碼

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指向目的地址
			
			mov cx,offset do0end-offset do0
			
			cld						; 設置正向傳輸
			rep movsb
			
			設置中斷向量表
			
			mov ax,4c00h
			int 21h
			
	  do0:	顯示字符串"overflow!"
	  		mov ax,4c00h
	  		int 21h
	  		
   do0end:	nop
	  		
code ends
end start

"-"是編譯器識別的運算符號,可以用來進行兩個常數的減法

mov ax,8-4			; 編譯器處理爲mov ax,4
mov ax,(5+3)*5/10	; 編譯器處理爲mov ax,4

12.9 do0

字符串"overflow"的位置值得思考,如果跟之前一樣,在主程序中開闢一個data段,那麼在程序執行結束後,其佔用的內存空間被系統釋放,data段的位置可能會被別的信息覆蓋,到時候可能顯示的就不是正確的內容

所以應該把字符串放在一段不會被覆蓋的空間中

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指向目的地址
			
			mov cx,offset do0end-offset do0
			
			cld						; 設置正向傳輸
			rep movsb
			
			設置中斷向量表
			
			mov ax,4c00h
			int 21h
			
	  do0:	jmp short do0start
	  		db "overflow!"		; 使用一部分內存存儲字符串
	  		
 do0start:	mov ax,cs
 			mov ds,ax
 			mov si,202h			; 設置ds:si指向字符串
 			
 			mov ax,0b800h
 			mov es,ax
 			mov di,12*160+36*2	; 設置es:di指向顯存空間的中間位置
 			
 			mov cx,9
 		s:	mov al,[si]
 			mov es:[di],al
 			inc si
 			add si,2
 			loop s
 			
	  		mov ax,4c00h
	  		int 21h
	  		
   do0end:	nop
	  		
code ends
end start

當除法溢出發生時,CPU執行0:200處的jmp指令跳過字符串,轉到正式的程序執行

該字符串的段地址與溢出發生時執行的中斷處理程序段地址相同,由於jmp short do0start佔兩個字節,所以偏移地址爲202h

12.10 設置中斷向量

將do0的入口地址寫入0號表項中

mov ax,0
mov es,ax
mov word ptr es:[0*4],200h
mov word ptr es:[0*4+2],0

12.11 單步中斷

CPU在執行完一條指令後,若檢測到標誌寄存器的TF位爲1,則產生單步中斷,中斷類型碼爲1

中斷過程如下:

1、取得中斷類型碼1

2、標誌寄存器入棧,TF、IF設置爲0

3、CS、IP入棧

4、設置CS、IP

如Debug的T命令,可以單步執行被加載程序的指令

Debug提供了單步中斷的中斷處理程序,功能爲顯示所有寄存器中的內容後等待輸入,然後在使用t命令時,Debug將TF設置爲1,使得CPU工作於單步中斷方式下,則在CPU執行完這條指令後就引發單步中斷,執行單步中斷的中斷處理程序,在屏幕上顯示寄存器的內容,並等待輸入命令

中斷處理程序也是由一條條指令組成的,如果執行中斷處理程序之前TF仍爲1,則在執行完中斷處理程序的第一條指令以後,又會產生單步中斷……不斷套娃,所以我們注意到在中斷過程中,TF被設置爲0

所以完整過程爲:T命令(設置TF=1)->執行當前指令->中斷過程(設置TF=0)->中斷處理程序執行(顯示寄存器內容&等待輸入)->T命令(設置TF=1)->返回程序執行下一條指令……

CPU提供單步中斷功能的原因是,爲單步跟蹤程序的執行過程提供了實現機制

12.12 響應中斷的特殊情況

在有些情況下,CPU在執行完一條指令後,即便發生中斷,也不會立即響應

舉例:在執行完mov ss,ax之後,即便發生中斷,也不會響應,因爲這樣可能會導致ss:sp聯合指向棧頂時,指向不正確的棧頂,導致錯誤,所以CPU在執行完設置ss的指令後,不響應中斷,這給連續設置ss和sp提供了機會,所以我們應該利用這一特性,將兩條指令連續存放,如果將棧頂設置爲1000:0,不應該

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

因此,在Debug利用單步中斷實現T命令時,在mov ss,ax指令執行之後,CPU不響應中斷(不管下一條是什麼指令,都不響應),而是等到下一條指令mov sp,10h執行後,才響應中斷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章