程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 演示異常處理之實例七

演示異常處理之實例七

編輯:匯編語言

下面給出一個用於模擬異常和演示異常處理的實例。該實例的邏輯功能是,在屏幕上顯示一條提示用戶以按鍵方式選擇異常類型的字符,然後模擬指定的異常。該實例演示內容包括:除法出錯故障處理、溢出陷阱處理、段不存在故障處理、堆棧段出錯處理和通用保護故障處理;還有作為一個獨立任務方式出現的陷阱處理程序。

1.源程序組織和清單
  為了演示以獨立任務方式出現的陷阱處理程序,實例含有兩個任務:演示任務和讀鍵盤任務。實例由如下幾部分組成:

(1)全局描述符表GDT和中斷描述符表IDT;
(2)讀鍵盤任務局部描述符表、任務狀態段、堆棧段和代碼段等;
(3)演示任務的局部描述符表、任務狀態段、堆棧段、代碼段和數據段等;
(4)作為演示任務一部分的有關陷阱處理和故障處理程序的代碼段;
(5)作為演示任務一部分的顯示出錯碼過程的代碼段;
(6)實模式下執行的啟動和結束程序代碼段和數據段。
  在切換到保護模式後,就進入臨時代碼段。為了簡單,演示任務不發生特權級變換。演示步驟如下:

(1)從臨時代碼段轉移到演示代碼段。

(2)做演示准備。把演示任務的LDT選擇子裝入LDTR,並填入TSS,裝載任務寄存器TR,建立演示任務堆棧,設置其它數據段寄存器。

(3)接收要模擬的異常類型號。通過軟中斷指令INT調用讀鍵盤任務完成該步驟。讀鍵盤任務只有在接收到指定的字符後才結束。接收的字符是0、4、B、C和D。

按接收的字符模擬異常。即根據鍵入的字符,執行有關程序片段。在這些片段中,有意安排了能引起有關故障或陷阱的指令。

結束演示,轉臨時代碼段,返回DOS。

程序清單如下:

名稱:ASM7.ASM
功能:模擬異常和演示異常處理
編譯:TASM ASM7.ASM
連接:TLINK ASM7.OBJ
----------------------------------------------------------------------------
INCLUDE     386SCD.INC
----------------------------------------------------------------------------
GDTSeg     SEGMENT PARA USE16        全局描述符表數據段(16位)
----------------------------------------------------------------------------
        全局描述符表GDT
GDT       LABEL  BYTE
        空描述符
DUMMY      Desc  <>
        規范段描述符及選擇子
Normal     Desc  <0ffffh,,,ATDW,,>
Normal_Sel   =    Normal-GDT
        視頻緩沖區段描述符(DPL=3)及選擇子
VideoBuf    Desc  <0ffffh,8000h,0bh,ATDW,,>
VideoBuf_Sel  =    VideoBuf-GDT
----------------------------------------------------------------------------
EFFGDT     LABEL  BYTE
        臨時代碼段描述符及選擇子
TempCode    Desc  <0ffffh,TempCodeSeg,,ATCE,,>
TempCode_Sel  =    TempCode-GDT
        演示代碼段描述符及選擇子
DemoCode    Desc  
DemoCode_Sel  =    DemoCode-GDT
        演示任務局部描述符表段描述符及選擇子
DemoLDT     Desc  
DemoLDT_Sel   =    DemoLDT-GDT
        演示任務TSS段描述符及選擇子
DemoTSS     Desc  
DemoTSS_Sel   =    DemoTSS-GDT
        緩沖數據段描述符及選擇子
XBuffer     Desc  
XBuffer_Sel   =    XBuffer-GDT
        讀鍵盤任務局部描述符表段描述符及選擇子
GKeyLDT     Desc  
GKeyLDT_Sel   =    GKeyLDT-GDT
        讀鍵盤任務TSS段描述符及選擇子
GKeyTSS     Desc  
GKeyTSS_Sel   =    GKeyTSS-GDT
        顯示陷阱處理程序代碼段描述符及選擇子
