标题:内存寻址:逻辑地址到物理地址转化
我们知道,在计算机⾥,内存分为虚拟内存和物理内存。 数据是存放在物理内存中的,⽽程序中使⽤的是虚拟内存并通过虚拟内存地址来访问数据和代码的,那么操作系统是如何 将虚拟内存地址映射成为实际的物理内存的呢?这是我们这篇⽂章要详细介绍的问题。
以X86的32位系统为例。如下图所⽰,在⽬前的32位的系统中,系统的内存虚拟地址范围为4GB。 其中低2GB主要为应⽤程序使⽤(Ring3级别),⽽⾼2GB为系统内核使⽤(Ring0级别)。 每⼀个程序都有属于⾃⼰的⼀个私有2GB虚存空间,⽽其中的低64KB为NULL 地址区域。 从中看出,NULL不单单是0,⽽是⼀个⼤⼩范围为[0,64KB]这样的⼀个区域。 ⽽在[0x7fff0000, 0x7fffffff]区域也被定义为⾮法区域,禁⽌程序访问, 这样做的⽬的是禁⽌处于Ring3级别的应⽤程序不⼩⼼访问了处于Ring 0级别的内核空间。
X86⽀持32位寻址,因此可以⽀持最⼤232=4GB的虚拟内存空间(当然也可以通过PAE将寻址空间扩⼤到64GB,PAE即Physical address extension,x86的处理器增加了额外的地址线以选择那些增加了的内存,所以实体内存的⼤⼩从32位增加到了36位。最⼤的实体内存由4GB增加到了64GB)。如下图所⽰,在4G 的虚拟地址空间中,Windows系统的内存主要分为内核空间和应⽤层空间上下两部分,每部
分各占约2GB,其中还包括了⼀个64KB的NULL空间以及⾮法区域,虚拟地址再通过页表机制映射到物理地址以便存取物理内存中的数据和指令。
X64(AMD64)的内存布局与X86的内存布局类似,不同的地⽅在于各⾃空间的范围和⼤⼩不同,同时X64下还存在着⼀些空洞(hole)。在X64内存理论上⽀持最⼤264的寻址空间,但实际上这个空间太⼤了,⽬前根本⽤不完,因此实际上的X64系统⼀般都只⽀持到40多位(⽐如Windows⽀持44位最⼤寻址空间为16TB,Linux ⽀持48位最⼤寻址空间256TB等),⽀持的空间达到了TB级别。但是,⽆论是在内核空间还是在应⽤层空间,这些上TB的空间并不都是可⽤的,存在着所谓的空洞(HOLE)。
分区X86 32位
Windows
X64 64位
Windows
空指针赋值分区0x00000000
0x0000FFFF
0x00000000'00000000
0x00000000'0000FFFF
⽤户模式分区0x00010000
0x7FFEFFFF
0x00000000'00010000
0x000007FF'FFFEFFFF
64KB禁⼊分区0x7FFF0000 0x7FFFFFFF
0x000007FF'FFFF0000
0x000007FF'FFFFFFFF
内核模式分区0x80000000
0xFFFFFFFF
0x00000800'00000000
0xFFFFFFFF'FFFFFFFF
CPU地址总线长度以及寻址范围如下:8086 20 bit
8088 20 bit
80286 24 bit
80386SX 24 bit
80386DX 32 bit
80486SX 32 bit
80486DX 32 bit
Pentium I 32 bit
K6 32 bit
Duron 32 bit
Athlon 32 bit
Athlon XP 32 bit
麻辣料理人Celeron 36 bit
Pentium Pro 36 bit
Pentium II 36 bit
Pentium III 36 bit
Pentium 4 36 bit
Athlon 40 bit
Athlon-64 40 bit
Athlon-64 FX 40 bit
Opteron 40 bit
Itanium 44 bit
Itanium 2 44 bit
20 bits 1MB
24 bits 16MB
32 bits 4GB
36 bits 64GB
40 bits 1TB十大名表排名
骄字组词44 bits 16TB
程序在执⾏时,传递给CPU的地址是逻辑地址,它由两部分组成,⼀部分是段选择符(⽐如cs和ds等
段寄存器的值), 另⼀部分为有效地址(即偏移量,⽐如eip寄存器的值)。逻辑地址必须经过映射转换变为线性地址, 线性地址再经过⼀次映射转为物理地址,才能访问真正的物理内存。转化过程如下:
1)⾸先逻辑地址需要转化为线性地址。
逻辑地址是以"段寄存器:偏移地址"形式存在的。段寄存器是⼀个16位的寄存器, 其中第0和1位控制着将要访问段的特权级,第2位说明是在GDT还是LDT寻地址。 ⾼13位作为⼀个索引值,总共8192个索引。如下图所⽰,通过段寄存器⾥的索引,可以从段描述符表⾥到段的基址。 然后⽤基址加上段内的偏移量,就得到了对应的线性地址。
2)接着线性地址再转化为物理地址。
线性地址可以分为三部分:页⽬录索引,页表索引,和字节偏移索引。如下图所⽰,通过页⽬录索引和CR3寄存器指定的页⽬录基址之和,可以查询到对应的页表基址。再通过页表索引和页表基址之和,
可以得到对应的页框地址,页框地址再加上页内字节偏移,就最终获得了对应的物理地址。
从C源代码经过编译器编译,链接器链接⽣成可执⾏⽂件之后,接下来程序是怎么执⾏起来的呢?
仙剑奇侠传三片头曲
接下来,操作系统会将可执⾏⽂件加载⼊内存,CPU将从程序的第⼀个指令开始执⾏。在理解CPU是如何执⾏程序之前,先来看看CPU的构造。CPU主要由运算器、控制器、寄存器组和内部总线等构成。 ALU:运算器是计算机中执⾏各种算术和逻辑运算操作的部件。运算器由算术逻辑单元(ALU,Arithmetic Logical Unit)、累加器、状态寄存器、通⽤寄存器组等组成。算术逻辑运算单元(ALU)的基本功能为加、减、乘、除四则运算,与、或、⾮、异或等逻辑操作,以及移位、求补等操作。计算机运⾏时,运算器的操作和操作种类由控制器决定。运算器处理的数据来⾃存储器;处理后的结果数据通常送回存储器,或暂时寄存在运算器中。 CU:控制器是计算机的指挥中⼼,负责决定执⾏程序的顺序,给出执⾏指令时机器各部件需要的操作控制命令。由程序计数器、指令寄存器、指令译码器、时序产⽣器和操作控制器组成,它是发布命令的“决策机构”,即完成协调和指挥整个计算机系统的操作。控制器从内存中取出⼀条指令,并指出下⼀条指令在内存中位置,对指令进⾏译码或测试,并产⽣相应的操作控制信号,以便启动规定的动作,指挥并控制CPU、内存和输⼊/输出设备之间数据流动的⽅向。 寄存器组⽤于在指令执⾏过后存放操作数和中间数据,由运算器完成指令所规定的运算及操作。
1)系统总线
CPU的系统总线包括控制总线,数据总线,地址总线。
数据总线⽤于传送数据信息。数据总线是双向总线,即它既可以把CPU的数据传送到存储器或I/O接⼝等其他部件,也可以将其他部件的数据传送到CPU。 地址总线是专门⽤来传送地址的,由于地址只能从CPU传向外部存储器或I/O端⼝,所以地址总线总是单向的,这与数据总线不同。地址总线的位数决定了CPU可直接寻址的内存空间⼤⼩,⽐如8位微机的地址总线为16位,则其最⼤可寻址空间为216=
64KB,16位微型机的地址总线为20位,其可寻址空间为220=1MB。⼀般来说,若地址总线为n位,则可寻址空间为2n字节。有的系统中,数据总线和地址总线是复⽤的,即总线在某些时刻出现的信号表⽰数据⽽另⼀些时刻表⽰地址,⽽有的系统则是分开的。 控制总线⽤来传送控制信号。控制信号中,有的是微处理器送往存储器和I/O接⼝电路的,如读/写,中断响应信号等; 也有是其他部件反馈给CPU 的,⽐如:中断申请、复位、总线请求、设备就绪等。因此,控制总线的传送⽅向由具体控制信号⽽定, ⼀般是双向的,控制总线的位数要根据系统的实际控制需要⽽定。实际上控制总线的具体情况主要取决于CPU。
2)寄存器
CPU的⼀个重要组成部分就是它的寄存器。 计算机体系结构中常⽤到的寄存器包括以下⼏类寄存器(以32位X86系统为例):
车险一般买哪些a) 通⽤寄存器:EAX,EBX,ECX,EDX
b) 源变址⽬标变址寄存器:ESI,EDI
c) 栈相关寄存器:SS,ESP,EBP
d) 代码段寄存器,程序指令寄存器:CS,IP
e) 数据段寄存器:DS(常与ESI寄存器结合使⽤)
f) 附加段寄存器:ES(常与EDI寄存器集合使⽤)
g) Flag标志寄存器:
ZF 零标志,零标志ZF⽤来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0;
AF 辅助进位标志,运算过程中第三位有进位值,置AF=1,否则,AF=0;
PF 奇偶标志,当结果操作数中偶数个"1",置PF=1,否则,PF=0;
SF 符号标志,当结果为负时,SF=1;否则,SF=0。溢出时情形例外;
CF 进位标志,最⾼有效位产⽣进位值,例如,执⾏加法指令时,MSB(最⾼位)有进位,置CF=1;否则,CF=0;
OF 溢出标志,若操作数结果超出了机器能表⽰的范围,则产⽣溢出,置OF=1,否则,OF=0。
在64位系统中,寄存器的表⽰⽅法为:
通⽤寄存器:rax, rbx, rcx, rdx
栈寄存器:rsp, rbp
传递参数的寄存器:rdi, rsi, (rdx, rcx,) r8, r9(arguments)
Scratch寄存器:(rbx,) r12, r13, r14, r15(scratch),即可以随时改写的寄存器
哪些专业就业前景好那么,CPU是如何⼀条条执⾏程序的指令的呢?如下⾯CPU执⾏指令图所⽰, ⾸先,CPU中的CS寄存器指向了程序被加载内存之后所在代码段的基址,⽽IP寄存器指向了下⼀条程序要执⾏的指令。 CS中的段基址加上IP寄存器中的值,形成⼀个线性地址,这个线性地址经过转换,形成物理地址,然后通过地址总线, 在对应的内存地址获得对应的⼀条指令,再把对应的指令通过数据总线传输到CPU的指令缓冲器中, 然后由指令缓冲器传给指令执⾏控制器,执⾏对应的指令。
内存的寻址模式讨论
逻辑地址,线性地址,物理地址
1.逻辑地址是编译器⽣成的,我们使⽤在linux环境下,使⽤C语⾔指针时,指针的值就是逻辑地址。对于每个进程⽽⾔,他们都有⼀样的进程地址空间,类似的逻辑地址,甚⾄很可能相同。逻辑地址由段地址+段内偏移组成
2.线性地址是由分段机制将逻辑地址转化⽽来的,如果没有分段机制作⽤,那么程序的逻辑地址就是线性地址了。
3.物理地址是CPU在地址总线上发出的电平信号,要得到物理地址,必须要将逻辑地址经过分段,分页等机制转化⽽来。
x86体系结构下,使⽤的较多的内存寻址模型主要有三种:
1. 实模式扁平模型 real mode flat model
2. 实模式分段模型 real mode segment model
3. 保护模式扁平模型 protected mode flat model
发布评论