pmtest1.asm简介

; =========================================
;pmtest1.asm
;编译方法:nasm pmtest1.asm -o pmtest1.com
; =========================================
%include "pm.inc"  ;常量、宏、以及一些说明
; =========================================
;pm.inc
;描述符
;usage:descriptor base,limit,attr
;	base: dd
;	limit: dd (low 20 bits available)
;	attr: dw(lower 4 bits of higher byte are always 0)
%macro Descriprot 3
	dw %2 & 0FFFFh ;段界限1 (2字节)
	dw %1 & 0FFFFh ;段基址1 (2字节)
	db (%1 >> 16) & 0FFh ;段基址2 (1字节)
	dw ((%2 >> 8) &  0F00h) | (%3 & 0F0FFh) ;属性1 + 段界限2 + 属性2 (2字节)
	db (%1 >> 24) & 0FFh ;段基址3 (1字节)
%endmacro ;共8字节
; =========================================
org 0100h  ;org 是 origin的缩写,起始地址源。在汇编语言源程序的开始通常都用一条org伪指令来实现规定程序的起始地址。如果不用org规定则汇编得到的目标程序将从0000H开始。"org"是一个汇编器伪指令,用于设置下一条指令的装入地址。"org"后面跟着的是一个表达式,这个表达式的值就是下一条指令的装入地址。如果不用org规定则汇编得到的目标程序将从0x0000开始。两个org伪指令之间,除了指令代码,若有自由空间,则用0填充。
	jmp LABEL_BEGIN
[SECTION .gdt]
; GDT
LABEL_GDT: Descriptor 0, 0, 0 ;空描述符,label标签就是这段内存空间的首地址。
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ;代码段,32位
LABEL_DESC_VIDEO: Descriptor 0B800H, 0ffffh, DA_DRW ;显存首地址
; GDT结束

GdtLen equ $ - LABEL_GDT ;GDT长度
GdtPtr dw GdtLen ;GDT界限
	   dd 0      ;GDT基地址

; GDT选择子
Selectorode32    equ LABEL_DESC_CODE32 - LABEL_GDT ;equ是equation的缩写,意思是“等式”。在汇编语言中,我们可以使用equ关键字来定义一个符号常量,它的值在整个程序中不会发生改变。这样做的好处是可以提高程序的可读性和可维护性。因为我们可以使用有意义的符号代替数字或字符串,更加清晰地表达程序的含义。
SelectorVideo	 equ LABEL_DESC_VIDEO  - LABEL_GDT
; END of [SECTION .gdt]
; ==========================================
; 标签和变量
; label意思是我指向的就是一大块的首地址,使用方法:LABEL_NAME: (注意后面要加冒号)
; 命名方式,尽可能使用java中的类似于包的命名方式,比如LABEL_SEG_CODE16,LABEL_SEG_CODE32,LABEL_DESC_STACK。
; 汇编中的LABEL还有一种叫做,局部label,是以点开头,比如.begin\.1\.2。在不同的段中可以使用相同的带点开头的label,不会重复。
; 并经过实验,最好只用在代码段中,数据段不好使。
; 变量名:
; 变量名分为函数变量名和普通变量名
; -函数变量名:
; 指的是一个sub_rutin的首地址。比如DispStr,使用的时候是call DispStr,然后在声明时候,因为它本来就是一个地址,就是用上面标签的同样的声明方式。DispStr:(注意后面有冒号)
; -普通变量名:
; 分为2中形式构成的变量名,
; 第一种使用equ生成的纯的变量,貌似是宏,比如:TopOfStack equ $ - LABEL_STACK - 1,命名为首字母大写(也不一定,如果可以代表DataSeg的存储空间)。
; 第二种使用db dd dw生成的变量,起始就是一个地址。生成的各种变量分别指向的是不同的数据类型,那么命名时候前几个字母尽量写清楚类型。
; 比如如下的命名:(特别四数据段会有这种命名方式的用法,冒号可加可不加)
; _dwDispPos: dd (80*6+0)*2
; _wSPValueInRealMode dw 0
; _szRAMSize db "RAM size:",0
; ==========================================
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, 0100h
	
	;初始化32位代码段描述符
	xor eax, eax ;xor指令在两个操作数的对应位之间进行(按位)逻辑异或(xor)操作,并将结果存在目标操作数中。xor destination source。两值不同为1,两值相同为0。
	mov ax, cs ;传送指令mov把一个字节、字、双字的操作数从源位置传送到目的位置,源操作数的内容不变。可以实现立即数到通用寄存器或主存的传送,通用寄存器与通用寄存器、主存或段寄存器之间的传送,主存与段寄存器之间的传送。该操作属于复制性质,不属于搬家性质。格式:mov destination source
	shl eax, 4 ;shl指令的作用是逻辑左移,将目的操作数顺寻左移1位或cl寄存器中执行的位数。左移一位时,操作数的最高位移入进位标识位cf,最低为补零。
	add eax, LABEL_SEG_CODE32 ;add 寄存器,数据   将数据累加到寄存器中,比如寄存器当时是1,数据为2,则结果为3,此时寄存器所保存的值就是3.
	mov word [LABEL_DESC_CODE32 + 2], ax
	shr eax, 16 ;shr右移指令使目的操作数逻辑右移一位,最高位用0填充。最低为复制到进位标志位cf,而仅为标志位中原来的数值被丢弃。
	mov byte [LABEL_DESC_CODE32 + 4], al
	mov byte [LABEL_DESC_CODE32 + 7], ah
	;为加载gdtr做准备
	xor eax, eax
	mov ax, ds
	shl eax, 4
	add eax, LABEL_GDT  ;eax <- gdt基地址
	mov dword [GdtPtr + 2], eax ;[GdtPtr + 2] <- gdt基地址
	
	; 加载 gdtr
	lgdt [GdtPtr]
	
	;关中断
	cli
	
	;打开地址线A20
	in al, 92h ;表示从92h端口读取一字节数据到al中
	or al, 00000010b
	out 92h, al ;表示将al的值写入92h端口
	
	;准备切换到保护模式
	mov eax, cr0
	or eax, 1
	mov cr0, eax
	
	;真正进入保护模式
	jmp dword SelectorCode32:0 ;执行这一句会把SelectorCode32装入cs,并跳转到SelectorCode32:0处
	
[SECTION .s32] ;32位代码段,由实模式跳入
[BITS 32]

LABEL_SEG_CODE32:
	mov ax, SelectorVideo
	mov gs, ax ;是频段选择子(目的)
	
	mov edi, (80 * 10 + 0) * 2 ;屏幕第10行,第0列。
	mov ah, 0Ch ;0000:黑底  1100:红字
	mov al, 'P'
	mov [gs:edi], ax
	
	;到此停止
	jmp $

SegCode32Len equ $ - LABEL_SEG_CODE32
; END of [SECTION .s32]

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值