Chinaunix首页 | 论坛 | 博客
  • 博客访问: 120099
  • 博文数量: 41
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 306
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-01 10:41
文章分类

全部博文(41)

文章存档

2011年(1)

2009年(40)

我的朋友

分类:

2009-04-14 21:27:56

<二>演示32位代码段和16位代码段切换的实例(实例二)

实例二的逻辑功能是,以十六进制数和ASCII字符两种形式显示从内存地址100000H开始的16个字节的内容。
从功能上看,本实例类似于实例一,但在实现方法上却有了改变,它更能反映出实模式和保护模式切换的情况。具体实现步骤是:(1)作切换到保护方式的准备;(2)切换到保护方式的一个32位代码段;(3)把指定内存区域的内容以字节为单位,转换成对应的十六进制数的ASCII码,并直接填入显示缓冲区实现显示;(4)再变换到保护方式下的一个16位代码段;(5)把指定内存区域的内容直接作为ASCII码填入显示缓冲区中实现显示;(6)切换回实模式。

1.实例二源程序

实例二的源程序如下所示:
 

;名称:ASM2.ASM
;功能:演示实方式和保护方式切换(切换到32位代码段)
;----------------------------------------------------------------------------
INCLUDE 386SCD.INC
;----------------------------------------------------------------------------
DSEG SEGMENT USE16 ;16位数据段
;----------------------------------------------------------------------------
GDT LABEL BYTE ;全局描述符表
DUMMY Desc <> ;空描述符
Normal Desc <0ffffh,,,ATDW,,> ;规范段描述符
Code32 Desc <C32Len-1,,,ATCE,D32,> ;32位代码段描述符
Code16 Desc <0ffffh,,,ATCE,,> ;16位代码段描述符
DataS Desc <DataLen-1,0,10h,ATDR,,> ;源数据段描述符
DataD Desc <3999,8000h,0bh,ATDW,,> ;显示缓冲区描述符
Stacks Desc <StackLen-1,,,ATDW,,> ;堆栈段描述符
;----------------------------------------------------------------------------
GDTLen = $-GDT ;全局描述符表长度
VGDTR PDesc <GDTLen-1,> ;伪描述符
;----------------------------------------------------------------------------
SaveSP DW ? ;用于保存SP寄存器
SaveSS DW ? ;用于保存SS寄存器
;----------------------------------------------------------------------------
Normal_Sel = Normal-GDT ;规范段描述符选择子
Code32_Sel = Code32-GDT ;32位代码段选择子
Code16_Sel = Code16-GDT ;16位代码段选择子
DataS_Sel = Datas-GDT ;源数据段选择子
DataD_Sel = DataD-GDT ;目标数据段选择子
Stacks_Sel = Stacks-GDT ;堆栈段描述符选择子
;----------------------------------------------------------------------------
DataLen = 16
;----------------------------------------------------------------------------
DSEG ENDS ;数据段定义结束
;----------------------------------------------------------------------------
StackSeg SEGMENT PARA STACK USE16
StackLen = 256
                DB StackLen DUP(0)
StackSeg ENDS
;----------------------------------------------------------------------------
CSEG1 SEGMENT USE16 'REAL' ;16位代码段
                ASSUME CS:CSEG1,DS:DSEG
