Linux下逻辑地址-线性地址-物理地址图解

转载 2016年08月29日 10:25:43

一、逻辑地址转线性地址

    机器语言指令中出现的内存地址,都是逻辑地址,需要转换成线性地址,再经过MMU(CPU中的内存管理单元)转换成物理地址才能够被访问到。

我们写个最简单的hello world程序,用gccs编译,再反编译后会看到以下指令:

mov    0x80495b0, %eax

这里的内存地址0x80495b0 就是一个逻辑地址,必须加上隐含的DS 数据段的基地址,才能构成线性地址。也就是说0x80495b0 是当前任务的DS数据段内的偏移。

 

 

 

 

 

x86保护模式下,段的信息(段基线性地址、长度、权限等)即段描述符8个字节,段信息无法直接存放在段寄存器中(段寄存器只有2字节)。Intel的设计是段描述符集中存放在GDTLDT中,而段寄存器存放的是段描述符在GDTLDT内的索引值(index)

Linux中逻辑地址等于线性地址。为什么这么说呢?因为Linux所有的段(用户代码段、用户数据段、内核代码段、内核数据段)的线性地址都是从 0x00000000 开始,长度4G,这样 线性地址=逻辑地址+ 0x00000000,也就是说逻辑地址等于线性地址了。

这样的情况下Linux只用到了GDT,不论是用户任务还是内核任务,都没有用到LDTGDT的第1213项段描述符是 __KERNEL_CS __KERNEL_DS,第1415项段描述符是 __USER_CS __USER_DS。内核任务使用__KERNEL_CS __KERNEL_DS,所有的用户任务共用__USER_CS __USER_DS,也就是说不需要给每个任务再单独分配段描述符。内核段描述符和用户段描述符虽然起始线性地址和长度都一样,但DPL(描述符特权级)是不一样的。__KERNEL_CS __KERNEL_DS DPL值为0(最高特权),__USER_CS __USER_DSDPL值为3

gdb调试程序的时候,用info reg 显示当前寄存器的值:

cs             0x73     115

ss             0x7b     123

ds             0x7b     123

es             0x7b     123

可以看到ds值为0x7b, 转换成二进制为 00000000 01111011TI字段值为0,表示使用GDTGDT索引值为 01111,即十进制15,对应的就是GDT内的__USER_DATA 用户数据段描述符。

从上面可以看到,Linuxx86的分段机制上运行,却通过一个巧妙的方式绕开了分段。

Linux主要以分页的方式实现内存管理。

二、线性地址转物理地址

前面说了Linux中逻辑地址等于线性地址,那么线性地址怎么对应到物理地址呢?这个大家都知道,那就是通过分页机制,具体的说,就是通过页表查找来对应物理地址。

准确的说分页是CPU提供的一种机制,Linux只是根据这种机制的规则,利用它实现了内存管理。

在保护模式下,控制寄存器CR0的最高位PG位控制着分页管理机制是否生效,如果PG=1,分页机制生效,需通过页表查找才能把线性地址转换物理地址。如果PG=0,则分页机制无效,线性地址就直接做为物理地址。

分页的基本原理是把内存划分成大小固定的若干单元,每个单元称为一页(page),每页包含4k字节的地址空间(为简化分析,我们不考虑扩展分页的情况)。这样每一页的起始地址都是4k字节对齐的。为了能转换成物理地址,我们需要给CPU提供当前任务的线性地址转物理地址的查找表,即页表(page table)。注意,为了实现每个任务的平坦的虚拟内存,每个任务都有自己的页目录表和页表

为了节约页表占用的内存空间,x86将线性地址通过页目录表和页表两级查找转换成物理地址。

32位的线性地址被分成3个部分:

最高10 Directory 页目录表偏移量,中间10 Table是页表偏移量,最低12Offset是物理页内的字节偏移量。

页目录表的大小为4k(刚好是一个页的大小),包含1024项,每个项4字节(32位),项目里存储的内容就是页表的物理地址。如果页目录表中的页表尚未分配,则物理地址填0

页表的大小也是4k,同样包含1024项,每个项4字节,内容为最终物理页的物理内存起始地址。

 

 

 

每个活动的任务,必须要先分配给它一个页目录表,并把页目录表的物理地址存入cr3寄存器。页表可以提前分配好,也可以在用到的时候再分配

还是以 mov    0x80495b0, %eax 中的地址为例分析一下线性地址转物理地址的过程。

