保护模式进阶

这个程序的核心目的是:试验大地址的读写,在保护模式下面寻址空间可达4GB,实模式下只能寻址1MB。(why:为什么保护模式下能有这么大的寻址能力,而实模式下不行?answer:实模式下有20位的地址总线,保护模式下有32位地址总线)

读写es段,5MB处的数据。首先读出开始处的8字节的内容,然后写入一个字符串,再从中读出。

读写字符串,使用的是[es:edi]和[es:esi]

; ==========================================

; pmtest2.asm

; 编译方法:nasm pmtest2.asm -o pmtest2.com

; ==========================================

%include "pm.inc" ; 常量, 宏, 以及一些说明

org 0100h

jmp LABEL_BEGIN


[SECTION .gdt]

; GDT

;                            段基址,        段界限 , 属性

LABEL_GDT:        Descriptor    0,              0, 0        ; 空描述符

LABEL_DESC_NORMAL: Descriptor    0,        0ffffh, DA_DRW    ; Normal 描述符

LABEL_DESC_CODE32: Descriptor    0, SegCode32Len-1, DA_C+DA_32; 非一致代码段, 32

LABEL_DESC_CODE16: Descriptor    0,        0ffffh, DA_C      ; 非一致代码段, 16

LABEL_DESC_DATA:  Descriptor    0,      DataLen-1, DA_DRW    ; Data

LABEL_DESC_STACK:  Descriptor    0,    TopOfStack, DA_DRWA+DA_32; Stack, 32 位

LABEL_DESC_TEST:  Descriptor 0500000h,    0ffffh, DA_DRW

LABEL_DESC_VIDEO:  Descriptor  0B8000h,    0ffffh, DA_DRW    ; 显存首地址

; GDT 结束

GdtLen equ $ - LABEL_GDT ; GDT长度

GdtPtr dw GdtLen - 1 ; GDT界限

dd 0 ; GDT基地址

; GDT 选择子

SelectorNormal equ LABEL_DESC_NORMAL - LABEL_GDT

SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT

SelectorCode16 equ LABEL_DESC_CODE16 - LABEL_GDT

SelectorData equ LABEL_DESC_DATA - LABEL_GDT

SelectorStack equ LABEL_DESC_STACK - LABEL_GDT

SelectorTest equ LABEL_DESC_TEST - LABEL_GDT

SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT

; END of [SECTION .gdt]


[SECTION .data1] ; 数据段

ALIGN 32

[BITS 32]

LABEL_DATA:

SPValueInRealMode dw 0

; 字符串

PMMessage: db "In Protect Mode now. ^-^", 0 ; 在保护模式中显示

OffsetPMMessage equ PMMessage - $$

StrTest: db "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0

OffsetStrTest equ StrTest - $$

DataLen equ $ - LABEL_DATA

; END of [SECTION .data1]


; 全局堆栈段

[SECTION .gs]

ALIGN 32

[BITS 32]

LABEL_STACK:

        times 512 db 0

        TopOfStack equ $ - LABEL_STACK - 1

; END of [SECTION .gs]


[SECTION .s16]

[BITS 16]

