汇编教程:控制转移(2)
2009-02-16 09:36:49 来源:WEB开发网(9)实模式下的数据和代码段。
该实例的逻辑功能是显示演示代码段执行时的当前特权级CPL。源程序清单如下:
;名称:ASM4.ASM
;功能:演示任务内有特权级变换的转移
;编译:TASM ASM4.ASM
;连接:TLINK /32 ASM4.OBJ
;----------------------------------------------------------------------------
INCLUDE 386SCD.INC
;----------------------------------------------------------------------------
GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位)
;----------------------------------------------------------------------------
;全局描述符表
GDT LABEL BYTE
;空描述符
DUMMY Desc <>
;规范段描述符
Normal Desc <0ffffh,,,ATDW,,>
;视频缓冲区段描述符(DPL=3)
VideoBuf Desc <07fffh,8000h,0bh,ATDW+DPL3,,>
;----------------------------------------------------------------------------
EFFGDT LABEL BYTE
;任务状态段TSS描述符
DemoTSS Desc <DemoTssLen-1,DemoTSSSeg,,AT386TSS,,>
;局部描述符表段的描述符
DemoLDTD Desc <DemoLDTLen-1,DemoLDTSeg,,ATLDT,,>
;临时代码段描述符
TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表长度
GDNum = ($-EFFGDT)/(SIZE Desc) ;需特殊处理的描述符数
;----------------------------------------------------------------------------
Normal_Sel = Normal-GDT ;规范段描述符选择子
Video_Sel = VideoBuf-GDT ;视频缓冲区段描述符选择子
;----------------------------------------------------------------------------
DemoTSS_Sel = DemoTSS-GDT ;任务状态段描述符选择子
DemoLDT_Sel = DemoLDTD-GDT ;局部描述符表段的选择子
TempCode_Sel = TempCode-GDT ;临时代码段的选择子
;----------------------------------------------------------------------------
GDTSeg ENDS ;全局描述符表段定义结束
;----------------------------------------------------------------------------
DemoLDTSeg SEGMENT PARA USE16 ;局部描述符表数据段(16位)
;----------------------------------------------------------------------------
DemoLDT LABEL BYTE ;局部描述符表
;0级堆栈段描述符(32位段)
DemoStack0 Desc <DemoStack0Len-1,DemoStack0Seg,,ATDW+DPL0,D32,>
;1级堆栈段描述符(32位段)
DemoStack1 Desc <DemoStack1Len-1,DemoStack1Seg,,ATDW+DPL1,D32,>
;3级堆栈段描述符(16位段)
DemoStack3 Desc <DemoStack3Len-1,DemoStack3Seg,,ATDW+DPL3,,>
;代码段描述符(32位段,DPL=3)
DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE+DPL3,D32,>
;过渡代码段描述符(32位段)
T32Code Desc <T32CodeLen-1,T32CodeSeg,,ATCE,D32,>
;显示子程序代码段描述符(32位段,DPL=1)
EchoSubR Desc <EchoSubRLen-1,EchoSubRSeg,,ATCER+DPL1,D32,>
;----------------------------------------------------------------------------
DemoLDNum = ($-DemoLDT)/(SIZE Desc)
;----------------------------------------------------------------------------
;0级堆栈描述符选择子(RPL=0)
DemoStack0_Sel = DemoStack0-DemoLDT+TIL+RPL0
;1级堆栈描述符选择子(RPL=1)
DemoStack1_Sel = DemoStack1-DemoLDT+TIL+RPL1
;3级堆栈描述符选择子(RPL=3)
DemoStack3_Sel = DemoStack3-DemoLDT+TIL+RPL3
;代码段描述符选择子(RPL=3)
DemoCode_Sel = DemoCode-DemoLDT+TIL+RPL3
;过渡代码段描述符选择子
T32Code_Sel = T32Code-DemoLDT+TIL
;显示子程序代码段描述符选择子(RPL=1)
Echo_Sel1 = EchoSubR-DemoLDT+TIL+RPL1
;显示子程序代码段描述符选择子(RPL=3)
Echo_Sel3 = EchoSubR-DemoLDT+TIL+RPL3
;----------------------------------------------------------------------------
;指向过渡代码段内T32Begin点的调用门(DPL=0)
ToT32GateA Gate <T32Begin,T32Code_Sel,,AT386CGate,>
;指向过渡代码段内T32End点的调用门(DPL=3)
ToT32GateB Gate <T32End,T32Code_Sel,,AT386CGate+DPL3,>
;指向显示子程序代码段的调用门(DPL=3)
ToEchoGate Gate <EchoSub,Echo_Sel3,,AT386CGate+DPL3,>
;----------------------------------------------------------------------------
DemoLDTLen = $-DemoLDT
;----------------------------------------------------------------------------
;指向过渡代码段内T32Begin点的调用门的选择子
ToT32A_Sel = ToT32GateA-DemoLDT+TIL
;指向过渡代码段内T32End点的调用门的选择子
ToT32B_Sel = ToT32GateB-DemoLDT+TIL
;显示子程序调用门的选择子
ToEcho_Sel = ToEchoGate-DemoLDT+TIL
;----------------------------------------------------------------------------
DemoLDTSeg ENDS ;局部描述符表段定义结束
;----------------------------------------------------------------------------
DemoTSSSeg SEGMENT PARA USE16 ;任务状态段TSS
;----------------------------------------------------------------------------
DD 0 ;Back
DD DemoStack0Len ;0级堆栈指针
DD DemoStack0_Sel ;初始化
DD DemoStack1Len ;1级堆栈指针
DD DemoStack1_Sel ;初始化
DD 0 ;2级堆栈指针
DD 0 ;未初始化
DD 0 ;CR3
DD 0 ;EIP
DD 0 ;EFLAGS
DD 0 ;EAX
DD 0 ;ECX
DD 0 ;EDX
DD 0 ;EBX
DD 0 ;ESP
DD 0 ;EBP
DD 0 ;ESI
DD 0 ;EDI
DD 0 ;ES
DD 0 ;CS
DD 0 ;SS
DD 0 ;DS
DD 0 ;FS
DD 0 ;GS
DD DemoLDT_Sel ;LDT
DW 0 ;调试陷阱标志
DW $+2 ;指向I/O许可位图
DW 0ffffh ;I/O许可位图结束标志
;----------------------------------------------------------------------------
DemoTSSLen = $
;----------------------------------------------------------------------------
DemoTSSSeg ENDS ;任务状态段TSS结束
;----------------------------------------------------------------------------
DemoStack0Seg SEGMENT DWORD STACK USE32 ;0级堆栈段(32位段)
DemoStack0Len = 512
DB DemoStack0Len DUP(?)
DemoStack0Seg ENDS ;0级堆栈段结束
;----------------------------------------------------------------------------
DemoStack1Seg SEGMENT DWORD STACK USE32 ;1级堆栈段(32位段)
DemoStack1Len = 512
DB DemoStack1Len DUP(?)
DemoStack1Seg ENDS ;1级堆栈段结束
;----------------------------------------------------------------------------
DemoStack3Seg SEGMENT DWORD STACK USE16 ;3级堆栈段(16位段)
DemoStack3Len = 512
DB DemoStack3Len DUP(?)
DemoStack3Seg ENDS ;3级堆栈段结束
;----------------------------------------------------------------------------
EchoSubRSeg SEGMENT PARA USE32 ;显示子程序代码段(32位,1级)
ASSUME CS:EchoSubRSeg
;----------------------------------------------------------------------------
Message DB 'CPL=',0 ;显示信息(该代码段可读)
;----------------------------------------------------------------------------
EchoSub PROC FAR
cld
push ebp
mov ebp,esp
mov ax,Echo_Sel1 ;该代码段是可读段
mov ds,ax ;采用RPL=1的选择子
mov ax,Video_Sel
mov es,ax
mov edi,1996
mov esi,OFFSET Message
mov ah,4eh ;置显示属性(红底黄字)
EchoSub1: lodsb
or al,al
jz EchoSub2
stosw
jmp EchoSub1
EchoSub2: mov eax,[ebp+8] ;从堆栈中取调用程序的选择子
and al,3 ;调用程序的CPL在CS的RPL字段
add al,'0'
mov ah,4eh ;置显示属性(红底黄字)
stosw
pop ebp
retf
EchoSub ENDP
;----------------------------------------------------------------------------
EchoSubRLen = $
;----------------------------------------------------------------------------
EchoSubRSeg ENDS ;显示子程序代码段结束
;----------------------------------------------------------------------------
DemoCodeSeg SEGMENT PARA USE32 ;32位代码段(3级)
ASSUME CS:DemoCodeSeg
;----------------------------------------------------------------------------
DemoBegin PROC FAR
CALL32 ToEcho_Sel,0 ;显示当前特权级(变换到1级)
CALL32 ToT32B_Sel,0 ;转到过渡代码段(变换到0级)
DemoBegin ENDP
DemoCodeLen = $
;----------------------------------------------------------------------------
DemoCodeSeg ENDS ;32位代码段结束
;----------------------------------------------------------------------------
T32CodeSeg SEGMENT PARA USE32 ;32位过渡代码段(0级)
ASSUME CS:T32CodeSeg
;----------------------------------------------------------------------------
T32Begin PROC FAR
mov ax,DemoStack0_Sel ;建立0级堆栈
mov ss,ax
mov esp,DemoStack0Len
push DWORD PTR DemoStack3_Sel ;压入3级堆栈指针
push DemoStack3Len
push DWORD PTR DemoCode_SEL ;压入入口点
push OFFSET DemoBegin
retf ;利用RET实现转3级的演示代码
T32Begin ENDP
;----------------------------------------------------------------------------
T32End PROC FAR
JUMP32 TempCode_Sel,<OFFSET ToReal>
T32End ENDP
T32CodeLen = $
;----------------------------------------------------------------------------
T32CodeSeg ENDS
;----------------------------------------------------------------------------
TempCodeSeg SEGMENT PARA USE16 ;16位临时代码段(0级)
ASSUME CS:TempCodeSeg
;----------------------------------------------------------------------------
Virtual PROC FAR
mov ax,DemoTSS_Sel ;装载TR
ltr ax
mov ax,DemoLDT_Sel ;装载LDTR
lldt ax
JUMP16 ToT32A_Sel,0 ;通过调用门转过渡段
ToReal: 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 <SEG Real>,<OFFSET Real>
Virtual ENDP
TempCodeLen = $
;----------------------------------------------------------------------------
TempCodeSeg ENDS
;============================================================================
RDataSeg SEGMENT PARA USE16 ;实方式数据段
VGDTR PDesc <GDTLen-1,> ;GDT伪描述符
SPVar DW ? ;用于保存实方式下的SP
SSVar DW ? ;用于保存实方式下的SS
RDataSeg ENDS
;----------------------------------------------------------------------------
RCodeSeg SEGMENT PARA USE16
ASSUME CS:RCodeSeg,DS:RDataSeg
;----------------------------------------------------------------------------
Start PROC
mov ax,RDataSeg
mov ds,ax
cld
CALL InitGDT ;初始化全局描述符表GDT
mov ax,DemoLDTSeg
mov fs,ax
mov si,OFFSET DemoLDT
mov cx,DemoLDNum
CALL InitLDT ;初始化局部描述符表LDT
mov SSVar,ss
mov SPVar,sp
lgdt QWORD PTR VGDTR ;装载GDTR并切换到保护方式
cli
mov eax,cr0
or al,1
mov cr0,eax
JUMP16 <TempCode_Sel>,<OFFSET Virtual>
Real: mov ax,RDataSeg
mov ds,ax
lss sp,DWORD PTR SPVar ;又回到实方式
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
;----------------------------------------------------------------------------
;入口参数: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
更多精彩
赞助商链接