;名称:386SCD.INC
;功能:符号常量等的定义
;----------------------------------------------------------------------------
;IFNDEF __386SCD_INC
;__386SCD_INC EQU 1
;----------------------------------------------------------------------------
.386P
;----------------------------------------------------------------------------
;打开A20地址线
;----------------------------------------------------------------------------
EnableA20 MACRO
push ax
in al,92h
or al,00000010b
out 92h,al
pop ax
ENDM
;----------------------------------------------------------------------------
;关闭A20地址线
;----------------------------------------------------------------------------
DisableA20 MACRO
push ax
in al,92h
and al,11111101b
out 92h,al
pop ax
ENDM
;----------------------------------------------------------------------------
;16位偏移的段间直接转移指令的宏定义(在16位代码段中使用)
;----------------------------------------------------------------------------
JUMP16 MACRO Selector,Offset
DB 0eah ;操作码
DW Offset ;16位偏移量
DW Selector ;段值或段选择子
ENDM
;----------------------------------------------------------------------------
;32位偏移的段间直接转移指令的宏定义(在32位代码段中使用)
;----------------------------------------------------------------------------
COMMENT <JUMP32>
JUMP32 MACRO Selector,Offset
DB 0eah ;操作码
DD OFFSET
DW Selector ;段值或段选择子
ENDM
<JUMP32>
;-------------------------------------------------
JUMP32 MACRO Selector,Offset
DB 0eah ;操作码
DW OFFSET
DW 0
DW Selector ;段值或段选择子
ENDM
;----------------------------------------------------------------------------
;16位偏移的段间调用指令的宏定义(在16位代码段中使用)
;----------------------------------------------------------------------------
CALL16 MACRO Selector,Offset
DB 9ah ;操作码
DW Offset ;16位偏移量
DW Selector ;段值或段选择子
ENDM
;----------------------------------------------------------------------------
;32位偏移的段间调用指令的宏定义(在32位代码段中使用)
;----------------------------------------------------------------------------
COMMENT <CALL32>
CALL32 MACRO Selector,Offset
DB 9ah ;操作码
DD Offset
DW Selector ;段值或段选择子
ENDM
<CALL32>
;-------------------------------------------------
CALL32 MACRO Selector,Offset
DB 9ah ;操作码
DW Offset
DW 0
DW Selector ;段值或段选择子
ENDM
;----------------------------------------------------------------------------
;存储段描述符结构类型定义
;----------------------------------------------------------------------------
Desc STRUC
LimitL DW 0 ;段界限(BIT0-15)
BaseL DW 0 ;段基地址(BIT0-15)
BaseM DB 0 ;段基地址(BIT16-23)
Attributes DB 0 ;段属性
LimitH DB 0 ;段界限(BIT16-19)(含段属性的高4位)
BaseH DB 0 ;段基地址(BIT24-31)
Desc ENDS
;----------------------------------------------------------------------------
;门描述符结构类型定义
;----------------------------------------------------------------------------
Gate STRUC
OffsetL DW 0 ;32位偏移的低16位
Selector DW 0 ;选择子
DCount DB 0 ;双字计数
GType DB 0 ;类型
OffsetH DW 0 ;32位偏移的高16位
Gate ENDS
;----------------------------------------------------------------------------
;伪描述符结构类型定义(用于装入全局或中断描述符表寄存器)
;----------------------------------------------------------------------------
PDesc STRUC
Limit DW 0 ;16位界限
Base DD 0 ;32位基地址
PDesc ENDS
;----------------------------------------------------------------------------
;任务状态段结构类型定义
;----------------------------------------------------------------------------
TSS STRUC
TRLink DW 0 ;链接字段
DW 0 ;不使用,置为0
TRESP0 DD 0 ;0级堆栈指针
TRSS0 DW 0 ;0级堆栈段寄存器
DW 0 ;不使用,置为0
TRESP1 DD 0 ;1级堆栈指针
TRSS1 DW 0 ;1级堆栈段寄存器
DW 0 ;不使用,置为0
TRESP2 DD 0 ;2级堆栈指针
TRSS2 DW 0 ;2级堆栈段寄存器
DW 0 ;不使用,置为0
TRCR3 DD 0 ;CR3
TREIP DD 0 ;EIP
TREFlag DD 0 ;EFLAGS
TREAX DD 0 ;EAX
TRECX DD 0 ;ECX
TREDX DD 0 ;EDX
TREBX DD 0 ;EBX
TRESP DD 0 ;ESP
TREBP DD 0 ;EBP
TRESI DD 0 ;ESI
TREDI DD 0 ;EDI
TRES DW 0 ;ES
DW 0 ;不使用,置为0
TRCS DW 0 ;CS
DW 0 ;不使用,置为0
TRSS DW 0 ;SS
DW 0 ;不使用,置为0
TRDS DW 0 ;DS
DW 0 ;不使用,置为0
TRFS DW 0 ;FS
DW 0 ;不使用,置为0
TRGS DW 0 ;GS
DW 0 ;不使用,置为0
TRLDTR DW 0 ;LDTR
DW 0 ;不使用,置为0
TRTrip DW 0 ;调试陷阱标志(只用位0)
TRIOMap DW $+2 ;指向I/O许可位图区的段内偏移
TSS ENDS
;----------------------------------------------------------------------------
;存储段描述符类型值说明
;----------------------------------------------------------------------------
ATDR EQU 90h ;存在的只读数据段类型值
ATDW EQU 92h ;存在的可读写数据段属性值
ATDWA EQU 93h ;存在的已访问可读写数据段类型值
ATCE EQU 98h ;存在的只执行代码段属性值
ATCER EQU 9ah ;存在的可执行可读代码段属性值
ATCCO EQU 9ch ;存在的只执行一致代码段属性值
ATCCOR EQU 9eh ;存在的可执行可读一致代码段属性值
;----------------------------------------------------------------------------
;系统段描述符类型值说明
;----------------------------------------------------------------------------
ATLDT EQU 82h ;局部描述符表段类型值
ATTaskGate EQU 85h ;任务门类型值
AT386TSS EQU 89h ;可用386任务状态段类型值
AT386CGate EQU 8ch ;386调用门类型值
AT386IGate EQU 8eh ;386中断门类型值
AT386TGate EQU 8fh ;386陷阱门类型值
;----------------------------------------------------------------------------
;DPL值说明
;----------------------------------------------------------------------------
DPL0 EQU 00h ;DPL=0
DPL1 EQU 20h ;DPL=1
DPL2 EQU 40h ;DPL=2
DPL3 EQU 60h ;DPL=3
;----------------------------------------------------------------------------
;RPL值说明
;----------------------------------------------------------------------------
RPL0 EQU 00h ;RPL=0
RPL1 EQU 01h ;RPL=1
RPL2 EQU 02h ;RPL=2
RPL3 EQU 03h ;RPL=3
;----------------------------------------------------------------------------
;IOPL值说明
;----------------------------------------------------------------------------
IOPL0 EQU 0000h ;IOPL=0
IOPL1 EQU 1000h ;IOPL=1
IOPL2 EQU 2000h ;IOPL=2
IOPL3 EQU 3000h ;IOPL=3
;----------------------------------------------------------------------------
;其它常量值说明
;----------------------------------------------------------------------------
D32 EQU 40h ;32位代码段标志
GL EQU 80h ;段界限以4K为单位标志
TIL EQU 04h ;TI=1(局部描述符表标志)
VMFL EQU 00020000h ;VMF=1
VMFLW EQU 0002h
IFL EQU 00000200h ;IF=1
RFL EQU 00010000h ;RF=1(重启动标志,为1表示忽略调试故障)
RFLW EQU 0001h
NTL EQU 00004000h ;NT=1
;----------------------------------------------------------------------------
;分页机制使用的常量说明
;----------------------------------------------------------------------------
PL EQU 1 ;页存在属性位
RWR EQU 0 ;R/W属性位值,读/执行
RWW EQU 2 ;R/W属性位值,读/写/执行
USS EQU 0 ;U/S属性位值,系统级
USU EQU 4 ;U/S属性位值,用户级
;----------------------------------------------------------------------------
;ENDIF
;名称: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
;名称: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
以上代码是从教程中复制的
但有以下问题不解:
1、这个要怎么编译链接
2、生成可执行程序要在什么系统下运行,其实跟第一个问题有点重复
3、如何调试。
我使用MASM6.1的MASM命令编译,两个程序都无法通过编译,第一个程序将装载GDT的那一行代码: lgdt QWORD PTR VGDTR改成lgdt VGDTR既可通过编译,但无法在虚拟DOS下运行。
而第二个程序,无论使用MASM还是ML命令都无法通过编译。
刚起步,什么都不懂,请讲解时讲得“白”一些。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!