EchoCode    Desc  
EchoCode_Sel  =    EchoCode-GDT
        顯示出錯碼過程代碼段描述符及選擇子
SubCode     Desc  
SubCode_Sel   =    SubCode-GDT
        其它中斷或異常處理程序代碼段描述符及選擇子
Other      Desc  
Other_Sel    =    Other-GDT
----------------------------------------------------------------------------
GDTLen     =    $-GDT           全局描述符表長度
GDNum      =    ($-EFFGDT)/(SIZE Desc)  需處理基地址的描述符個數
----------------------------------------------------------------------------
GDTSeg     ENDS               全局描述符表段定義結束
----------------------------------------------------------------------------
IDTSeg     SEGMENT PARA USE16        中斷描述符表數據段(16位)
----------------------------------------------------------------------------
IDT       LABEL  BYTE           中斷描述符表
        0號陷阱門描述符(對應除法出錯故障)
        Gate  
        從1--3的3個陷阱門描述符
        REPT  3
        Gate  
        ENDM
        4號陷阱門描述符(對應溢出陷阱)
        Gate  
        從5--0ah的的6個陷阱門描述符
        REPT  6
        Gate  
        ENDM
        0bh號陷阱門描述符(對應段不存在故障)
        Gate  
        0ch號陷阱門描述符(對應堆棧段故障)
        Gate  
        0dh號陷阱門描述符(對應通用保護故障)
        Gate  
        從0eh--0edh的240個陷阱門描述符
        REPT  240
        Gate  
        ENDM
        對應0feh號陷阱門描述符(對應顯示中斷處理程序)
        Gate  
        0ffh號任務門描述符(對應讀鍵盤中斷處理任務)
        Gate  <,GKeyTSS_Sel,,ATTaskGate,>
----------------------------------------------------------------------------
IDTLen     =    $-IDT
----------------------------------------------------------------------------
IDTSeg     ENDS               中斷描述符表段定義結束
----------------------------------------------------------------------------
讀鍵盤任務局部描述符表段
----------------------------------------------------------------------------
GKeyLDTSeg   SEGMENT PARA USE16
----------------------------------------------------------------------------
GLDT      LABEL  BYTE
        代碼段描述符及選擇子
GKeyCode    Desc  <0ffffh,GKeyCodeSeg,,ATCE,,>
GKeyCode_Sel  =    GKeyCode-GLDT+TIL
        堆棧段描述符及選擇子
GKeyStack    Desc  
GKeyStack_Sel  =    GKeyStack-GLDT+TIL
----------------------------------------------------------------------------
GKeyLDNum    =    ($-GLDT)/(SIZE Desc)   需初始化基地址的描述符個數
GKeyLDTLen   =    $             局部描述符表段長度
----------------------------------------------------------------------------
GKeyLDTSeg   ENDS
----------------------------------------------------------------------------
讀鍵盤任務TSS段
----------------------------------------------------------------------------
GKeyTSSSeg   SEGMENT PARA USE16
        DD   0             鏈接字
        DD   ?             0級堆棧指針
        DW   ?,?
        DD   ?             1級堆棧指針
        DW   ?,?
        DD   ?             2級堆棧指針
        DW   ?,?
        DD   0             CR3
        DW   GKeyBegin,0        EIP
        DD   0             EFLAGS
        DD   0             EAX
        DD   0             ECX
        DD   0             EDX
        DD   0             EBX
        DW   GKeyStackLen,0      ESP
        DD   0             EBP
        DD   0             ESI
        DD   0             EDI
        DW   Normal_Sel,0       ES
        DW   GKeyCode_Sel,0      CS
        DW   GKeyStack_Sel,0      SS
        DW   Normal_Sel,0       DS
        DW   Normal_Sel,0       FS
        DW   Normal_Sel,0       GS
        DW   GKeyLDT_Sel,0       LDTR
        DW   0             調試陷阱標志
        DW   $+2            指向I/O許可位圖的偏移
        DB   0ffh           I/O許可位圖結束字節
