物理地址、逻辑地址、线性地址、虚拟地址

物理地址、逻辑地址、线性地址、虚拟地址


转自: https://www.zhihu.com/question/29918252/answer/163114415
https://blog.csdn.net/prike/article/details/52722934

物理地址

物理地址,CPU地址总线传来的地址,由硬件电路控制(现在这些硬件是可编程的了)其具体含义。物理地址中很大一部分是留给内存条中的内存的,但也常被映射到其他存储器上(如显存、BIOS等)。在没有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同地址的物理存储器被读写;而在使用了虚拟存储器的情况下,虚拟地址不是被直接送到内存地址总线上,而是送到存储器管理单元MMU,把虚拟地址映射为物理地址。

逻辑地址

**逻辑地址**,逻辑地址(logical address)是 selector:offset 这种形式,selector 是 CS 寄存器的值,offset 是 EIP 寄存器的值。如果用 selector 去 GDT( 全局描述符表 ) 里拿到 segment base address(段基址) 然后加上 offset(段内偏移),这就得到了 linear address。我们把这个过程称作段式内存管理。

逻辑地址是在有地址变换功能的计算机中,访内指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址,也就是是机器语言指令中,用来指定一个操作数或是一条指令的地址。要经过寻址方式的计算或变换才得到内存储器中的实际有效地址即物理地址。一个逻辑地址由两部份组成,段标识符: 段内偏移量。段标识符是由一个16位长的字段组成,称为段选择符。其中前13位是个索引号,后面3位包含一些硬件细节 。

CPU将一个逻辑地址转换为物理地址,需要进行两步:首先将给定一个逻辑地址(其实是段内偏移量,这个一定要理解!!!),CPU要利用其段式内存管理单元,先将为个逻辑地址转换成一个线程地址,再利用其页式内存管理单元,转换为最终物理地址。这样做两次转换,的确是非常麻烦而且没有必要的,因为直接可以把线性地址抽像给进程。之所以这样冗余,Intel完全是为了兼容而已(Intel为了兼容,将远古时代的段式内存管理方式保留了下来,x86体系的处理器刚开始时只有20根地址线,寻址寄存器是16位。我们知道16位的寄存器可以访问64K的地址空间,如果程序要想访问大于64K的内存,就需要把内存分段,每段64K,用段地址+偏移量的方式来访问,这样使20根地址线全用上,最大的寻址空间就可以到1M字节,这在当时已经是非常大的内存空间了。)。

线性地址

如果用 selector 去 GDT( 全局描述符表 ) 里拿到 segment base address(段基址) 然后加上 offset(段内偏移),这就得到了 linear address。

虚拟地址

题来了,为什么没提到 virtual address,这是个什么东西?其实在 Intel IA-32 手册里并没有提到这个术语,但是在内核的确是用到了这个概念,比如__va和__pa这两个宏定义。看似神秘的 virtual address 究其本质就是程序里面使用的地址比如一个指针值,指针的本质就是 EIP 寄存器里的值,说直白点,virtual address 就是 EIP 寄存器的值。你会发现我们上面说过,logical address 由 selector 和 offset 两部分组成,offset 也是 EIP 寄存器的值,所以结论为:logical address 的 offset 正是 virtual address,它俩是一个东西。

既然搞明白了 logical address 和 virtual address 的关系,那么我们再来看下,linear address 和 virtual address 是什么关系。在上面讲到的段式内存管理中,Linux 内核会将 segment base address(段基址)设成 0,于是就有 linear address = 0+offset,又因为 virtual address 就是 offset,所以算出的 linear address在数值上等于 virtual address,注意,是数值上等于,它们之间是差了段基址的,只不过段基址为 0 罢了。

按照 Intel 的设计,段式内存管理中的段类型分为三种:代码段(上面讲了)、数据段、系统段(TSS之类的),实在是太麻烦了。我们只靠页式内存管理就已经可以完成Linux内核需要的所有功能,根本不需要段映射,但是段映射这玩意儿又关不掉,那就只能上点手段了。于是,Linux内核将所有类型的段的 segment base address 都设成0,段限长都设成最大(具体数值不展开讲了,涉及到段描述符结构,很麻烦,这里理解成地址总线的最大寻址限度即可),那么这样一来所有段都重合了,也就是不分段了,此外由于段限长是地址总线的寻址限度,所以这也相当于所有段跟整个线性空间重合了。虚拟地址本来是在段内的偏移量,现在段就是整个线性空间,所以虚拟地址就成了在整个线性空间内的偏移量,这和线性地址的概念一样,所以内核开发者都已经将虚拟地址和线性地址当作一个东西了。像是 Understand The Linux Kernel 这本书里面为了避免混淆,除了在开头和术语表中引用了 virtual address 这个词组之外,其他地方全是用的 linear address。看完这个答案,你会发现我们绕了一圈回来,虽然逻辑地址的概念很清晰,但是虚拟地址和线性地址依然可以不作区分,因为区分了也没什么用,内核里这俩概念是通用的。不过,知道点区别还是不至于在某些时候把自己搞晕,尤其是有些书和教程里面这两个词不说缘由就混着用,这很蛋疼。好了,最后结论就是,这两个概念区分开来的确更加清晰,但如果不作区分而直接把虚拟地址看作线性地址的别名,对你理解内核也不会产生任何影响。

现代的多用户多进程操作系统,需要MMU, 才能达到每个用户进程都拥有自己独立的地址空间的目标。使用MMU, 操作系统划分出一段地址区域, 在这块地址区域中, 每个进程看到的内容都不一定一样。例如MICROSOFT WINDOWS操作系统将地址范围4M-2G划分为用户地址空间,进程A在地址0X400000(4M)映射了可执行文件,进程B同样在地址0X400000(4M)映射了可执行文件,如果A进程读地址0X400000, 读到的是A的可执行文件映射到RAM的内容,而进程B读取地址0X400000时,则读到的是B的可执行文件映射到RAM的内容。这就是MMU在当中进行地址转换所起的作用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值