首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 汇编语言 >

一个关于实模式转到保护模式的有关问题

2012-02-06 
一个关于实模式转到保护模式的问题先看网上很多介绍的一个程序:名称:ASM1.ASM功能:演示实方式和保护方式

一个关于实模式转到保护模式的问题
先看网上很多介绍的一个程序:
;名称:ASM1.ASM
;功能:演示实方式和保护方式切换(切换到16位代码段)
;----------------------------------------
INCLUDE                   386SCD.INC
;----------------------------------------
;字符显示宏指令的定义
;----------------------------------------
EchoCh                     MACRO       ascii
                                mov           ah,2
                                mov           dl,ascii
                                int           21h
                                ENDM
;----------------------------------------
DSEG                         SEGMENT   USE16                                   ;16位数据段
;----------------------------------------
GDT                           LABEL       BYTE                                     ;全局描述符表
DUMMY                       Desc         <>                                         ;空描述符
Code                         Desc         <0ffffh,,,ATCE,,>           ;代码段描述符
DataS                       Desc         <0ffffh,0,11h,ATDW,,>   ;源数据段描述符
DataD                       Desc         <0ffffh,,,ATDW,,>           ;目标数据段描述符
;----------------------------------------
GDTLen                     =               $-GDT                                   ;全局描述符表长度
VGDTR                       PDesc       <GDTLen-1,>                       ;伪描述符
;----------------------------------------
Code_Sel                 =               Code-GDT                             ;代码段选择子
DataS_Sel               =               Datas-GDT                           ;源数据段选择子


DataD_Sel               =               DataD-GDT                           ;目标数据段选择子
;----------------------------------------
BufLen                     =               256                                       ;缓冲区字节长度
Buffer                     DB             BufLen   DUP(0)                   ;缓冲区
;----------------------------------------
DSEG                         ENDS                                                     ;数据段定义结束
;----------------------------------------
CSEG                         SEGMENT   USE16                                   ;16位代码段
                                ASSUME     CS:CSEG,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
                                ;设置代码段描述符


                                mov           ax,cs
                                mul           bx
                                mov           WORD   PTR   Code.BaseL,ax   ;代码段开始偏移为0
                                mov           BYTE   PTR   Code.BaseM,dl   ;代码段界限已在定义时设置好
                                mov           BYTE   PTR   Code.BaseH,dh
                                ;设置目标数据段描述符
                                mov           ax,ds
                                mul           bx                                           ;计算并设置目标数据段基址
                                add           ax,OFFSET   Buffer
                                adc           dx,0
                                mov           WORD   PTR   DataD.BaseL,ax
                                mov           BYTE   PTR   DataD.BaseM,dl
                                mov           BYTE   PTR   DataD.BaseH,dh
                                ;加载GDTR
                                lgdt         QWORD   PTR   VGDTR
                                cli                                                         ;关中断
                                EnableA20                                             ;打开地址线A20
                                ;切换到保护方式
                                mov           eax,cr0


                                or             eax,1
                                mov           cr0,eax
                                ;清指令预取队列,并真正进入保护方式
                                JUMP16     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,BufLen/4                         ;设置4字节为单位的缓冲区长度
                                repz         movsd                                     ;传送
                                ;切换回实模式
                                mov           eax,cr0
                                and           al,11111110b
                                mov           cr0,eax
                                ;清指令预取队列,进入实方式
                                JUMP16     <SEG   Real> , <OFFSET   Real>


Real:                       ;现在又回到实方式
                                DisableA20
                                sti
                                mov           ax,DSEG
                                mov           ds,ax
                                mov           si,OFFSET   Buffer
                                cld
                                mov           bp,BufLen/16
NextLine:               mov           cx,16
NextCh:                   lodsb
                                push         ax
                                shr           al,1
                                call         ToASCII
                                EchoCh     al
                                pop           ax
                                call         ToASCII
                                EchoCh     al
                                EchoCh     '   '
                                loop         NextCh
                                EchoCh     0dh
                                EchoCh     0ah
                                dec           bp
                                jnz           NextLine
                                mov           ax,4c00h
                                int           21h


Start                       ENDP
;----------------------------------------
ToASCII                   PROC
                                and           al,0fh
                                add           al,90h
                                daa
                                adc           al,40h
                                daa
                                ret
ToASCII                   ENDP
;----------------------------------------
CSEG                         ENDS                                                       ;代码段定义结束
;----------------------------------------
                                END           Start
搞不懂的是这句:
adc           dx,0                                       ;界限已在定义时设置好
首先是不知道为什么要使用这条指令,里面DX根本没初始化,那他原来的值是多少?呢?

[解决办法]
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 bx,16
mul bx
上面两句是将AX的数据段的段值乘以16,获得数据段的物理地址。结果存放在dx:ax中。因此指向mul bx时dx得到了初始化。
add ax,OFFSET GDT ;计算并设置基地址
adc dx,0 ;界限已在定义时设置好
上面两句是计算GDT的物理地址,在数据段物理地址的基础上加上了GDT结构的偏移,第二句是怕相加之后产生进位,所以把进位加到了物理地址的高16位DX上,当然在这个程序里是不会产生进位的,因为GDT位于数据段的头一行,偏移是零。如此编码可以在GDT前面加入其它变量以后,计算的物理地址仍然有效。
顺便说一句,上面的代码出自《80x86汇编语言程序设计教程》第十章。

热点排行