GKeyTSSLen   =    $
GKeyTSSSeg   ENDS
----------------------------------------------------------------------------
讀鍵盤任務堆棧段
----------------------------------------------------------------------------
GKeyStackSeg  SEGMENT PARA USE16
GKeyStackLen  =    1024
        DB   GKeyStackLen DUP(0)
GKeyStackSeg  ENDS
----------------------------------------------------------------------------
讀鍵盤任務代碼段
----------------------------------------------------------------------------
GKeyCodeSeg   SEGMENT PARA USE16
        ASSUME CS:GKeyCodeSeg,DS:RDataSeg,ES:BufferSeg
----------------------------------------------------------------------------
GKeyBegin    PROC  FAR
        push  ds
        push  es
        push  fs
        push  gs
        mov   ax,Normal_Sel
        mov   ss,ax           准備轉實方式
        mov   eax,cr0
        and   al,11111110b
        mov   cr0,eax          轉實方式
        JUMP16 ,
GetKey:     mov   ax,RDataSeg        實方式
        mov   ds,ax
        mov   ebp,esp          恢復實方式部分現場
        lss   sp,DWORD PTR SPVar
        lidt  QWORD PTR NORVIDTR
        sti
        mov   dx,OFFSET Mess
        mov   ah,9
        int   21h            顯示提示信息
GetKey1:    mov   ah,0
        int   16h            讀鍵盤
        cmp   al,'0'
        jz   GetKey2
        cmp   al,'4'
        jz   GetKey2
        and   al,11011111b       小寫轉大寫
        cmp   al,'B'
        jb   GetKey1
        cmp   al,'D'
        ja   GetKey1          只有[0,4,b,c,d]有效
GetKey2:    mov   dl,al
        mov   ah,2
        int   21h            顯示所按字符
        mov   ax,BufferSeg
        mov   es,ax
        mov   BYTE PTR es:KeyASCII,dl  保存到緩沖數據段
        cli                准備返回保護方式
        lidt  QWORD PTR VIDTR
        mov   eax,cr0
        or   al,1
        mov   cr0,eax
        JUMP16 ,
GetKeyV:    mov   ax,GKeyStack_Sel     又進入保護方式
        mov   ss,ax
        mov   esp,ebp
        pop   gs
        pop   fs
        pop   es
        pop   ds
        iretd
        jmp   GKeyBegin
GKeyBegin    ENDP
----------------------------------------------------------------------------
GKeyCodeLen   =    $
GKeyCodeSeg   ENDS
----------------------------------------------------------------------------
其它中斷或異常處理程序的代碼段
----------------------------------------------------------------------------
OtherCodeSeg  SEGMENT PARA USE16
        ASSUME CS:OtherCodeSeg
----------------------------------------------------------------------------
OtherBegin   PROC  FAR
        mov   si,OFFSET MessOther
        int   0feh           顯示提示信息
        mov   WORD PTR es:[0],ax
        jmp   $             進入無限循環
OtherBegin   ENDP
----------------------------------------------------------------------------
OtherCodeLen  =    $
OtherCodeSeg  ENDS
----------------------------------------------------------------------------
除法出錯故障處理程序代碼段
----------------------------------------------------------------------------
DivCodeSeg   SEGMENT PARA USE16
        ASSUME CS:DivCodeSeg
----------------------------------------------------------------------------
DivBegin    PROC  FAR
        mov   si,OFFSET Mess0
        mov   di,0
        int   0feh           顯示提示信息
        shr   ax,1           處理模擬的除法錯誤
        iretd               返回
DivBegin    ENDP
----------------------------------------------------------------------------
DivCodeLen   =    $
DivCodeSeg   ENDS
----------------------------------------------------------------------------
溢出陷阱處理程序代碼段
----------------------------------------------------------------------------
OFCodeSeg    SEGMENT PARA USE16
        ASSUME CS:OFCodeSeg