前面说到Linux中逻辑地址等于线性地址,那么我们要转换的线性地址就是0x80495b0。转换的过程是由CPU自动完成的,Linux所要做的就是准备好转换所需的页目录表和页表(假设已经准备好,给页目录表和页表分配物理内存的过程很复杂,后面再分析)。

内核先将当前任务的页目录表的物理地址填入cr3寄存器。

线性地址 0x80495b0 转换成二进制后是 0000 1000 0000 0100 1001 0101 1011 0000,最高100000 1000 00的十进制是32CPU查看页目录表第32项,里面存放的是页表的物理地址。线性地址中间1000 0100 1001 的十进制是73,页表的第73项存储的是最终物理页的物理起始地址。物理页基地址加上线性地址中最低12位的偏移量,CPU就找到了线性地址最终对应的物理内存单元。

我们知道Linux中用户进程线性地址能寻址的范围是 3G,那么是不是需要提前先把这3G虚拟内存的页表都建立好呢?一般情况下,物理内存是远远小于3G的,加上同时有很多进程都在运行,根本无法给每个进程提前建立3G的线性地址页表。Linux利用CPU的一个机制解决了这个问题。进程创建后我们可以给页目录表的表项值都填0CPU在查找页表时,如果表项的内容为0,则会引发一个缺页异常,进程暂停执行,Linux内核这时候可以通过一系列复杂的算法给分配一个物理页,并把物理页的地址填入表项中,进程再恢复执行。当然进程在这个过程中是被蒙蔽的,它自己的感觉还是正常访问到了物理内存。

相关文章推荐

Linux下逻辑地址-线性地址-物理地址图解

转载:http://blog.csdn.net/wxzking/article/details/5905214 一、逻辑地址转线性地址     机器语言指令中出现的内存地址,都是逻辑地...
  • dfg0124
  • dfg0124
  • 2015年10月13日 21:30
  • 152

Linux下逻辑地址-线性地址-物理地址图解(转)

一、逻辑地址转线性地址      机器语言指令中出现的内存地址,都是逻辑地址,需要转换成线性地址,再经过MMU(CPU中的内存管理单元)转换成物理地址才能够被访问到。 我们写个最简单的hello wo...

Linux下逻辑地址、线性地址、物理地址详细总结

Linux中逻辑地址等于线性地址。为什么这么说呢?因为Linux所有的段(用户代码段、用户数据段、内核代码段、内核数据段)的线性地址都是从 0x00000000 开始,长度4G,这样 线性地址=逻辑地...

Linux--物理地址.虚拟内存.逻辑地址.线性地址

Linux--物理地址.虚拟内存.逻辑地址.线性地址 2010年12月17日 星期五 下午 02:01 本贴涉及的硬件平台是X86,如果是其它平台,嘻嘻,不保证能一一对号入座,...
  • junecau
  • junecau
  • 2011年09月10日 14:54
  • 385

Linux内存管理:逻辑地址到线性地址和物理地址的转换

本文图文结合简单清晰的讲述了Linux内核中逻辑地址到线性地址和线性地址到物理地址的转换过程...
  • Aryang
  • Aryang
  • 2013年07月16日 18:42
  • 2462

linux内存管理---虚拟地址、逻辑地址、线性地址、物理地址的区别(一)

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

Linux中的逻辑地址,线性地址和物理地址转换关系

一、逻辑地址转线性地址    机器语言指令中出现的内存地址,都是逻辑地址,需要转换成线性地址,再经过MMU(CPU中的内存管理单元)转换成物理地址才能够被访问到。我们写个最简单的hello world...
  • erazy0
  • erazy0
  • 2011年05月31日 18:06
  • 4975

Linux-0.11内核源码分析系列:关于线性地址,逻辑地址,物理地址的关系与区别

/* *Author : DavidLin *Date : 2014-11-22pm *Email : linpeng1577@163.com or l...

Linux_我理解的逻辑地址、线性地址、物理地址和虚拟地址(补充完整了)

要过年了,发个年终总结贴,只是个人理解,不包正确哈。 本贴涉及的硬件平台是X86,如果是其它平台,嘻嘻,不保证能一一对号入座,但是举一反三,我想是完全可行的。 一、概念 物理地址(p...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux下逻辑地址-线性地址-物理地址图解
举报原因:
原因补充:

(最多只允许输入30个字)