;----------------------------------------------------------------------------
Start PROC
                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
                ;设置32位代码段描述符
                mov ax,CSEG2
                mul bx
                mov WORD PTR Code32.BaseL,ax
                mov BYTE PTR Code32.BaseM,dl
                mov BYTE PTR Code32.BaseH,dh
                ;设置16位代码段描述符
                mov ax,CSEG3
                mul bx
                mov WORD PTR Code16.BaseL,ax ;代码段开始偏移为0
                mov BYTE PTR Code16.BaseM,dl ;代码段界限已在定义时设置好
                mov BYTE PTR Code16.BaseH,dh
                ;设置堆栈段描述符
                mov ax,ss
                mov WORD PTR SaveSS,ax
                mov WORD PTR SaveSP,sp
                mov ax,StackSeg
                mul bx
                mov WORD PTR Stacks.BaseL,ax
                mov BYTE PTR Stacks.BaseM,dl
                mov BYTE PTR Stacks.BaseH,dh
                ;加载GDTR
                lgdt QWORD PTR VGDTR
                cli ;关中断
                EnableA20 ;打开地址线A20
                ;切换到保护方式
                mov eax,cr0
                or al,1
                mov cr0,eax
                ;清指令预取队列,并真正进入保护方式
                JUMP16 Code32_Sel,<OFFSET SPM32>
ToReal: ;现在又回到实方式
                mov ax,DSEG
                mov ds,ax
                mov sp,SaveSP
                mov ss,SaveSS
                DisableA20
                sti
                mov ax,4c00h
                int 21h
Start ENDP
;----------------------------------------------------------------------------
CSEG1 ENDS ;代码段定义结束
;----------------------------------------------------------------------------
CSEG2 SEGMENT USE32 'PM32'
                ASSUME CS:CSEG2
;----------------------------------------------------------------------------
SPM32 PROC
                mov ax,Stacks_Sel
                mov ss,ax
                mov esp,StackLen
                mov ax,DataS_Sel
                mov ds,ax
                mov ax,DataD_Sel
                mov es,ax
                xor esi,esi
                xor edi,edi
                mov ecx,DataLen
                cld
Next: lodsb
                push ax
                CALL ToASCII
                mov ah,7
                shl eax,16
                pop ax
                shr al,4
                CALL ToASCII
                mov ah,7
                stosd
                mov al,20h
                stosw
                loop Next
                JUMP32 Code16_Sel,<OFFSET SPM16>
SPM32 ENDP
;----------------------------------------------------------------------------
ToASCII PROC
                and al,00001111b
                add al,30h
                cmp al,39h
                jbe Isdig
                add al,7
IsDig: ret
ToASCII ENDP
;----------------------------------------------------------------------------
C32Len = $
;----------------------------------------------------------------------------
CSEG2 ENDS
;----------------------------------------------------------------------------
CSEG3 SEGMENT USE16 'PM16'
                ASSUME CS:CSEG3
;----------------------------------------------------------------------------
SPM16 PROC
                xor si,si
                mov di,DataLen*3*2
                mov ah,7
                mov cx,DataLen
AGain: lodsb
                stosw
                loop AGain
                mov ax,Normal_sel
                mov ds,ax
                mov es,ax
                mov ss,ax
                mov eax,cr0
                and al,11111110b
                mov cr0,eax
                jmp FAR PTR ToReal
SPM16 ENDP
;----------------------------------------------------------------------------
CSEG3 ENDS
;----------------------------------------------------------------------------
                END Start

2.关于实现步骤的注释

(1)切换到保护模式的准备工作

建立全局描述符表,这里的全局描述符表含有两个16位数据段的描述符、一个16位代码段的描述符和一个16位的堆栈段描述符。此外,GDT中还有一个32位的代码段描述符,描述32位代码段,该描述符的属性字段中的D位为1。

(2)由实模式切换到保护模式

由实模式切换到保护模式32位代码段的方法与切换到16位代码段的方法相同。由保护模式16位代码段切换回实模式的方法与实例一相似。
在保护模式下,通过如下直接段间转移指令从32位代码段切换到16位代码段:

JUMP32 Code16_Sel,<OFFSET SPM16>

从该宏指令的定义可知,该转移指令含48位指针,其高16位是16位代码段的选择子,低32位是16位代码段的入口偏移。该指令在32位方式下预取并执行。由于在32位方式下执行,所以要使用48位指针。

(3)显示指定内存区域的内容