----------------------------------------------------------------------------
OFBegin     PROC  FAR
        mov   si,OFFSET Mess4
        mov   di,0
        int   0feh           顯示提示信息
        iretd               返回
OFBegin     ENDP
----------------------------------------------------------------------------
OFCodeLen    =    $
OFCodeSeg    ENDS
----------------------------------------------------------------------------
段不存在故障處理程序代碼段
----------------------------------------------------------------------------
SNPCodeSeg   SEGMENT PARA USE16
        ASSUME CS:SNPCodeSeg
----------------------------------------------------------------------------
SNPBegin    PROC  FAR
        mov   si,OFFSET MessB
        mov   di,0
        int   0feh           顯示提示信息
        pop   eax            彈出出錯代碼
        CALL16 SubCode_Sel,SubBegin   顯示出錯代碼
        pop   eax
        add   eax,2           按模擬的引起段不存在指令
        push  eax            調整返回地址
        iretd
SNPBegin    ENDP
----------------------------------------------------------------------------
SNPCodeLen   =    $
SNPCodeSeg   ENDS
----------------------------------------------------------------------------
堆棧段故障處理程序代碼段
----------------------------------------------------------------------------
SSECodeSeg   SEGMENT PARA USE16
        ASSUME CS:SSECodeSeg
----------------------------------------------------------------------------
SSEBegin    PROC  FAR
        mov   si,OFFSET MessC
        mov   di,0
        int   0feh           顯示提示信息
        pop   eax            彈出出錯代碼
        CALL16 SubCode_Sel,SubBegin   顯示出錯代碼
        pop   eax
        add   eax,4           按模擬的引起堆棧段錯誤的
        push  eax            指令調整返回地址
        iretd
SSEBegin    ENDP
----------------------------------------------------------------------------
SSECodeLen   =    $
SSECodeSeg   ENDS


----------------------------------------------------------------------------
通用保護故障處理程序代碼段
----------------------------------------------------------------------------
GPCodeSeg    SEGMENT PARA USE16
        ASSUME CS:GPCodeSeg
----------------------------------------------------------------------------
GPBegin     PROC  FAR
        push  ebp
        mov   ebp,esp
        push  eax
        push  esi
        push  edi            保護現場
        mov   si,OFFSET MessD
        mov   di,0
        int   0feh           顯示提示信息
        mov   eax,[bp+4]        從堆棧中取出出錯代碼
        CALL16 SubCode_Sel,SubBegin   顯示出錯代碼
        pop   edi
        pop   esi
        pop   eax            恢復部分現場
        add   DWORD PTR [ebp+8],2    按模擬的故障指令調整返回
        pop   ebp            地址
        add   esp,4           廢除堆棧中的出錯代碼
        iretd
GPBegin     ENDP
----------------------------------------------------------------------------
顯示出錯碼過程代碼段
----------------------------------------------------------------------------
SubCodeSeg   SEGMENT PARA USE16
        ASSUME CS:SubCodeSeG
----------------------------------------------------------------------------
SubBegin    PROC               AX中含出錯代碼
        push  ax            保護現場
        push  cx
        push  dx
        push  si
        push  di
        mov   si,OFFSET ErrCode
        mov   dx,ax
        mov   cx,4
SubR1:     rol   dx,4           把16位出錯代碼轉換成4位
        mov   al,dl           十六進制數的ASCII碼並保存
        and   al,0fh
        add   al,30h
        cmp   al,'9'
        jbe   SubR2
        add   al,7
SubR2:     mov   [si],al
        inc   si
        loop  SubR1
        mov   si,OFFSET ErrMess
        Mov   di,80*2          從第二行行首開始
        int   0feh           顯示出錯碼
        pop   di            恢復現場
        pop   si
        pop   dx
        pop   cx
        pop   ax
        retf               返回