LABEL_BEGIN:

        mov ax, cs

        mov ds, ax

        mov es, ax

        mov ss, ax

        mov sp, 0100h

        mov [LABEL_GO_BACK_TO_REAL+3], ax   将LABEL_GO_BACK_TO_REAL中的jmp指令的第三个字节修改位cs_real_mode值,实现jmp正确的跳转

        mov [SPValueInRealMode], sp

        ; 初始化 16 位代码段描述符

        mov ax, cs

        movzx eax, ax

        shl eax, 4

        add eax, LABEL_SEG_CODE16

        mov word [LABEL_DESC_CODE16 + 2], ax

        shr eax, 16

        mov byte [LABEL_DESC_CODE16 + 4], al

        mov byte [LABEL_DESC_CODE16 + 7], ah

        ; 初始化 32 位代码段描述符

        xor eax, eax

        mov ax, cs

        shl eax, 4

        add eax, LABEL_SEG_CODE32

        mov word [LABEL_DESC_CODE32 + 2], ax

        shr eax, 16

        mov byte [LABEL_DESC_CODE32 + 4], al

        mov byte [LABEL_DESC_CODE32 + 7], ah

        ; 初始化数据段描述符

        xor eax, eax

        mov ax, ds

        shl eax, 4

        add eax, LABEL_DATA

        mov word [LABEL_DESC_DATA + 2], ax

        shr eax, 16

        mov byte [LABEL_DESC_DATA + 4], al

        mov byte [LABEL_DESC_DATA + 7], ah

        ; 初始化堆栈段描述符

        xor eax, eax

        mov ax, ds

        shl eax, 4

        add eax, LABEL_STACK

        mov word [LABEL_DESC_STACK + 2], ax

        shr eax, 16

        mov byte [LABEL_DESC_STACK + 4], al

        mov byte [LABEL_DESC_STACK + 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

        or al, 00000010b

        out 92h, al

        ; 准备切换到保护模式

        mov eax, cr0

        or eax, 1

        mov cr0, eax

        ; 真正进入保护模式

        jmp dword SelectorCode32:0 ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LABEL_REAL_ENTRY: ; 从保护模式跳回到实模式就到了这里

        mov ax, cs

        mov ds, ax

        mov es, ax

        mov ss, ax

        mov sp, [SPValueInRealMode]

        in al, 92h ; `.

        and al, 11111101b ;  | 关闭 A20 地址线

        out 92h, al ; /

        sti ; 开中断

        mov ax, 4c00h ; `.

        int 21h ; /  回到 DOS

 ; END of [SECTION .s16]



[SECTION .s32]; 32 位代码段. 由实模式跳入.

[BITS 32]

LABEL_SEG_CODE32:

        mov ax, SelectorData

        mov ds, ax ; 数据段选择子

        mov ax, SelectorTest

        mov es, ax ; 测试段选择子

        mov ax, SelectorVideo

        mov gs, ax ; 视频段选择子

        mov ax, SelectorStack

        mov ss, ax ; 堆栈段选择子

        mov esp, TopOfStack

        ; 下面显示一个字符串

        mov ah, 0Ch ; 0000: 黑底    1100: 红字

        xor esi, esi

        xor edi, edi

        mov esi, OffsetPMMessage ; 源数据偏移

        mov edi, (80 * 10 + 0) * 2 ; 目的数据偏移。屏幕第 10 行, 第 0 列。

        cld  将数据从esi拷贝到edi

.1:

        lodsb

        test al, al 测试al是否为空

        jz .2

        mov [gs:edi], ax

        add edi, 2

        jmp .1

.2: ; 显示完毕

        call DispReturn

        call TestRead

        call TestWrite

        call TestRead

        ; 到此停止

        jmp SelectorCode16:0

; ------------------------------------------------------------------------

TestRead:     将[es:esi]中的数据逐个以16进制形式显示出来

        xor esi, esi

        mov ecx, 8

.loop:

        mov al, [es:esi]

        call DispAL

        inc esi

        loop .loop

        call DispReturn

        ret

; TestRead 结束-----------------------------------------------------------

; ------------------------------------------------------------------------

TestWrite:   OffsetStrTest的数据写入到[es:edi]

        push esi

        push edi

        xor esi, esi

        xor edi, edi

        mov esi, OffsetStrTest ; 源数据偏移

        cld

.1:

        lodsb

        test al, al 

        jz .2      测试寄存器al是否为空,如果为空,则跳转2

        mov [es:edi], al    

        inc edi

        jmp .1

.2:

        pop edi

        pop esi

        ret

; TestWrite 结束----------------------------------------------------------

; ------------------------------------------------------------------------

; 显示 AL 中的数字

; 默认地:

; 数字已经存在 AL 中

; edi 始终指向要显示的下一个字符的位置

; 被改变的寄存器:

; ax, edi

; ------------------------------------------------------------------------

DispAL: 将al中的字节用16进制形式显示出来

        push ecx

        push edx

        mov ah, 0Ch ; 0000: 黑底    1100: 红字

        mov dl, al

        shr al, 4

        mov ecx, 2

.begin:

        and al, 01111b

        cmp al, 9

        ja .1

        add al, '0'

        jmp .2

.1:

        sub al, 0Ah

        add al, 'A'

.2:

        mov [gs:edi], ax

        add edi, 2

        mov al, dl

        loop .begin

        add edi, 2

        pop edx

        pop ecx

        ret

; DispAL 结束-------------------------------------------------------------

; ------------------------------------------------------------------------

DispReturn: 修改的edi的值,让下一个字符显示在下一行的开头处

        push eax

        push ebx 

        mov eax, edi

        mov bl, 160

        div bl

        and eax, 0FFh

        inc eax

        mov bl, 160

        mul bl

        mov edi, eax

        pop ebx

        pop eax

         ret

; DispReturn 结束---------------------------------------------------------


SegCode32Len equ $ - LABEL_SEG_CODE32

; END of [SECTION .s32]

; 16 位代码段. 由 32 位代码段跳入, 跳出后到实模式

[SECTION .s16code]

ALIGN 32

[BITS 16]

LABEL_SEG_CODE16:

        ; 跳回实模式:

        mov ax, SelectorNormal

        mov ds, ax

        mov es, ax

        mov fs, ax

        mov gs, ax

        mov ss, ax 

        mov eax, cr0

        and al, 11111110b

        mov cr0, eax

LABEL_GO_BACK_TO_REAL:

        jmp 0:LABEL_REAL_ENTRY ; 段地址会在程序开始处被设置成正确的值

Code16Len equ $ - LABEL_SEG_CODE16

; END of [SECTION .s16code]



一、cld汇编指令

与cld相对应的指令是std,二者均是用来操作方向标志位DF(Direction Flag)。cld使DF 复位,即是让DF=0,std使DF置位,即DF=1.这两个指令用于串操作指令中。通过执行cld或std指令可以控制方向标志DF,决定内存地址是增大(DF=0,向高地址增加)还是减小(DF=1,向地地址减小)。

源操作数和目的操作数分别使用寄存器(e)si和(e)di进行间接寻址;每执行一次串操作,源指针(e)si和目的指针(e)di将自动进行修改:±1、±2、±4,其对应的分别是字节操作、字操作和双字操作。

在执行该指令之前,必须预置SI和DI的初值,用STD或CLD设置DF值.

MOVS DST , SRC //同上,不常用,DST和SRC只是用来用类型检查,并不允许使用其它寻址方式来确定操作数.

        1.目的串必须在附加段中,即必须是ES:[DI]

        2.源串允许使用段跨越前缀来修饰,但偏移地址必须是[SI].

二、lodsb 字符串操作指令

汇编语言中,串操作指令LODSB/LODSW是块装入指令,其具体操作是把SI指向的存储单元读入累加器,LODSB就读入AL,LODSW就读入AX中,然后SI自动增加或减小1或2.其常常是对数组或字符串中的元素逐个进行处理。

三、test汇编指令

test属于逻辑运算指令

功能: 执行BIT与BIT之间的逻辑运算

测试(两操作数作与运算,仅修改标志位,不回送结果).

Test对两个参数(目标,源)执行AND逻辑操作,并根据结果设置标志寄存器,结果本身不会保存。TEST AX,BX 与 AND AX,BX 命令有相同效果

语法: TEST r/m,r/m/data

影响标志: C,O,P,Z,S(其中C与O两个标志会被设为0)

四、div指令


五、loop指令

loop指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作

1.(cx)=(cx)-1

2.判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • 可以将一个单独的任务所用到的所有东西都封装在一个LDT中。 step1.增加一个32位的代码段:LABEL_COD...
    王侦阅读 1,138评论 0 0
  • 核心目的:实现由实模式到保护模式的转换 核心步骤: 1)程序定义了GDT数据结构 2)16位代码进行了一些...
    王侦阅读 1,125评论 0 0
  • 8086汇编 本笔记是笔者观看小甲鱼老师(鱼C论坛)《零基础入门学习汇编语言》系列视频的笔记,在此感谢他和像他一样...
    Gibbs基阅读 37,204评论 8 114
  • 因为项目用的vue.js框架和ES6语法,所以这套规范主要出于我们自己项目来考虑的,额,有一些太基础的也就不写了,...
    HelenYin阅读 636评论 2 3
  • 链式方法是当前比较流行的一种语法规则。在过去的几个版本中,我们已经提到了几个支持链式方法的函数: assign (...
    Datartisan数据工匠阅读 4,618评论 1 3