《80x86汇编语言程序设计》保护模式第一个例题

《80x86汇编语言程序设计》保护模式第一个例题的一些个人理解和注视

; 16位偏移的段间直接转移指令的宏定义
jump macro selector, offsetv

	db 0eah					; jmp far 的操作码
	dw offsetv
	dw selector
	
endm

; 字符显示宏指令定义
echoch macro ascii

	mov ah, 2
	mov dl, ascii
	int 21h
	
endm

; 存储段描述符结构类型的定义
descriptor struc

limitl		dw 0				; 段界限低16位
basel		dw 0				; 基地址低16位
basem		db 0				; 基地址中8位
attributes	dw 0				; 段属性,包含段界限高4位
baseh		db 0				; 基地址高8位

descriptor ends

; 伪描述符结构类型的定义
pdesc struc

limit		dw 0				; 16位段界限
base 		dd 0				; 32位基地址

pdesc ends

; 常量定义
atdw = 92h						; 存在的可读写数据段属性值
atce = 98h						; 存在的只执行代码段属性值

.386p

; 数据段
dseg segment use16

gdt		label byte				; 全局描述符表GDT
dummy		descriptor <>				; 空描述符
code		descriptor <0ffffh, , , atce, >		
code_sel 	= code - gdt				; 代码段描述的选择子
datas		descriptor <0ffffh, 0h, 11h, atdw, 0>	
datas_sel 	= datas - gdt				; 源数据段描述符的选择子
datad		descriptor <0ffffh, , , atdw, >		
datad_sel 	= datad - gdt				; 目标数据段描述符的选择子
gdtlen 		= $ - gdt			

vgdtr		pdesc <gdtlen - 1, >			; 伪描述符

bufferlen	= 256					; 缓冲区字节长度
buffer		db bufferlen dup (0)			; 缓冲区

dseg ends

; 代码段
cseg segment use16

		assume cs:cseg, ds:dseg
		
start:

		mov ax, dseg
		mov ds, ax
		
		; 准备要加载到gdtr的伪描述符
		mov bx, 16
		mul bx
		add ax, offset gdt						
		adc dx, 0
		mov word ptr vgdtr.base, ax				
		mov word ptr vgdtr.base + 2, dx			
		
		; 设置代码段描述符
		mov ax, cs
		mul bx									
		mov code.basel, ax	
		mov code.basem, dl
		mov code.baseh, dh
		
		; 设置目标数据段描述符
		mov ax, ds								
		mul bx
		add ax, offset buffer
		adc dx, 0
		mov datad.basel, ax
		mov datad.basem, dl
		mov datad.baseh, dh
		
		; 加载gdtr
		lgdt fword ptr vgdtr
		
		cli 
		call enablea20
		
		; 切换到保护方式
		xchg bx, bx
		mov eax, cr0
		or eax, 1
		mov cr0, eax
		
		; 清指令欲取队列,并真正进入保护方式
		jump <code_sel>, <offset virtual>
		
virtual:
		mov ax, datas_sel
		mov ds, ax
		mov ax, datad_sel
		mov es, ax
		cld
		xor si, si
		xor di, di
		mov cx, bufferlen / 4
		repz movsd
		
		; 切换回实方式
		mov eax, cr0
		and eax, 0fffffffeh
		mov cr0, eax
		
		; 清指令预取队列,进入实方式
		jump <seg real>, <offset real>
		
real:
		call disablea20
		sti
		
		mov ax, dseg
		mov ds, ax
		mov si, offset buffer
		cld 
		mov bp, bufferlen / 16
		
nextline:
		mov cx, 16
		
nextch:
		lodsb
		push ax
		shr al, 4
		call toascii
		xchg bx, bx
		echoch al
		xchg bx, bx
		pop ax
		call toascii
		echoch al
		echoch ' '
		loop nextch
		echoch 0dh
		echoch 0ah
		dec bp
		jnz nextline
		
		mov ax, 4c00h
		int 21h
		
toascii  proc

		and al, 0fh
		add al, 30h
		cmp al, '9'
		jbe quit
		add al, 7
		
quit:
		ret
		
toascii endp
		
enablea20 proc

		push ax
		in al, 92h
		or al, 2
		out 92h, al
		pop ax
		ret
		
enablea20 endp

disablea20 proc
		
		push ax
		in al, 92h
		and al, 0fdh
		out 92h, al
		pop ax
		ret
		
disablea20 endp

cseg ends

end start				

我自己以前的疑问与我自己的答案:

Q:为什么要设置GDTR?

A:应为需要他来找到GDT

Q:

mul bx
什么意思?

A:转换为物理地址,就是段值*16

Q:

jump <code_sel>, <offset virtual>
什么意思?

A:这条指令是在转换到保护模式之前预取到指令队列的,如果不预取,转换到保护模式后系统会把cs中的值以为是选择子,但其实他是段值,就无法执行下一条指令,也就是jmp,所以要预取这条宏,然后执行时把cs设置为选择子,刷新预取指令队列,引用:

“由此可见,执行这条jmp指令时CPU已经处于“保护方式”了(因为cr0中的PE已经被置成“保护方式”)。如果此条jmp指令如果不是在“实方式”下被预取到指令队列中,就无法执行到它,因为“cr0中的PE被置成保护方式”之后,cs中的值仍为实方式的段值,此时将当前ip加1,然后用cs:ip去取下面的这条jmp指令显然会失败,因为此时处于“保护方式”下的cpu会把cs中的内容理解为“选择子”,所以自然无法取得“紧接着的”jmp指令。”

Q:

shr al, 4
啥意思?

A:是要显示其高4位,然后下面pop后显示低四位

Q:

mov ax, datas_sel

什么意思?

A:datas_sel为选择子,值为8,换为二进制是1000,低三位分别是0位、1位为RPL,2位为TI,3~15位是描述符表索引,也即第一个描述符

>>>>>>>>>>>>>>>琐碎记忆>>>>>>>>>>>>>>>>>

保护方式下通过选择子的3~15位来定位在描述符表中的描述符,然后获得基地址、界限、属性

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值