SubBegin    ENDP
----------------------------------------------------------------------------
SubCodeLen   =    $
SubCodeSeg   ENDS
----------------------------------------------------------------------------
GPCodeLen    =    $
GPCodeSeg    ENDS
----------------------------------------------------------------------------
實現顯示的陷阱處理程序代碼段
入口參數--DS:SI指向顯示信息串,ES:DI指向顯示緩沖區
----------------------------------------------------------------------------
EchoCodeSeg   SEGMENT PARA USE16
        ASSUME CS:EchoCodeSeg
----------------------------------------------------------------------------
EchoBegin    PROC  FAR
        pushad              保護現場
        cld
        mov   ah,7
        mov   al,20h
        mov   cx,80
        push  di
        rep   stosw           清所在顯示行
        pop   di
Echo1:     lodsb
        or   al,al
        jz   Echo2
        stosw               顯示指定信息串
        jmp   Echo1
Echo2:     popad               恢復現場
        iretd
EchoBegin    ENDP
----------------------------------------------------------------------------
EchoCodeLen   =    $
EchoCodeSeg   ENDS
----------------------------------------------------------------------------
緩沖區數據段
----------------------------------------------------------------------------
BufferSeg    SEGMENT PARA USE16
KeyASCII    DB   ?
Buffer     DB   128 DUP(?)
BufferLen    =    $
BufferSeg    ENDS
----------------------------------------------------------------------------
演示任務局部描述符表段
----------------------------------------------------------------------------
DemoLDTSeg   SEGMENT PARA USE16
----------------------------------------------------------------------------
DLDT      LABEL  BYTE
        演示任務TSS段作為數據段的描述符及選擇子
ToDemoTSS    Desc  
ToDemoTSS_Sel  =    ToDemoTSS-DLDT+TIL
        演示任務堆棧段描述符及選擇子
DemoStack    Desc  
DemoStack_Sel  =    DemoStack-DLDT+TIL
        演示任務數據段描述符及選擇子
DemoData    Desc  
DemoData_Sel  =    DemoData-DLDT+TIL
        除法出錯故障處理程序代碼段描述符及選擇子
Divide     Desc  
Divide_Sel   =    Divide-DLDT+TIL
        溢出陷阱處理程序代碼段描述符及選擇子
OverFlow    Desc  
OF_Sel     =    OverFlow-DLDT+TIL
        段不存在故障處理程序代碼段描述符及選擇子
SNPCode     Desc  
SNP_Sel     =    SNPCode-DLDT+TIL
        堆棧段出錯故障處理程序代碼段描述符及選擇子
SSECode     Desc  
SSE_Sel     =    SSECode-DLDT+TIL
        通用保護故障處理程序代碼段描述符及選擇子
GPCode     Desc  
GP_Sel     =    GPCode-DLDT+TIL
        為模擬段不存在故障而安排的數據段描述符及選擇子
TestNPS     Desc  <0ffffh,,,ATDW-80h,,>
TestNPS_Sel   =    TestNPS-DLDT+TIL
----------------------------------------------------------------------------
DemoLDNum    =    ($-DLDT)/(SIZE Desc)   LDT描述符個數
DemoLDTLen   =$
----------------------------------------------------------------------------
DemoLDTSeg   ENDS
----------------------------------------------------------------------------
演示任務TSS段
----------------------------------------------------------------------------
DemoTSSSeg   SEGMENT PARA USE16
DemoTaskSS   TSS   <>
        DB   0ffh
DemoTSSLen   =    $
DemoTSSSeg   ENDS
----------------------------------------------------------------------------
演示任務的堆棧段
----------------------------------------------------------------------------
DemoStackSeg  SEGMENT PARA USE16
DemoStackLen  =    1024
        DB   DemoStackLen DUP(0)