在本实例中,采用直接写显示缓冲区的方法实现显示。假设显示缓冲区的开始物理地址是0B8000H, 3号文本显示模式,在屏幕的第一行进行显示。

3.特别说明

本实例在保护方式下使用了涉及堆栈操作的指令,因此建立了一个16位的保护模式下的堆栈段。
本实例仍作了大量的简化处理。如:没有建立IDT和LDT等,各特权级均是0。也没有采用分页管理机制。
从本实例的GDT中可见,两个数据段的界限都是根据实际大小而设置的。从源程序代码段CSEG3可见,在切换到实模式之前,把一个指向似乎没有用的数据段的描述符Normal的选择子装载到DS和ES。这是为什么呢?
实模
式下
段描
述符
高速
缓冲
寄存
器的
内容
段寄存器 段基地址 段界限(固定) 段属性(固定)
存在性 特权级 已存取 粒度 扩展方向 可读性 可写性 可执行 堆栈大小 一致特权
CS 当前CS*16 0000FFFFH Y 0 Y B U Y Y Y - N
SS 当前SS*16 0000FFFFH Y 0 Y B U Y Y N W -
DS 当前DS*16 0000FFFFH Y 0 Y B U Y Y N - -
ES 当前ES*16 0000FFFFH Y 0 Y B U Y Y N - -
FS 当前FS*16 0000FFFFH Y 0 Y B U Y Y N - -
GS 当前GS*16 0000FFFFH Y 0 Y B U Y Y N - -


 

在分段管理机制一文中已介绍过,每个段寄存器都配有段描述符高速缓冲寄存器,这些高速缓冲寄存器在实方式下仍发挥作用,只是内容上与保护模式下有所不同。如上表所示,其中“Y”表示“是”; “N”表示“否”;“B”表示字节;“U”表示向上扩展,“W”表示以字方式操作堆栈。段基地址仍是 32位,其值是相应段寄存器值(段值)乘以16,在把段值装载到段寄存器时刷新。由于其值是16位段值乘上16,所以在实模式下基地址实际上有效位只有20位。每个段的32位段界限都固定为0FFFFH,段属性的许多位也是固定的。所谓固定是指在实方式下不可设置这些属性值,只能继续沿用保护方式下所设置的值。因此,在准备结束保护模式回到实模式之前,要通过加载一个合适的描述符选择子到有关段寄存器,以使得对应段描述符高速缓冲寄存器中含有合适的段界限和属性。本实例GDT中的描述符Normal就是这样一个描述符,在返回实模式之前把对应选择子Normal_Sel加载到DS和ES就是此目的。由于SS段描述符中的内容已符合实模式的需要,所以尽管也改变了SS,但不需要重新加载SS(本实例中重新加载了SS,这除了稍增加运行时间外,并没有什么坏处)。16位代码段描述符中的内容也符合实模式的需要,所以在通过16位代码段返回实模式时,CS段描述符中的内容也符合实模式的要求。需要注意的是,不能从32位代码段返回实模式,这是因为无法实现从32位代码段返回时CS高速缓冲寄存器中的属性符合实模式的要求(实模式不能改变段属性)。顺便说以下,实例一中的描述符都是符合实模式要求的。段描述符高速缓冲寄存器中含有合适的段界限

4.关于32位代码段程序设计的说明

在32位代码段中,缺省的操作数大小是32位,缺省的存储单元地址大小是32位。由于串操作指令使用的指针寄存器是ESI和EDI,LOOP指令使用的计数器是ECX,所以,在代码段CSEG2中,为了使用串操作指令,对ESI和EDI等寄存器赋初值。请比较代码段CSEG3中的相关片段和实例一中的相关片段,它们是16位代码段。


 

参考资料 书        名 出  版  社 作    者
《保护方式下的80386及其编程》 清华大学出版社 周明德主编
《80X86汇编语言程序设计教程》 清华大学出版社 扬季文主编
阅读(1093) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~