内存寻址(上)

来源:互联网 发布:美国退出量化宽松知乎 编辑:程序博客网 时间:2024/06/07 06:16

内存地址

在操作系统中,一般会引用三种地址描述方式:

逻辑地址(logical address

每一个逻辑地址由一个段地址和偏移地址组成。在有地址变换功能的计算机中,访问指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址。

线性地址(linear address

由一块连续的虚拟内存空间组成。在80x86微处理器中是一个32位无符号整数,可以用来表示4GB的地址,也就是4294967个内存单元。

物理地址(physical address

是计算机内的实际地址,它们与从微处理器的地址引脚发送到内存总线上的电信号对应。在80x86微处理器中由32位或36位无符号整数表示。

内存寻址流程:

地址间转换关系

分段机制

硬件中的分段机制

从80286模型开始,Intel微处理器以两种不同的方式执行地址转换,这两种方式分别为实模式(real mode)和保护模式(protested mode)。实模式被特殊定义为20位地址内存可访问空间上,这就意味着它的容量是2的20次幂(1M)的可访问内存空间(物理内存和BIOS-ROM),软件可通过这些地址直接访问BIOS程序和外围硬件。

实模式下寻址方式

保护模式又被称作为虚拟地址,它本身本身是80286及以后兼容处理器序列之后产成的一种操作模式,它具有许多特性设计为提高系统的多道任务和系统的稳定性。例如内存的保护,分页机制和硬件虚拟存储的支持。现代多数的x86处理器操作系统都运行在保护模式下,包括Linux, Free BSD。

保护模式下寻址方式

段选择符和段寄存器:

一个逻辑地址由两部分组成:一个段标识符和一个指定端内相对地址的偏移量。段标识符是一个16位长的字段,称作段选择符,而偏移量是一个32位字长的字段。为了方便地找到段选择符,处理器提供段寄存器,段寄存器的唯一目的是存放段选择符。

段选择符

段描述符:

每个段由一个8字节的段描述符表示,他描述了段的特征。段描述符放在全局描述符表(Gloabal Descriptor Table,GDT),或LDT(Local Descriptor Table,LDT)中。

段描述符

快速访问描述符:

为了加速逻辑地址到线性地址额转换,80x86处理器提供了一种附加的非编程的寄存器,供6个可编程的段寄存器使用。每当一个段选择符被装入段寄存器时,相应的段描述符就由内存装入到对应的非编程CPU寄存器。从那时起,针对那个段的逻辑地址转换就可以不访问主存中的GDT或LDT,处理器只需直接引用存放段描述符的CPU寄存器。

段选择符和段描述符

分段单元

分段单元执行以下操作

先检查段选择符的TI字段,以决定段描述符保存在哪一个描述符表中。TI字段指明描述符是在GDT中还是在LDT中。从段选择符的index字段计算段描述符的地址,index字段的值乘以8,这个结果与gdtr或ldtr寄存器中的内容相加。把逻辑地址的偏移量与段描述符Base字段的值相加就得到了线性地址。

这里写图片描述

Linux中的分段

Linux以非常有限的方式使用分段,与分段相比,Linux更喜欢使用分页方式,因为:

当所有进程使用相同的段寄存器值时,内存管理变得更简单,也就是说它们能共享同样的一组线性地址Linux设计目标之一是可以把它移植到绝大多数流行的处理器平台上。然而,RISC体系结构对分段的支持十分有限。

Linux 2.6只有在80x86结构下才需要使用 分段。
运行在用户态和运行在内核态的进程使用不同的段描述符,于是在Linux下就有了4个重要的段描述符字段:
用户代码段
用户数据段
内核代码段
内核数据段
相应的段选择符由宏__USER_CS,__USER_DS,__KERNEL_CS,__KERNEL_DS分别定义。

Linux GDT

在单处理器系统中只有一个GDT,在多处理器系统中系统每个CPU对应一个GDT。所有的GDT都存放在cpu_gdt_table数组中,所有GDT的地址和它们的大小被存放在cpu_gdt_dsescr数组中。
每个GDT包含18个段描述符和14个空的,未使用的或保留的项。

每个GDT中包含的18个段描述符指向下列段

用户和内核态下的代码段和数据段共4个。任务状态段(TSS),每个处理器有1个。1个包括缺省局部描述符表的段,这个段通常是被所有进程共享的段3个局部线程储存(Thread-Local Storage,TLS)段,这种机制允许多线程应用程序使用最多3个局部与线程的数据段。与高级电源管理(AMP)相关的3个段。与支持即插即用(PnP)功能BIOS服务程序相关的5个段。被内核用来处理“双重错误”异常的特殊TSS段。

这里写图片描述

Linux LDT

大多数用户态下的Linux程序不使用局部描述符表,这样内核就定义了一个缺省的LDT供大多数进程共享。缺省的局部描述符表存放在default_ldt数组中。

2 0
原创粉丝点击