DemoStackSeg  ENDS
----------------------------------------------------------------------------
演示任務的數據段
----------------------------------------------------------------------------
DemoDataSeg   SEGMENT PARA USE16
Mess0      DB   'Divide Error (Exception 0)',0
Mess4      DB   'Overflow (Exception 4)',0
MessB      DB   'Segment Not Present (Exception 11)',0
MessC      DB   'Stack Segment (Exception 12)',0
MessD      DB   'General Protection (Exception 13)',0
MessOther    DB   'Other Exception',0
ErrMess     DB   'Error Code = '
ErrCode     DB   4 DUP(0),'H',0
DemoDataLen   =    $
DemoDataSeg   ENDS
----------------------------------------------------------------------------
演示任務的代碼段
----------------------------------------------------------------------------
DemoCodeSeg   SEGMENT PARA USE16
        ASSUME CS:DemoCodeSeg,DS:DemoDataSeg
----------------------------------------------------------------------------
DemoBegin    PROC  FAR
        mov   ax,DemoLDT_Sel
        lldt  ax            裝載LDTR
        mov   ax,DemoStack_Sel     置堆棧
        mov   ss,ax
        mov   esp,DemoStackLen
        mov   ax,ToDemoTSS_Sel
        mov   gs,ax           把演示任務LDT選擇子填入TSS
        mov   WORD PTR gs:DemoTaskSS.TRLDTR,DemoLDT_Sel
        mov   ax,DemoTSS_Sel
        ltr   ax            裝載TR
        mov   ax,DemoData_Sel
        mov   ds,ax           裝載其它數據段寄存器
        mov   ax,VideoBuf_Sel
        mov   es,ax
        mov   ax,XBuffer_Sel
        mov   fs,ax
        mov   ax,XBuffer_Sel
        mov   gs,ax
        int   0ffh           接收要模擬的異常類型號
        mov   al,BYTE PTR fs:KeyASCII  按接收的字符模擬異常號
        cmp   al,'0'
        jnz   Demo4
        mov   ax,2000
        mov   cl,2           模擬除法出錯故障
        div   cl            該指令長2字節
        jmp   Over
Demo4:     cmp   al,'4'
        jnz   Demo11
        mov   al,100
        add   al,50
        into               模擬溢出陷阱
        JMP   OVER
Demo11:     cmp   al,'B'
        jnz   Demo12
        mov   ax,TestNPS_Sel      模擬段不存在故障
        mov   gs,ax           該指令長2字節
        JMP   Over
Demo12:     cmp   al,'C'
        jnz   Demo13
        mov   ebp,esp          模擬堆棧出錯故障
        mov   al,[ebp]         該指令長4字節
        jmp   Over
Demo13:     mov   ax,DemoTSS_Sel      模擬通用保護故障
        mov   gs,ax           該指令長2字節
Over:      轉臨時代碼段
        JUMP16 TempCode_Sel,
DemoBegin    ENDP
----------------------------------------------------------------------------
DemoCodeLen   =    $
DemoCodeSeg   ENDS
----------------------------------------------------------------------------
TempCodeSeg   SEGMENT PARA USE16        臨時任務的代碼段
        ASSUME CS:TempCodeSeg
----------------------------------------------------------------------------
Virtual     PROC  FAR
        JUMP16 DemoCode_Sel,DemoBegin  轉演示任務
ToDos:     mov   ax,Normal_Sel       恢復實方式段描述符高速緩存
        mov   ds,ax
        mov   es,ax
        mov   fs,ax
        mov   gs,ax
        mov   ss,ax
        mov   eax,cr0          准備返回實模式
        and   al,11111110b
        mov   cr0,eax
        JUMP16 ,
Virtual     ENDP
----------------------------------------------------------------------------
TempCodeSeg   ENDS
============================================================================
RDataSeg    SEGMENT PARA USE16        實方式數據段
VGDTR      PDesc          GDT偽描述符
VIDTR      PDesc          IDT偽描述符
NORVIDTR    PDesc  <3ffh,>          用於保存原IDTR值
SPVar      DW   ?             用於保存實方式下的SP
SSVar      DW   ?             用於保存實方式下的SS
Mess      DB   'Press a key[0,4,B,C,D]:$'提示信息
RDataSeg    ENDS
----------------------------------------------------------------------------
RCodeSeg    SEGMENT PARA USE16        實方式代碼段
        ASSUME CS:RCodeSeg,DS:RDataSeg
