Linux内存管理图解(1)逻辑地址转线性地址

来源:互联网 发布:vb.net sqlite3 编辑:程序博客网 时间:2024/05/17 07:04

一、逻辑地址转线性地址

   

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

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

mov    0x80495b0, %eax

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

 

 

 

 

 

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

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

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

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

cs             0x73     115

ss             0x7b     123

ds             0x7b     123

es             0x7b     123

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

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

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

 

 

 

原创粉丝点击