从实模式到保护模式第8到12章笔记讲解.docx

上传人:b****7 文档编号:8712903 上传时间:2023-02-01 格式:DOCX 页数:20 大小:48.42KB
下载 相关 举报
从实模式到保护模式第8到12章笔记讲解.docx_第1页
第1页 / 共20页
从实模式到保护模式第8到12章笔记讲解.docx_第2页
第2页 / 共20页
从实模式到保护模式第8到12章笔记讲解.docx_第3页
第3页 / 共20页
从实模式到保护模式第8到12章笔记讲解.docx_第4页
第4页 / 共20页
从实模式到保护模式第8到12章笔记讲解.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

从实模式到保护模式第8到12章笔记讲解.docx

《从实模式到保护模式第8到12章笔记讲解.docx》由会员分享,可在线阅读,更多相关《从实模式到保护模式第8到12章笔记讲解.docx(20页珍藏版)》请在冰豆网上搜索。

从实模式到保护模式第8到12章笔记讲解.docx

从实模式到保护模式第8到12章笔记讲解

第10章IA32

10.1IA-32架构的基本执行环境

10.1.1寄存器的扩展

在16位处理器内,有8个通用寄存器AX、BX、CX、DX、SI、DI、BP和SP,其中,前4个还可以拆分成两个独立的8位寄存器来用,即AH、AL、BH、BL、CH、CL、DH和DL。

为了在汇编语言程序中使用经过扩展(Extend)的寄存器,需要给它们命名,它们的名字

分别是EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP。

可以在程序中使用这些寄存器,

即使是在实模式下:

moveax,0xf0000005

movecx,eax

addedx,ecx

但是,就像以上指令所示的那样,指令的源操作数和目的操作数必须具有相同的长度,个别特

殊用途的指令除外。

因此,像这样的搭配是不允许的,在程序编译时,编译器会报告错误:

moveax,cx;错误的汇编语言指令

如果目的操作数是32位寄存器,源操作数是立即数,那么,立即数被视为32位的:

moveax,0xf5;EAX←0x000000f5

32位通用寄存器的高16位是不可独立使用的,但低16位保持同16位处理器的兼容性。

因此,

在任何时候它们都可以照往常一样使用:

movah,0x02

moval,0x03

addax,si

可以在32位处理器上运行16位处理器上的软件。

但是,它并不是16位处理器的简单增强。

事实上,32位处理器有自己的32位工作模式,在本书中,32位模式特指32位保护模式。

在这种

模式下,可以完全、充分地发挥处理器的性能。

同时,在这种模式下,处理器可以使用它全部的32

根地址线,能够访问4GB内存。

10.1.2基本的工作模式

8086具有16位的段寄存器、指令指针寄存器和通用寄存器(CS、SS、DS、ES、IP、AX、

BX、CX、DX、SI、DI、BP、SP),因此,我们称它为16位的处理器。

尽管它可以访问1MB

的内存,但是只能分段进行,而且由于只能使用16位的段内偏移量,故段的长度最大只能是

64KB。

8086只有一种工作模式,即实模式。

当然,这个名称是后来才提出来的。

10.1.3线性地址

为IA-32处理器编程,访问内存时,需要在程序中给出段地址和偏移量,因为分段是IA-32

架构的基本特征之一。

传统上,段地址和偏移地址称为逻辑地址,偏移地址叫做有效地址

(EffectiveAddress,EA),在指令中给出有效地址的方式叫做寻址方式(AddressingMode)。

10.2现代处理器的结构和特点

10.2.1流水线

处理器的每一次更新换代,都会增加若干新特性,这是很自然的。

同时我们也会发现,老

软件在新的处理器上跑得更快。

这里面的原因很简单,处理器的设计者总是在想尽办法加快指

令的执行。

10.2.2高速缓存

影响处理器速度的另一个因素是存储器。

从处理器内部向外看,它们分别是寄存器、内存和硬

盘。

当然,现在有的计算机已经用上了固态磁盘。

10.2.3乱序执行