----------------------------------------------------------------------------
Start      PROC
        mov   ax,RDataSeg
        mov   ds,ax
        cld
        call  InitGDT          初始化全局描述符表GDT
        call  InitIDT          初始化中斷描述符表IDT
        mov   ax,GKeyLDTSeg
        mov   fs,ax
        mov   cx,GKeyLDNum
        mov   si,OFFSET GLDT
        CALL  InitLDT
        mov   ax,DemoLDTSeg
        mov   fs,ax
        mov   cx,DemoLDNum
        mov   si,OFFSET DLDT
        CALL  InitLDT
        mov   SSVar,ss         保存堆棧指針
        mov   SPVar,sp
        lgdt  QWORD PTR VGDTR      裝載GDTR
        sidt  QWORD PTR NORVIDTR    保存IDTR
        cli                關中斷
        lidt  QWORD PTR VIDTR      裝載IDTR
        mov   eax,cr0
        or   al,1
        mov   cr0,eax
        JUMP16 ,
Real:      mov   ax,RDataSeg
        mov   ds,ax
        lss   sp,DWORD PTR SPVar    又回到實方式
        lidt  QWORD PTR NORVIDTR
        sti
        mov   ax,4c00h
        int   21h
Start      ENDP
----------------------------------------------------------------------------
InitGDT     PROC
        push  ds
        mov   ax,GDTSeg
        mov   ds,ax
        mov   cx,GDNum
        mov   si,OFFSET EFFGDT
InitG:     mov   ax,[si].BaseL
        movzx  eax,ax
        shl   eax,4
        shld  edx,eax,16
        mov   WORD PTR [si].BaseL,ax
        mov   BYTE PTR [si].BaseM,dl
        mov   BYTE PTR [si].BaseH,dh
        add   si,SIZE Desc
        loop  InitG
        pop   ds
        mov   bx,16
        mov   ax,GDTSeg
        mul   bx
        mov   WORD PTR VGDTR.Base,ax
        mov   WORD PTR VGDTR.Base+2,dx
        ret
InitGDT     ENDP
----------------------------------------------------------------------------
InitIDT     PROC
        mov   bx,16
        mov   ax,IDTSeg
        mul   bx
        mov   WORD PTR VIDTR.Base,ax
        mov   WORD PTR VIDTR.Base+2,dx
        ret
InitIDT     ENDP
----------------------------------------------------------------------------
入口參數:FS:SI=第一個要初始化的描述符,CX=要初始化的描述符數
----------------------------------------------------------------------------
InitLDT     PROC
ILDT:      mov   ax,WORD PTR FS:[si].BaseL
        movzx  eax,ax
        shl   eax,4
        shld  edx,eax,16
        mov   WORD PTR fs:[si].BaseL,ax
        mov   BYTE PTR fs:[si].BaseM,dl
        mov   BYTE PTR fs:[si].BaseH,dh
        add   si,SIZE Desc
        loop  ILDT
        ret
InitLDT     ENDP
----------------------------------------------------------------------------
RCodeSeg    ENDS
        END   Start

2.關於實例七的說明
  上述模擬與演示程序的許多內容與實例六相同,下面就各異常處理程序和讀鍵盤任務的實現作些說明:
(1)除法出錯故障處理程序的實現
  從源程序可見,除法出錯是在執行故意安排的被除數為2000,而除數為2的無符號除指令時引起的。作為演示,除法出錯故障處理程序先顯示一條提示信息,然後把存放被除數AX的內容右移一位,然後就返回。由於除法出錯為故障類異常,所以在故障處理結束後,仍執行該無符號除指令。顯然將再次引起同樣的故障,仍把被除數右移一位。由於每次處理時都把被除數減半,所以幾次故障後就不發生該故障了。

