摘要:本节,我们将通过分析pmtest4来实现利用调用门进行段间转移。
一、背景与原理
在汇编语言中,我们不能执行这样的指令:mov ds 100h和mov cs,ax;也就是说,段寄存器的值,是不能像通用寄存器一样,随意赋值的。具体的cs寄存器而言,它涉及到程序的控制转移,需要借助jmp、call、ret、sysenter,sysexit,int n,iret来实现,或者通过中断和异常来完成。我们知道,jmp和call指令,实现的跳转形式如下jmp selector:offset,其中,selector可以指向:
2)调用门描述符(->目标代码段选择子)
3)TSS(->目标代码段选择子)
4)任务门(->tss-->目标代码段)
其中第一类属于直接转移,剩下三种属于简介转移。
我们知道,通过jmp和call指令的一般转移,对于非一致性代码段,只能在同特权级之间进行。如果想在不同特权级之间自由切换,需要借助门描述符或者TSS。门描述符有任务门、中断门、陷阱门、异常门:其中中断门和陷阱门属于特殊的调用门。门描述符(目标选择子+入口地址+属性)的结构可以参考这里:http://blog.youkuaiyun.com/trochiluses/article/details/20312479
但是,call和jmp在控制转移的时候,作用不是完全相同的,如果代码段A通过调用门G转移到代码段B,call和jmp对应的特权级规则如下:
也就是说,通过call和调用门,可以实现从低特权级转移到高特权级。
2.程序流程概览:
pmtest4这个程序,我们主要将讲解如何通过调用门实现,低特权级代码向高特权级别的代码转移——就像鲤鱼越龙“门”。
保护模式下32b代码段:打印初始化字符,通过调用门,进入目标代码段32b
目标代码段:打印字符C,然后通过retf指令,返回32b代码段
32b代码段:通过jmp,进入LDT中的codeA段,、
LDT中的codeA段:打印字符L,通过jmp指令,回到16b代码段
16b代码段:回到实模式下
通过以上分析,我们知道:只需要在pmtest3的代码中添加目标代码段和门描述符就可以了。
二、代码解惑
按照以往的惯例,我们仍然采用分段的方式,分析代码:
1.GDT中注意:
上述多了一个调用门的选择子和描述符,它也被放在GDT之中
2.调用门目标段中的retf指令和ret指令有哪些不同?
retf指令的意义
ret 弹出一个参数,给ip,返回
retf 弹出2个参数,一个给 ip,一个给 cs
iref 弹出 3个参数,一个给 ip,一个 给 cs ,一个 给 flag标志位
他们都是返回调用点的,看你调用的时候,用的什么调用的,是 call 段内转移 ,还是call 段间转移,还是int 调用中断。
3.对于实模式第一个段的分析:
1)、为什么需要在这里初始化各个段描述符的相关属性呢?
答:开始,没有进入保护模式。同时CS的值已经被刷新。目前,程序运行的代码已经被dos加载到内存的相关部分,GDT的表才刚刚落户,所以我们才刚刚得到GDT的基地址,所以我们在这个时候刷新各个段的描述符属性。
2)、为何要加载GDT?
加载GDT是能够进行保护模式寻址的关键,不然我们仅仅知道段选择子,还是没法找到段描述符。GDTR中包含32b段基地址和16b段限长,这一点我们已经在gdt段中定义过了。
3)、重新回到实模式以后,是否有必要刷新ds、es、ss、sp等?
这是程序编写的一般流程,即使不刷新,也不一定会产生错误,我们可以亲自尝试一下。
4.保护模式
1)、这个段完成了什么功能?
显示初始化的字符串;通过调用门完成打印字母‘C’;通过跳入局部任务,打印字母‘L’;定义了一个局部程序DisplayReturn
2)、为什么要在jmp之前,设置ldt?
和GDT的设定是同样的道理。
实际代码如下:
%include "head.inc"
org 0100h
jmp LABEL_BEGIN
[SECTION .gdt]
;GDT base, length, attr
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW
LABEL_DESC_CODE16: Descriptor 0, 0FFFFH, DA_C
LABEL_DESC_DATA: Descriptor 0, SegDataLen-1, DA_DRW
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len-1, DA_C+DA_32
LABEL_DESC_CODE_DEST: Descriptor 0, SegCodeDestLen-1,DA_C+DA_32
LABEL_DESC_LDT: Descriptor 0, LDTLen-1, DA_LDT
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
LABEL_CALL_GATE_TEST: Gate SelectorCodeDest,0,0,DA_386CGate + DA_DPL0
GdtLen equ $-LABEL_GDT
GdtPtr dw GdtLen-1;注意,长度都是实际长度减1
dd 0 ;段基地址,注意,这里之所以没有直接制定,是因为还没有确定保护模式下gdt的基地址
;选择子
SelectorData equ LABEL_DESC_DATA - LABEL_GDT
SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT
SelectorLDT equ LABEL_DESC_LDT - LABEL_GDT
SelectorCodeDest equ LABEL_DESC_CODE_DEST - LABEL_GDT
SelectorCallGateTest equ LABEL_CALL_GATE_TEST - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
;end of section gdt
;--------------------------------------------------------------
[SECTION .data]
[BITS 32]
ALIGN 32
LABEL_SEG_DATA:
SPValueInRealModel dw 0
PMMessage: db "Coming into protect mode now !",0
OffsetPMMessage equ PMMessage - $$
StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0
OffsetStrTest equ StrTest - $$
SegDataLen equ $ - LABEL_SEG_DATA
;end of section data
;-----------------------------section:global stack------------------
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_SEG_STACK:
times 512 db 0
TopOfStack equ $-LABEL_SEG_STACK-1
;----------------------section:LDT----------------------------------
[SECTION .ldt]
align 32
[bits 32]
LABEL_SEG_LDT:
LABEL_DESC_CODEA: Descriptor 0,CodeALen -1,DA_C+DA_32
LDTLen equ $- LABEL_SEG_LDT
SelectorCodeA equ LABEL_DESC_CODEA - LABEL_SEG_LDT + SA_TIL
;end of ldt segment
;-------------------------------section:codeA------------------------
[section .codeA]
align 32
[bits 32]
LABEL_SEG_CODEA:
mov ax,SelectorVideo
mov gs,ax
mov ah,0ch
mov al,'L'
mov edi,(2*80+0)*2
mov [gs:edi],ax
jmp SelectorCode16:0
CodeALen equ $-LABEL_SEG_CODEA
;end of secion codeA
;------------------------------section:s16 begin---------------------
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
xchg bx,bx
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,0100h
mov [LABEL_GO_BACK_TO_REAL+3],ax
mov [SPValueInRealModel],sp
;for segment code32
xor eax,eax
mov eax,cs
shl eax,4
add eax,LABEL_SEG_CODE32;
mov word [LABEL_DESC_CODE32 +2],ax
shr eax,16
mov byte [LABEL_DESC_CODE32 + 4],al
mov byte [LABEL_DESC_CODE32 + 7],ah
;for segment code16
xor eax,eax
mov ax,cs
shl eax,4
add eax,LABEL_SEG_CODE16;
mov word [LABEL_DESC_CODE16 +2],ax
shr eax,16
mov byte [LABEL_DESC_CODE16 + 4],al
mov byte [LABEL_DESC_CODE16 + 7],ah
;for segment data
xor eax,eax
mov eax,ds
shl eax,4
add eax,LABEL_SEG_DATA;
mov word [LABEL_DESC_DATA +2],ax
shr eax,16
mov byte [LABEL_DESC_DATA + 4],al
mov byte [LABEL_DESC_DATA + 7],ah
;for segment ldt
xor eax,eax
mov eax,ds
shl eax,4
add eax,LABEL_SEG_LDT;
mov word [LABEL_DESC_LDT +2],ax
shr eax,16
mov byte [LABEL_DESC_LDT + 4],al
mov byte [LABEL_DESC_LDT + 7],ah
;for segment codeA
xor eax,eax
mov eax,ds
shl eax,4
add eax,LABEL_SEG_CODEA;
mov word [LABEL_DESC_CODEA +2],ax
shr eax,16
mov byte [LABEL_DESC_CODEA + 4],al
mov byte [LABEL_DESC_CODEA + 7],ah
;for segment stack
xor eax,eax
mov eax,ds
shl eax,4
add eax,LABEL_SEG_STACK;
mov word [LABEL_DESC_STACK +2],ax
shr eax,16
mov byte [LABEL_DESC_STACK+ 4],al
mov byte [LABEL_DESC_STACK+ 7],ah
;no need for video base
;for segment dstcode
xor eax,eax
mov ax,cs
shl eax,4
add eax,LABEL_SEG_CODE_DEST
mov word [LABEL_DESC_CODE_DEST +2],ax
shr eax,16
mov byte [LABEL_DESC_CODE_DEST +4],al
mov byte [LABEL_DESC_CODE_DEST +7],ah
xor eax,eax
mov ax,ds
shl eax,4
add eax, LABEL_GDT
mov dword [GdtPtr +2 ],eax
lgdt [GdtPtr]
cli
in al,92h
or al,02h
out 92h,al
mov eax,cr0
or eax,1
mov cr0,eax
jmp dword SelectorCode32:0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LABEL_REAL_ENTRY: ;come here from protect model
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,[SPValueInRealModel]
in al,92h
and al,11111101b
out 92h,al
sti
mov ax,4c00h
int 21h
;end of section .s16
;------------------------section:code32,start of protect model--------
[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
mov ax,SelectorVideo
mov gs,ax
mov ax,SelectorData
mov ds,ax
mov ax,SelectorStack
mov ss,ax
mov esp,TopOfStack
mov ah,0ch
xor esi,esi
xor edi,edi
mov esi,OffsetPMMessage
mov edi,(80*11+0)*2
cld
.loopPmMessage:
lodsb
test al,al
jz .end
mov [gs:edi],ax
add edi,2
jmp .loopPmMessage
.end: ;
call DispReturn
call SelectorCallGateTest:0
;Load LDT
mov ax,SelectorLDT
lldt ax
jmp SelectorCodeA:0
;function: read and print 8 byte from es:0
TestRead:
xor esi,esi
mov ecx,8
.loopForEightBype:
mov al,[es:esi]
call DispAL
inc esi
loop .loopForEightBype
call DispReturn
ret; be sure of this
;funtion:
;write 8byte to es:OffsetStrTest
;input:es
TestWrite:
push esi
push edi
xor esi,esi
xor edi,edi
mov esi,OffsetStrTest
cld
.loopForEightBype:
lodsb ;ds:si->al
test al,al
jz .end
mov [es:edi],al
inc edi
jmp .loopForEightBype
.end:
pop edi
pop esi
ret
;funtion DispAL
; display the number in AL
;input: AL-the number
; edi-the position to display
;modified:ax,edi
DispAL:
push ecx
push edx
mov ah,0ch
mov dl,al
shr al,4
mov ecx,2
.begin:
and al,01111b
cmp al,9
ja .moreThanNine
add al,'0'
jmp .end
.moreThanNine:
sub al,0ah
add al,'A'
.end:
mov [gs:edi],ax
add edi,2
mov al,dl
loop .begin
add edi,2
pop edx
pop ecx
ret
;DispAL
;function DispReturn
;if edi=(a*80 + b)*2
;then edi=(a*80 + 80)*2
DispReturn:
push eax
push ebx
mov eax,edi
mov bl,160
div bl
and eax,0ffh;
inc eax
mov bl,160
mul bl
mov edi,eax
pop ebx
pop eax
ret
;end for function DispReturn
SegCode32Len equ $-LABEL_SEG_CODE32
;end of section .s32
;---------------------section s16code,before return to real-----------
[SECTION .s16code]
ALIGN 32
[BITS 16]
LABEL_SEG_CODE16:
;return to real model
mov ax,SelectorNormal
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov eax,cr0
and al,11111110b
mov cr0,eax
LABEL_GO_BACK_TO_REAL:
jmp 0:LABEL_REAL_ENTRY;
Code16Len equ $-LABEL_SEG_CODE16
;end of section s16code
;---------------------section:sdest---------------------------------
[section .sdest]
[bits 32]
LABEL_SEG_CODE_DEST:
mov ax,SelectorVideo
mov gs,ax
mov edi,(80*12+0)*2
mov ah,0ch
mov al,'C'
mov [gs:edi],ax
retf
SegCodeDestLen equ $-LABEL_SEG_CODE_DEST