这是一段用nasm编写的程序,有2个文件组成,第一个头文件为pm.inc,第2个文件为pmtest.asm,编译成.com文件在DOS下运行。
程序在保护模式打印一串字符串,然后返回实模式退回dos
文件pm.inc:
文件pmtest.asm:
进入保护模式的主要步骤:
1、准备GDT
2、用lgdt加载gdtr
3、打开A20
4、置cr0的PE位
5、跳转,进入保护模式
返回实模式的要点:
首先我们不能从32位代码段返回实模式,只能从16位代码段返回
其次,需要在返回时让寄存器符合实模式的要求。所以上面代码中有一个Normal的描述符,在返回实模式前把对应选择子SelectNormal加载回寄存器,就是以下代码实现的:
mov ax, SelectorNormal
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
然后清除cr0的PE位
接下来有段代码: jmp 0:LABEL_REAL_ENTRY,段地址是0,非常诡异。
其实在之前的这段代码:
43.mov [LABEL_GO_BACK_TO_REAL+3], ax ,把这条指令的段地址已经设置好了。因为实模式跳转指令的机器码
OEAH(1个字节) offset(2个字节) segment(2个字节) 第3个字节开始正好是段地址,实际的代码是:
jmp cs_real_mode:LABEL_REAL_ENTRY
最后程序在dos模拟器的运行结果如下图: