演示异常处理之实例七
2009-02-16 09:36:51 来源:WEB开发网下面给出一个用于模拟异常和演示异常处理的实例。该实例的逻辑功能是,在屏幕上显示一条提示用户以按键方式选择异常类型的字符,然后模拟指定的异常。该实例演示内容包括:除法出错故障处理、溢出陷阱处理、段不存在故障处理、堆栈段出错处理和通用保护故障处理;还有作为一个独立任务方式出现的陷阱处理程序。
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
更多精彩
赞助商链接