为什么不能从32位的保护模式直接跳转到实模式,而要先跳转到16位的保护模式,再从16位的保护模式跳转到实模式的理解
不能从32位代码段返回实模式,而只能从16位代码段返回。
原因:(书中说的)因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)
下面具体的来进行分析:
;****************注意在此用normal选择子对段寄存器进行填充******************************
mov ax, SelectorNormal
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
从上述代码可以看出:ds,es,fs,gs,ss这些段寄存器对应的段描述符高速缓冲寄存器(关于什么是段描述符高速缓冲寄存器,请看这篇文章《段描述符高速缓冲寄存器介绍》)中的内容可以通过加载normal选择子而得到更新,当向这几个段寄存器中装入normal选择子时,会自动地将normal对应的描述符装载到描述符高速缓冲寄存器中,因normal选择子所对应的描述符的属性符合实模式下的要求,即:段界限为ffffh,段属性也是固定的。
但是:CS寄存器是不可以通过装载normal来更新CS对应的高速缓冲寄存器的,为什么?你能写出这样的指令吗:MOV CS,SelectorNormal,汇编中没有这样的指令。
即然这样,那怎么可以让CS对应的高速缓冲寄存器中的内容符合实模式的要求呢?
方法是这样的:因为CS的值只能通过jmp,call这样的指令去改变,所以,定义一个16位的代码段,这个代码段的描述符定义为:段界限0ffffh,段属性:存在的只执行代码段 DA_C
假设这个代码段的选择子为:SelectorCode16,偏移地址为:offsetaddr
用一条转移指令向这段代码跳转:jmp SelectorCode16:offsetaddr
因现在处于保护模式,所以jmp指令执行的结果是将SelectorCode16对应的描述符装入cs对应的描述符高速缓冲寄存器中,这个描述符就是符合实模式要求的。这样,CS段寄存器对应的高速缓冲寄存器中的内容终于达到实模式的要求了,所以现在可以进行从保护模式到实模式跳转了,再用一条jmp语句就可以从保模式跳转到实模式了,下边的代码是所定义的一个16位的代码段:
;16位代码段,由32位代码段跳入,跳出后到实模式 [SECTION .s16code] ALIGN 32 [BITS 16] LABEL_SEG_CODE16: ;跳回实模式: 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 ;段地址会在程序开始处被设置成正确的值 ,(看下边的代码)
开始处的代码如下:
LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 0100h mov [LABEL_GO_BACK_TO_REAL+3], ax ;设置正确的返回实模式时的段寄存器值