简单的由实模式切换到保护模式的例子, 在MASM9下面写的, 运行的时候必须在Dos下面运行.
 

   保护模式确实是比较复杂啊, 对这个保护模式的复杂度又有了更深刻的理解, 当然这个例子代码不是很长, 只出生后了GDT, 然后在保护模式下写了个字符串而已.. 但是确实是进入了保护模式!
   这个保护模式的复杂, 我觉得一个由于本来保护模式就比较抽象难以理解, 吓到了不少的人, 在一个现在确实很少这方面的资料啊, 能够找到的资料大部分代码都是比较比较陈旧的, 比如用TASM写, 说实话. 这个东西我是从没有倒腾过. 好在语法和MASM差别不是很大, 万幸..
   一步一步的摸索, 遇到很多问题,. 当然也得到了唐老师的悉心指点,和童哥的热心帮助..  灰常给力..
   源码是Masm9下面写的, 也就是VS2008里面Copy出来那个版本了, 谁说写Dos下的程序只能用masm5呢?? 又好东西干嘛不用.. 你可以在这里下载源码的, 只要你电脑上设置好MASM的环境变量, 里面的makefile直接编译就可以的.. 又问题可以发个Email:[email protected]

Protect1.rar

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
;============================================================================
	;简单的切换到保护模式实例
	;MASM9.00  + link 5.60  TAB = 8
	;编译: 	ml /c /omf pm.asm
	;链接:	link pm.obj;
;============================================================================
	.686p
	Include pm.inc				;保护模式的结构定义
	
DataSeg	Segment	use16
GDT	label	byte				;全局描述符表
Dummy:		Descriptor	0, 0, 0		;空的描述符
;============================================================================
;				;段基址	  	;段界限		;属性
CodeDesc:	Descriptor 	0,		0ffffh, 	DA_C	;非一致代码段16位
VideoDesc:	Descriptor	0b8000h,	0ffffh, 	DA_DRW	;显存段(可读写)

GDT_Len		equ	$-GDT			;GDT长度

GDT_Ptr		word	GDT_Len -1		;GDTR伪描述符
		dword	0

SelectorCode	equ	CodeDesc - GDT		;代码段选择子偏移
SelectorVideo	equ	VideoDesc - GDT		;视频段选择子偏移
;============================================================================

DataSeg	Ends
;============================================================================
	;程序入口段, 初始化GDTR 和一个代码段描述符, 然后跳到保护模式
;============================================================================
CodeSeg	Segment	use16				;16位代码段
Jmain	Proc
	
	xor	eax, eax
	mov	ax, DataSeg
	mov	ds, ax
;----------------------------------------------------------------------------
	;初始化	CodeDesc描述符的基址
	xor	eax, eax
	mov	ax, cs
	shl	eax, 4
	mov	word ptr ds:[CodeDesc+2], ax	;段基址低地址
	shr	eax, 16
	mov	byte ptr ds:[CodeDesc+4], al	;段基址高地址低位
	mov	byte ptr ds:[CodeDesc+7], ah	;段基址高地址高位
	
;----------------------------------------------------------------------------
	;初始化并加载GDTR伪描述符	
	xor	eax, eax
	mov	ax, ds
	shl	eax, 4				;GTDR伪描述符的段地址
	add	eax, offset GDT
	mov	dword ptr ds:[GDT_Ptr+2], eax	;GTDR伪描述符基址
	
	lgdt	fword ptr ds:[GDT_Ptr]
;----------------------------------------------------------------------------
	cli
	_EnableA20				;打开A20地址线
	
	mov	eax, cr0
	or	eax, 1
	mov	cr0, eax			;开启Cr0的分段标记正式进入保护模式

	;这行代码有着特殊的意义, 由此进入保护模式	
	Jmp16	SelectorCode,  <offset _Protect >
;----------------------------------------------------------------------------
	;现在已经进入了保护模式(进入历史性的时刻)
;----------------------------------------------------------------------------
	;进入保护模式就写一个字符就可以
_Protect:
	mov	ax, SelectorVideo
	mov	es, ax
	mov	edi, (80*11+40) * 2		;屏幕的第11行第40列
	mov	ah, 0ch				;属性
	mov	al, 'J'				;字符
	mov	word ptr es:[edi], ax		;写入一个字符串 Joen
	add	edi,2
	mov	al, 'o'
	mov	word ptr es:[edi], ax
	add	edi,2
	mov	al, 'e'
	mov	word ptr es:[edi], ax
	add	edi,2
	mov	al, 'n'
	mov	word ptr es:[edi], ax
	
	mov	eax, cr0
	and	al, 0feh			;关闭PE分段位, 进入实模式
	mov	cr0, eax
	
	Jmp16	<SEG _Real>, < offset _Real >	;又跳回实模式
;----------------------------------------------------------------------------
	;又跳回保护模式了
;----------------------------------------------------------------------------
_Real:	mov	ax, cs	
	mov	ds, ax	
	mov	es, ax	
	mov	ss, ax
	_DisableA20				;关闭A20地址线
	sti
	mov	ax, 4c00h
	int	21h				;退出程序
Jmain 	Endp
CodeSeg	Ends
;----------------------------------------------------------------------------
End	Jmain