为了实现流水线技术,需要将指令拆分成更小的可独立执行部分,即拆分成微操作(Micro-Operations),简写为μops。

10.2.5分支目标预测

流水线并不是百分之百完美的解决方案。

实际上,有很多潜在的因素会使得流水线不能达到最

佳的效率。

一个典型的情况是,如果遇到一条转移指令,则后面那些已经进入流水线的指令就都无

效了。

换句话说,我们必须清空(Flush)流水线,从要转移到的目标位置处重新取指令放入流水线。

10.3.132位处理器的寻址方式

在16位处理器上,指令中的操作数可以是8位或者16位的寄存器、指向8位或者16位实际

操作数的16位内存地址,以及8位或16位的立即数。

 

第十一章进入保护模式

NASM编译

●情景描述

使用NASM编译一段程序,并可以在裸机上运行。

●实现功能

在开机后显示"Hello,OSworld!

"

●流程

1)初始化寄存器

2)调用BIOSint10h,显示字符串

3)进入死循环

●代码及注释

%define_BOOT_DEBUG_

%ifdef_BOOT_DEBUG_

org0100h

%else

org07c00h

%endif

;告诉编译器加载到0100处生成,这样方便生成com文件。

;或者告诉编译器加载到7c00处生成,这样方便

movax,cs;将当前段地址放入ax,可以不要

movds,ax;将当前段地址放入数据寄存器,可以不要

moves,ax;将当前段地址放入extra寄存器,可以不要

callDispStr;调用显示字符串程序

jmp$;无限循环(跳转到当前地址)

DispStr:

movax,BootMessage;BootMessage的首地址送ax

movbp,ax;段内地址送到bp,至此地址完成——CS:

BP=串地址

movcx,16;CX=串长度

movax,01301h;AH=13,AL=01h

movbx,000ch;BH=0(页号为0),BL=0ch(黑底红字高亮)

movdl,0;0送dx寄存器的低字节

int10h;10h号中断(视频中断,对应的中断向量为40-43H)

ret;从显示子程序中返回到主程序

BootMessage:

db"Hello,OSworld!

"

times510-($-$$)db0;用“0”填充0面0磁道1扇区剩下的空间,使生成的二进制代码恰好为512字节;

;$是当前行的段内偏移地址,$$是本小节代码的第一行代码,在本程序中就是“org07c00h”的段内偏移地址。

dw0xaa55;结束标志.使得0面0磁道1扇区510字节存55,511字节存aa,0扇区从0-511号单元,共512个字节。

(引导扇区的结束标志)

●显示界面

运行程序界面

实验补充资料

一.内存引导地址7C00

Intel公司当初设计8086系统内存时对内存(1M)是这样规定的:

内存包括暂驻程序区640K和系统内存区384K,在640K中把BIOS和驻留操作系统的数据和程序安排在低地址处,在保留一定的可扩展空间后,为配合BIOS和磁盘操作系统就把7C00规定为硬件及软件都支持的启动引导的内存地址,并写成引导规范。

在当时各个公司都有自己的一些未公开的标准,而IBM公开推行IBM计算机的内部详细的结构时,他采用的是Intel的芯片,所以他遵循了这个标准,又由于大批的公司知道了这个标准之后,都兼容这个标准,以后也继续兼容,就真正成为一个共同的标准了,现在的CPU都是向下兼容的,还在用7C00。

由于引导扇区被加载到了7c00h处,代码中BootMessage的首地址放入bp中时,只是将8位放入了bp,缺省了高8位,这高8位需要由org指定,否则无法将正确的字符串相对偏移地址放入bp中:

BootMessage变量对应字符串在内存中首地址=0000(es段值):

{7c00(org指定)+BootMessage在程序段内偏移(8位2进制)}

org会在编译期影响到内存寻址指令的编译(编译器会把所有程序用到的段内偏移地址自动加上org后跟的数值),而其自身并不会被编译成机器码。

就是为程序中所有的引用地址(需要计算的相对地址)增加一个段内偏移值。

二.10h中断说明