(2)溢出陷阱處理程序的實現
  作為演示的溢出陷阱處理程序較簡單。先顯示一條提示信息,然後就返回。因為溢出異常為陷阱類異常,所以在陷阱處理結束後,就直接返回到引起陷阱指令的下一條指令。

(3)段不存在故障處理程序的實現
  從源程序可見,段不存在故障是在執行故意安排的把一個選擇子送段寄存器GS的指令時引起的。該選擇子索引的描述符中的存在位P被置為0,表示對應段不在內存。在正常情況下,段不存在故障處理程序要把對應的段裝入內存,再把描述符內的P位修改為1,於是,在故障處理結束後,引起故障的指令可得到順序執行。為了簡單,這裡安排的故障處理程序先顯示一條提示信息,然後顯示出錯碼,最後調整堆棧中的返回地址並返回。段不存在故障提供一個出錯碼,該故障處理程序利用POP指令把它用堆棧中彈出,這樣堆棧指針就指向返回地址。由於段不存在異常屬於故障類異常,所以返回點仍是引起故障的指令。因此,演示程序調整了堆棧中的返回地址,使其返回到引起故障的指令的下一條指令。

(4)堆棧段出錯故障處理程序的實現
  引起堆棧出錯故障的原因有多種,實例通過執行故意安排的偏移超過段界限的堆棧段訪問指令來模擬堆棧段出錯故障的產生。作為演示的堆棧出錯故障處理程序比較簡單,先顯示一條信息,然後顯示出錯碼,最後調整堆棧中的返回地址並返回。
(5)通用保護障處理程序的實現
  引起通用保護故障處理程序的原因有多種,實例通過把一個指向系統段描述符的選擇子裝入數據段寄存器GS來模擬通用保護故障的產生。作為演示的通用保護故障處理程序,象上述兩個故障處理程序一樣比較簡單,先顯示一條提示信息,然後顯示出錯碼,最後調整堆棧中的返回地址並返回,但在廢除堆棧中的出錯碼和調整堆棧中的返回地址時采用了其它方法。

(6)異常處理程序的一般說明
  在實例中,通向上述各種異常處理程序的門都是陷阱門。所以,在發生異常而轉入這些異常處理程序時,都不發生任務切換。於是,這些異常處理仍作為演示任務的一部分。

正常情況下,異常處理程序應該注意現場的保護和恢復,但為了簡單,作為演示的異常處理程序沒有能夠切實地保護現場。注意,這些異常處理程序所采用的處理方法與所模擬的指令有關,不適用於一般情況。

(7)顯示出錯代碼的過程
  實例采用一個過程用於顯示出錯代碼,該過程的入口參數是AX含出錯碼。利用該過程不僅縮短程序,而且也用於表現異常處理程序的實現。

(8)讀鍵盤任務的實現
  在實例的IDT中,0FFH號門描述符是任務門,指向一個獨立的任務。該任務的功能是讀鍵盤,接收一個指定范圍內的字符。演示任務通過指令“INT 0FFH”來調用它,接收一個代表需要模擬異常的字符。

為了簡單,該任務在實模式下讀鍵盤,接收指定范圍內的字符。為此,該任務每次經歷如下步驟:(1)轉到實模式。此前要作必要的准備,轉到實模式後,要恢復必須的實模式下的部分現場。(2)接收指定的字符。調用DOS功能顯示提示信息,調用BIOS中斷讀鍵盤,如果在指定范圍內,那麼就顯示,並保存在約定的數據段中。(3)轉回到保護模式,此前也要作必要的准備。


  盡管在任務切換時,自動利用TSS保護和恢復現場,但由於該任務相當於一個讀鍵盤的過程,所以在開始任務時,還通過堆棧保護必要的現場,在結束任務時恢復現場。請特別注意,安排在該任務代碼段中的IRETD指令之後的轉移指令的作用。當執行IRETD指令時,由於NT位為1,所以按反向鏈進行任務切換,同時保存各寄存器到當前的TSS,為了下次進入時仍能從頭開始執行此任務,所以在IRETD後加一條轉移到該任務開頭的指令。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved