用匯編編寫DOS下的記憶體駐留程式(3) (轉)

amyz發表於2007-08-15
用匯編編寫DOS下的記憶體駐留程式(3) (轉)[@more@] 三 中斷向量
3.1 IBM PC提供的中斷
 IBM PC有兩種基本形態的中斷.如果是由外圍裝置所產生的中斷就叫做中斷(Hardware interrupt),譬如:鍵盤,機和時鐘等外圍裝置都可以產生硬體中斷.外圍裝置所產生的中斷訊號都連線到中斷控制器,中斷控制器可以根據它們之間的重要性來安排優先順序,以便使有效地處理這些硬體訊號.另一種中斷是中斷(Software interrupt),軟體中斷也叫做陷井(Trap),它是由中的軟體所產生.雖然軟體包中斷的處理方式和硬體中斷完全相同,但是通常軟體中斷是希望執行操作所提供的服務.
 表3.1是IBM PC所提供的中斷,這些中斷是根據中斷號碼和中斷向量(Interrupt vector)排列.
 IBM PC的或是編寫應用的程式人員很少會直接接觸到硬體中斷,除非是使用某些特殊的硬體,或是需要較嚴格的要求時,最常被修改的硬體中斷是敲鍵盤所產生的中斷(9H),尤其是文字編輯的程式.大體而言,只有硬體設計者基是系統程式人員才會注意到所有在硬體中斷;編寫駐留程式的設計人員則只使用到部分硬體中斷而已,尤其是:鍵盤中斷和計時器(Timer)的中斷.
 反之,軟體中斷對於任何編寫匯序的人,甚至對編寫高階語言程式的人都相當的重要.軟體中斷是應用程式進入到IBM PC的介面,經由這些介面應用程式才可以執行所要求的系統服務.
 其中軟體中斷中最重要,同時也是最常被語言師所用到是DINT 21H.這個中斷是執行DOS系統的軟體中斷,它可以讓應用程式執行任何DOS的操作.
 接下來最有用的軟體中斷是ROM-(基本輸入輸出系統)所提供的中斷.這些軟體中斷是IBM PC所提供的的低層次服務,譬如:鍵盤輸入,顯示器輸出和磁碟機的輸入與輸出等.
3.2 鍵盤輸入的方法
 以下就以IBM PC從鍵盤讀取字元為例子,來說明中斷的工作方式.IBM PC從鍵盤讀取字元時,使用了兩種不同形式中斷,亦即:硬體中斷和軟體中斷.當使用者從鍵盤敲下一個鍵時,鍵盤的線路就會送出一個訊號.這個訊號會造成硬體中斷髮生,從而觸發低層次的鍵盤中斷處理程式開始執行.這個中斷處理程式馬上從鍵盤的硬體讀取使用者所敲入的字元,然後把它放到一個佇列中,如果這個佇列填滿時,鍵盤中斷處理程式會使IBM PC發出一聲響.鍵盤中斷處理程式做完這些事情之後,它就把控制權交還給原先被中斷的程式.如果有一個程式希望從鍵盤讀取一個字元時,它就發出適當的軟體中斷訊號,這時候就由相對應的中斷處理程式去檢查鍵盤佇列,並且傳回佇列中的第一個字元.
 上面所介紹的鍵盤輸入工作方式,在中斷系統中很普遍地採用.這和做法可以把實際上需要輸入的應用程式和實際上執行輸入的處理部分分開來.這種做法也可以用在其它不同形式的輸入和輸出外圍裝置.
3.3 改變輸入向量
 中斷向量儲存在IBM PC最前面的400H個位元組中.每一個向量的長度是四個位元組組成,這四個位元組內所存放的是中斷處理程式執行的地址值.其中前兩個位元組包含地址值的位移(Offset)部分,後面的兩個位元組則包含了段(Segment)部分.
 中斷向量有兩種修改方法.可以直接地設定中斷向量的地址值,或是使用DOS所提供的系統呼叫設定中斷向量的地址值.
 3.3.1 直接設定中斷向量
 因為中斷向量只是存放地址值的位置,因此我們可以直接地把地址存放到儲存位置中.以下是一個小例子:
 mov ax,0
 mov es,ax
 mov  ptr es:24,offset Keyboard
 mov word ptr es:26,seg Keyboard
 在許多情況下,上面的程式都可以正確地執行.但是如果上面的程式正在執行時突然敲下一個鍵的話,就可能會問題;而最糟的情 況是發生:第三個MOV已經執行完畢,而第四個MOV尚未執行時.如果在此時敲下任何鍵的話,鍵盤中斷向量都沒有任何意義,而造成整個系 統當機.因此我們可以在設定中斷向量時,讓中斷無效,譬如:
 mov ax,0
 mov es,ax
 cli
 mov word ptr es:24,offset Keyboard
 mov word ptr es:26,seg Keyboard
 上面的做法在大部分的情況下都可以正確地執行.但是CLI這個指令無法停止NMI中斷(不可遮蔽中斷),因此如果發生NMI中斷時就 沒用辦法.下面的這一種做法雖然比較複雜,但是對於所有的中斷都有效,這包括了NMI中斷在內:
 mov word ptr kbd-ptr[0],offset Keyboard
 mov word ptr kbd-ptr[2],seg Keyboard
 mov di,0 ;Use Di to Set ES to zero
 mov es,di ;Set ES to destination segment
 mov di,24 ;Set DI to destination offset
 mov si,offset kbdptr ;set SI to offset
 mov cx,2 ;Set word count to 2
 cld ;Set direction to forward 
 cli  ;Disable interrupts
 rep movsw ;Copy the new vector
 sti ;Enable interrupts
 kbdptr dd ?
 上面的程式中,kbdptr是兩個位元組(WORD)的指標(Pointer),其中包含了鍵盤 中斷處理程式的起始志趣值.REP這個指令將根據寄存 器CX所設定的次數來重複執行MOVSW,而整個指令就如同單一的指令一樣.NMI中斷不能夠發生在一個完整的指令中.因為地址值搬移的操 作都能包含在一個單一指令中,因此可以免除任何中斷的干擾.
 3.3.2 使用DOS來設定中斷向量
 因為要想地設定中斷向量需要一些技巧,因此DOS提供了一項特殊的服務,以幫助程式人員安全地設定中斷向量,如果只使用 DOS所提供的這項服務來設定中斷向量的話,那麼就不必擔心會發生前面所敘述的差錯.DOS同時也提供了:讀取中斷向量的服務.因為讀 取中斷向量的內容不會修改系統的狀態;因此若直接寫程式讀取,也很安全.但是如果你要自己直接讀取中斷向量的內容時,就必須計算 出中斷向量的位置.而DOS已經提供了這項服務.
 使用DOS所提供的系統呼叫,來讀取中斷向量的內容時,必須利用INT 21H中的35H(讀取中斷向量),這個函式熱氣向量號碼來 計算中斷向量的地址,然後返回其中的內容.以下就是一個例子:
 Old_Keyboard_IO dd ?
 mov al,16h
 mov ah,35h
 int 21h
 mov word ptr Old_Keyboard_IO,bx ;Offset of interrupt handler
 mov word ptr Old_Keyboard_IO,es ;Segment of interrupt handler
 用DOS來設定中斷向量例子:
 New_Keyboard_IO dd ?
 mov word ptr New_Keyboard_IO,bx ;Offset of interrupt handler
 mov word ptr New_Keyboard_IO,es ;Segment of interrupt handler
 mov al,16h
 mov ah,25h
 int 21h
3.4 檢查中斷向量
 這裡都是採用COM格式程式設計,可以建立一個BAT來處理寫好的程式,以減少擊鍵次數.設BAT檔名為MAKE.BAT:
 MASM %1
 LINK %1
 EXE2BIN %1.EXE %1.COM
 如果寫好的程式名為MACRO.ASM,則可敲入:
 C:MAKE MACRO.ASM
 即可.
3.5 顯示中斷向量
 下面這個例子可以列出所有的重要的中斷向量內容,在剛剛開啟PC時,並且沒有執行任何駐留程式時,可以發現所有的中斷向量段值都相同,這些地址值所存放的是ROM的程式.當你修改中斷向量之後,就可以利用這個程式觀察到中斷向量的變化.以下就是IVEC.ASM的內容:
 cseg  segment para public 'CODE'
 org  100h
 jmp start
 assume  cs:cseg,ds:cseg
 start: 
 mov  bx,cs  ;Make data seg be the same as
 mov  ds,bx  ;the code seg
 call  vectors
 waitIn:
 mov ah,0bh
 int 21h
 cmp al,0ffh
 jne waitIn
 mov  ah,4ch
 int  21h
 ;****************************************************************************
 ;Scan through display table,prinying two vectors per line
 ;If any record has an interrupt #=zero,this indicates
 ;end of the table.
 ;****************************************************************************
 mov  di,offset disptab  ;Pointer to start of table
 mov  dh,0  ;Zero out top half of DX
 vl: 
 mov  dl,[di]  ;Get the interrupt number
 cmp  dl,0  ;If it's zero,we are done
 je  vdone  ;so exit loop
 add  di,1  ;Advance pointer 1 byte
 mov  si,[di]  ;Get pointer to description
 call  dvector  ;Call the display routine
 add  di,2  ;Get the interrupt number
 mov  dl,[di]  ;Advance to the next record 
 cmp  dl,0  ;If it's zero,we are done
 je  vdone  ;so exit loop
 add  di,1  ;Advance pointer 1 byte
 mov  si,[di]  ;get pointer to description
 call  dvector  ;Call the display routine
 add  di,2  ;Advance to the next record
 jmp  vloop 
 vdone:  ;Print final CRLF
 ret
 vectors endp
 ;----------------------------------------------------------------------------
 ;Displays an interrupt vector.Display is in the foof
 ;,,:
 ;where ,and
 ;are all dexadecimal numbers
 ;Call with
 ;DX  -interrupt number
 ;DS:SI  -pointer to banner string
 ;----------------------------------------------------------------------------
 dvector proc  near
 call  dstring  ;Display the string in DS:SI
 call  yte  ;Display the byte in DL
 call  dspace  ;Display a space
 call dspace
 ;
 mov  al,dl  ;move the interrupt number to AL
 mov  ah,35h  ;Function is Get interrupt vector
 int  21h
 mov  dx,bx  ;Move BX to DX so we can display
 call  ddword  ;double-word in ES:DX
 call dEndFra
 call  dcrlf  ;Display a newline
 ret
 dvector endp 
 ;----------------------------------------------------------------------------
 ;DS:SI points to ASCII string to be printed
 ;----------------------------------------------------------------------------
 dstring proc  near
 push  si
 push  ax
 dis:  mov  al,[si]  ;Fetch the next character
 cmp  al,0  ;If it's zero,we are done
 je  disdone 
 call  dchar  ;If not,point it
 inc  si  ;Advance pointer to nest char
 jmp  dis
 disdone:pop  ax
 pop  si
 ret
 dstring endp
 ;---------------------------------------------------------------------------- 
 ;ES:DX contains double word to be displayed
 ;----------------------------------------------------------------------------
 ddword  proc  near
 push  dx  ;Save offset temporarily
 mov  dx,es  ;Move segment to DX
 call  dsword  ;Display segment
 call  dcolon  ;Print a ";"
;   call  dcrlf
 pop  dx  ;Restore offset to DX
 call  dsword  ;Display offset
 ret
 ddword  endp
 ;----------------------------------------------------------------------------
 ;DX containes single word to be displayed
 ;----------------------------------------------------------------------------
 dsword  proc  near
 push  dx  ;Save low byte temporarily
 mov  dl,dh  ;Move high byte to low byte
 call  dbyte  ;Display high byte
 pop  dx  ;Restore low byte to DL
 call  dbyte  ;Display low byte
 ret
 dsword  endp
 ;----------------------------------------------------------------------------
 ;DL contains byte to be displayed
 ;----------------------------------------------------------------------------
 dbyte  proc  near
 push  ax  ;Save any registers used
 push  dx 
 push  si
 push  dx  ;Save low nybble temporarily
 push  cx  ;Save CX
 mov  cl,4  ;Set shift count to 4
 shr  dx,cl  ;Shift high nybble into low nybble
 and  dx,0fh  ;Mask out all but low nybble
 mov  si,dx  ;Use low nybble as index into
 mov  al,hextab[si]  ;hexadecimal character table
 call  dchar  ;Display character
 pop  cx  ;Restore CX
 pop  dx  ;Restore low nybble
 and  dx,0fh  ;Mask out all but low nybble
 mov  si,dx  ;Use low nybble as an index into
 mov  al,hextab[si]  ;hexadecimal character table
 call  dchar  ;Display character
 pop  si  ;Restore registers
 pop  dx
 pop  ax
 ret
 dbyte  endp
 ;----------------------------------------------------------------------------
 ;Display a ":"
 ;----------------------------------------------------------------------------
 dcolon  proc  near
 mov  al,':'
 call  dchar
 ret
 dcolon  endp
 ;----------------------------------------------------------------------------
 ;Display a " "
 ;----------------------------------------------------------------------------
 dspace  proc  near
 mov  al,' '
 call  dchar
 ret
 dspace  endp
 ;----------------------------------------------------------------------------
 ;Display a Carriage Return/Line Feed
 ;----------------------------------------------------------------------------
 dcrlf  proc  near
 mov  al,0dh
 call  dchar
 mov  al,0ah
 call  dchar
 ret
 dcrlf  endp
 ;----------------------------------------------------------------------------
 ;Display the character contained in AL
 ;----------------------------------------------------------------------------
 dchar  proc  near
 push  ax
 push  bx
 mov  bh,1
 mov  ah,0eh
 int  10h
 pop  bx
 pop  ax
 ret
 dchar  endp
 ;----------------------------------------------------------------------------
 ;Data define
 ;----------------------------------------------------------------------------
 hextab  db  '0123456789ABCDEF',0
 disptab db  05h  ;Print screen
 dw  v05
 db  19h  ;Bootstrap loader
 dw  v19 
 db  08h  ;Timer tick
 dw  v08
 db  1ah  ;Real_time clock
 dw  v1a
 db  09h  ;Keyboard input
 dw  v09 
 db  1bh  ;CTRL_Break handler
 dw  v1b 
 db  0bh  ;Comm.port 1
 dw  v0b 
 db  1ch  ;Timer control
 dw  v1c
 db  0ch  ;Comm.port 0
 dw  v0c
 db  1dh  ;Pointer to vo parameter table
 dw  v1d
 db  0dh  ;Hard disk controller
 dw  v0d
 db  1eh  ;Pointer to disk parameter table
 dw  v1e
 db  0eh  ;Floppy disk controller
 dw  v0e 
 db  1fh  ;Pointer graphics character table
 dw  v1f
 db  0fh  ;Printer controller
 dw  v0f 
 db  20h  ;Program tenate
 dw  v20
 db  10h  ;Video
 dw  v10
 db  21h  ;DOS universal function
 dw  v21
 db  11h  ;Equipment check
 dw  v11 
 db  22h  ;Pointer to termination handler
 dw  v22
 db  12h  ;Memorey size check
 dw  v12
 db  23h  ;Pointer to Ctrl_C handler
 dw  v23
 db  13h  ;Disk driver
 dw  v13
 db  24h  ;Pointer to critical error handler
 dw  v24
 db  14h  ;Communications driver
 dw  v14
 db  25h  ;Absolute disk read
 dw  v25
 db  15h  ;Cassette driver
 dw  v15
 db  26h  ;Absolute disk write
 dw  v26 
 db  16h  ;Keyboard driver
 dw  v16
 db  27h  ;Terminate and stay resident
 dw  v27
 db  17h  ;Printer driver
 dw  v17
 db  2fh  ;Print spooler
 dw  v2f
 db  18h  ;Rom basic
 dw  v18
 db  0
 dw  0
 v05  db  186,5 dup (20h),'Print screen:',26 dup (20h),0
 v08  db  186,5 dup (20h),'Timer tick controller:',17 dup (20h),0
 v09  db  186,5 dup (20h),'Keyboard input:',24 dup (20h),0 
 v0b  db  186,5 dup (20h),'Communication port 1:',18 dup (20h),0
 v0c  db  186,5 dup (20h),'Communication port 0:',18 dup (20h),0
 v0d  db  186,5 dup (20h),'Hard disk controller:',18 dup (20h),0
 v0e  db  186,5 dup (20h),'Floppy disk controller:',16 dup (20h),0
 v0f  db  186,5 dup (20h),'Printer controller:',20 dup (20h),0
 v10  db  186,5 dup (20h),'Video driver:',26 dup (20h),0
 v11  db  186,5 dup (20h),'Equipment check:',23 dup (20h),0 
 v12  db  186,5 dup (20h),'Memory size check:',21 dup (20h),0
 v13  db  186,5 dup (20h),'Disk driver:',27 dup (20h),0
 v14  db  186,5 dup (20h),'Communication driver:',18 dup (20h),0
 v15  db  186,5 dup (20h),'Cassette driver:',23 dup (20h),0
 v16  db  186,5 dup (20h),'Keyboard driver:',23 dup (20h),0
 v17  db  186,5 dup (20h),'Printer driver:',24 dup (20h),0
 v18  db  186,5 dup (20h),'ROM BASIC:',29 dup (20h),0
 v19  db  186,5 dup (20h),'Bootstrap loader:',22 dup (20h),0
 v1a  db  186,5 dup (20h),'Real_time clock:',23 dup (20h),0
 v1b  db  186,5 dup (20h),'Ctrl_break handler:',20 dup (20h),0
 v1c  db  186,5 dup (20h),'Timer control:',25 dup (20h),0
 v1d  db  186,5 dup (20h),'Video parameter table:',17 dup (20h),0
 v1e  db  186,5 dup (20h),'Disk parameter:',24 dup (20h),0
 v1f  db  186,5 dup (20h),'Graphic character table:',15 dup (20h),0
 v20  db  186,5 dup (20h),'Programe terminate:',20 dup (20h),0
 v21  db  186,5 dup (20h),'DOS universal function:',16 dup (20h),0
 v22  db  186,5 dup (20h),'Terminate vector:',22 dup (20h),0
 v23  db  186,5 dup (20h),'Ctrl_C vector:',25 dup (20h),0
 v24  db  186,5 dup (20h),'Critical error vector:',17 dup (20h),0
 v25  db  186,5 dup (20h),'Absolute disk read:',20 dup (20h),0
 v26  db  186,5 dup (20h),'Absolute disk write:',19 dup (20h),0
 v27  db  186,5 dup (20h),'Terminate and stay resident:',11 dup (20h),0
 v2f  db  186,5 dup (20h),'Print spooler:',25 dup (20h),0
 cseg  ends
 end  start

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-958645/,如需轉載,請註明出處,否則將追究法律責任。

相關文章