10h中断表示,功能号为AH=13h时为写入字符串;AL=01h表示字符串包含属性;BH=页数;BL=显示属性;CX=字符串中的字符数量;DL,DH=从哪一列,行开始写;ES:

BP指向该字符串

反编译

通过反编译,可以将程序返回至源代码内容

反编译方法:

ndisasmw-o0x7c00>>1.asm

显示1.asm内容如下:

00007C008CC8movax,cs

00007C028ED8movds,ax

00007C048EC0moves,ax

00007C06E80200call0x7c0b

00007C09EBFEjmpshort0x7c09

00007C0BB81E01movax,0x11e

00007C0E89C5movbp,ax

00007C10B91000movcx,0x10

00007C13B80113movax,0x1301

00007C16BB0C00movbx,0xc

00007C19B200movdl,0x0

00007C1BCD10int0x10

00007C1DC3ret

以下为数据区

00007C1E48H

00007C1F65e

00007C206Cl

00007C216Cl

00007C226Fo

00007C232C,

00007C2420空格

00007C254FO

00007C2653S

00007C2720空格

00007C2877w

00007C296F0

00007C2A72r

00007C2B6Cl

00007C2C64d

00007C2D21!

以下数据为0

00007C2E00无

……

00007DFC00无

00007DFD00无

00007DFE55AA55AA

保护模式

保护模式介绍

保护模式(ProtectedMode,或有时简写为pmode)是一种80286系列和之后的x86兼容CPU操作模式。

保护模式有一些新的特色,设计用来增强多工和系统稳定度,像是内存保护,分页系统,以及硬件支援的虚拟内存。

大部分的现今x86操作系统都在保护模式下运行,包含Linux、FreeBSD、以及微软Windows2.0和之后版本。

PM是处理器的native模式,在这种模式下,处理器支持所有的指令和所有的体系结构特性提供最高的性能和兼容性。

对于所有的应用程序和操作系统来说,建议都使用这种模式。

另外一种286和其之后CPU的操作模式是真实模式(RealMode),一种向前兼容且关闭这些特色的模式。

设计用来让新的芯片可以执行旧的软件。

依照设计的规格,所有的x86CPU都是在真实模式下开机来确保传统操作系统的向前兼容性。

在任何保护模式的特色可用前,他们必须要由某些程序手动地切换到保护模式。

在现今的电脑,这种切换通常是由操作系统在开机时候必须完成的第一件工作的其中内容之一。

为了保证PM的兼容性,处理器允许在受保护的,多任务的环境下执行RM程序。

这个特性被称做虚拟8086模式(Virtual-8086Mode),尽管它并不是一个真正的处理器模式。

Virtual-8086模式实际上是一个PM的属性,任何任务都可以使用它。

它也可能当CPU在保护模式下运行时,使用虚拟86模式来执行设计给真实模式的程序码。

RM提供了Intel8086处理器的编程环境,另外有一些扩展(比如切换到PM或SMM的能力)。

当主机被Power-up或Reset后,处理器处于RM下。

对于Intel80386以及其后的芯片,只有使用PM才能发挥作用。

因此需要解决从RM切换到PM的问题。

GDT(GlobalDescriptorTable)

在保护模式下,一个重要的数据结构就是GDT。

在实模式下,我们对一个内存地址的访问是通过(Segment:

Offset)的方式来进行的。

其中Segment是一个段的基地址,而一个段的最大长度是64KB(2^16),这是16位系统所能表示的最大长度。

而Offset则是相对于该段基地址的偏移量。

因此BaseAddress+Offset就是一个内存绝对地址。

由此,我们可以看出,一个段具备两个因素:

BaseAddress和Limit(段的最大长度),而对一个内存地址的访问,则是需要指出:

使用哪个段?

以及相对于这个段BaseAddress的Offset(这个Offset应该小于此段的Limit)。

当然对于16-bit系统,Limit不要指定,默认为最大长度64KB,而16-bit的Offset也永远不可能大于此Limit。

我们在实际编程的时候,使用16-bit段寄存器CS(CodeSegment),DS(DataSegment),SS(StackSegment)来指定Segment,CPU将段寄存器中的数值向左偏移4-bit,放到20-bit的地址线上就成为20-bit的BaseAddress。

(因此内存为2^20,不会超过1M)

到了保护模式,内存的管理模式分为两种,段模式和页模式,其中页模式也是基于段模式的。

也就是说,保护模式的内存管理模式事实上是:

纯段模式和段页式。

进一步说,段模式必不可少。

对于段模式来讲,访问一个内存地址仍然使用Segment:

Offset的方式,其中由于保护模式运行在32位系统上,那么Segment的两个因素:

BaseAddress和Limit也都应该是32位的。

IA-32允许将一个段的BaseAddress设为32-bit所能表示的任何值(Limit则可以被设为32-bit所能表示的,以2^12为倍数的任何数字。

而不象RealMode下,一个段的BaseAddress只能是16的倍数(因为其低4-bit是通过左移运算得来的,只能为0,从而达到使用16-bit段寄存器表示20-bitBaseAddress的目的),而一个段的Limit只能为固定值64KB。

)另外,ProtectedMode又为段模式提供了保护机制,也就说一个段的描述符需要规定对自身的访问权限(Access)。

所以在ProtectedMode下,对一个段的描述则包括3方面因素:

[BaseAddress,Limit,Access],它们加在一起被放在一个64-bit长的数据结构中,被称为段描述符。

这样如果直接通过一个64-bit段描述符来引用一个段的时候,就必须使用一个64-bit长的段寄存器装入这个段描述符。

但Intel为了保持向后兼容,将段寄存器仍然规定为16-bit(尽管每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16-bit的),那么很明显,无法通过16-bit长度的段寄存器来直接引用64-bit的段描述符。

解决的方法就是把这些长度为64-bit的段描述符放入一个数组中,而将段寄存器中的值作为下标索引来间接引用(事实上,是将段寄存器中的高13-bit的内容作为索引)。

这个全局的数组就是GDT。

在GDT中存放的不仅仅是段描述符,还有其它描述符,它们都是64-bit。

GDT可以被放在内存的任何位置,那么当程序员通过段寄存器来引用一个段描述符时,CPU必须知道GDT的入口,也就是GDT的基地址放在哪里,因此设计者提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过lgdt指令将GDT的入口地址装入此寄存器,之后从此以后,CPU就根据此寄存器的内容作为GDT的入口来访问GDT了。

GDT是ProtectedMode所必须的数据结构,也是唯一的。

它是全局可见的,对任何一个任务而言都是这样。

除了GDT之外,IA-32还允许程序员构建与GDT类似的数据结构,它们被称作LDT(LocalDescriptorTable)。

但与GDT不同的是,LDT在系统中可以存在多个,并且不是全局可见的,它们只对引用它们的任务可见。

每个任务最多可以拥有一个LDT。

另外,每一个LDT自身作为一个段存在,它们的段描述符被放在GDT中。

前面所讨论的装入段寄存器中作为GDT/LDT索引的就是SegmentSelector(选择子),当需要引用一个内存地址时,使用的仍然是Segment:

Offset模式,具体操作是:

在相应的段寄存器装入SegmentSelector,按照这个SegmentSelector可以到GDT或LDT中找到相应的SegmentDescriptor,这个SegmentDescriptor中记录了此段的BaseAddress,然后加上Offset,就得到了最后的内存地址。

从实模式到保护模式

●情景描述

完成一个程序,从实模式到保护模式的转变

●编译方法

nasmpmtest1.asm-o

●pmtest1.asm程序源码

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

org0100h;告诉编译器程序加载到0100处(段值)

jmpLABEL_BEGIN;跳到LABEL_BEGIN处

[SECTION.gdt]

;GDT

LABEL_GDT:

Descriptor0,0,0;空描述符(全部为零)

LABEL_DESC_CODE32:

Descriptor0,SegCode32Len-1,DA_C+DA_32

;非一致代码段,32(定义界限和属性)

;LABEL_DESC_CODE3298H(10011000B)内存中,DPL为0,代码段,只执行

;LABEL_DESC_CODE324000H(0100B)32位

LABEL_DESC_VIDEO:

Descriptor0B8000h,0ffffh,DA_DRW

;显存首地址(定义基址,界限和属性)

;LABEL_DESC_VIDEO92h存在的可读写数据段属性值,指向显存

;GDT结束

GdtLenequ$-LABEL_GDT;GDT长度

GdtPtrdwGdtLen-1;GDT界限

dd0;GDT基地址

;GDT选择子

SelectorCode32equLABEL_DESC_CODE32-LABEL_GDT

SelectorVideoequLABEL_DESC_VIDEO-LABEL_GDT

;GDT选择子结束

;ENDof[SECTION.gdt]

[SECTION.s16]

[BITS16]

LABEL_BEGIN:

movax,cs;段值-〉AX

movds,ax;DS指向与CS相同的段值

moves,ax;ES指向与CS相同的段值

movss,ax;SS指向与CS相同的段值

movsp,0100h

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

xoreax,eax;清空EAX

movax,cs;段值

shleax,4;段值左移4位

addeax,LABEL_SEG_CODE32;段值+偏移地址-〉基址

movword[LABEL_DESC_CODE32+2],ax;基址1

shreax,16

movbyte[LABEL_DESC_CODE32+4],al;基址2

movbyte[LABEL_DESC_CODE32+7],ah;基址3

;为加载GDTR作准备

xoreax,eax;清空EAX

movax,ds

shleax,4

addeax,LABEL_GDT;eax<-gdt基地址

movdword[GdtPtr+2],eax;[GdtPtr+2]<-gdt基地址

;加载GDTR

lgdt[GdtPtr];GdtPtr->lgdt

;关中断

cli

;打开地址线A20

inal,92h

oral,00000010b

out92h,al

;准备切换到保护模式,CRO第0位置置1

moveax,cr0

oreax,1

movcr0,eax

;真正进入保护模式

jmpdwordSelectorCode32:

0

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

0处

;LABEL_DESC_CODE32已经准备好,其中的基址就是LABEL_SEG_CODE32地址处

;ENDof[SECTION.s16]

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

[BITS32]

LABEL_SEG_CODE32:

movax,SelectorVideo

movgs,ax;视频段选择子(目的)->GS(段值)

movedi,(80*10+0)*2;屏幕第10行,第0列。

movah,0Ch;0000:

黑底1100:

红字

moval,'P'

mov[gs:

edi],ax

;到此停止

jmp$

SegCode32Lenequ$-LABEL_SEG_CODE32

;ENDof[SECTION.s32]

●pm.inc工具程序

;GDT参数——描述符类型值说明

;其中:

;DA_:

DescriptorAttribute/;D:

数据段/;C:

代码段/;S:

系统段

;R:

只读/;RW:

读写/;A:

已访问

DA_32equ4000h;32位段

DA_DPL0equ00h;DPL=0

DA_DPL1equ20h;DPL=1

DA_DPL2equ40h;DPL=2

DA_DPL3equ60h;DPL=3

;存储段描述符类型值说明

DA_DRequ90h;存在的只读数据段类型值

DA_DRWequ92h;存在的可读写数据段属性值

DA_DRWAequ93h;存在的已访问可读写数据段类型值

DA_Cequ98h;存在的只执行代码段属性值

DA_CRequ9Ah;存在的可执行可读代码段属性值

DA_CCOequ9Ch;存在的只执行一致代码段属性值

DA_CCORequ9Eh;存在的可执行可读一致代码段属性值

;系统段描述符类型值说明

DA_LDTequ82h;局部描述符表段类型值

DA_TaskGateequ85h;任务门类型值

DA_386TSSequ89h;可用386任务状态段类型值

DA_386CGateequ8Ch;386调用门类型值

DA_386IGateequ8Eh;386中断门类型值

DA_386TGateequ8Fh;386陷阱门类型值

;RPL(RequestedPrivilegeLevel):

请求特权级,用于特权检查。

;TI(TableIndicato

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 外语学习 > 日语学习

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1