虚拟地址空间包含了若干区域,其分布方式是特定于体系结构的。但是基本都包含下列共同的成分。
- 当前运行代码的二进制代码,代码段又称为text,所处的地址空间由称为text段。
- 程序使用的动态库的代码
- 存储全局变量和动态产生的数据的堆。
- 用于保存局部变量和实现函数/过程调用的栈
- 环境变量和命令行参数的段
- 将文件内容映射到虚拟地址空间的内存映射。
是由elf标准确定。每个体系结构都指定了一个特定起始地址,因此这里我们用两个最常见的体系结构IA32和ARM9为列,讨论不同架构下的进程地址空间分布。
IA32地址空间划分
首先地址空间的划分并不是固定不变的,即便是架构已经确定的情况下,仍然有一些宏会影响到地址空间布局。
1. text段
IA32 text段起始地址是0x08048000,在text段起始地址和最低可用地址间保留了大约128MB地址空间,这个保留空间的作用主要是用来捕获空指针,其他的架构应该也有类系的空洞。
2. 堆
堆的起始位置紧跟着text的结束位置,堆的起始位置固定为mm_struct->start_brk,但是堆的结束位置mm_struct->brk是可变的,向上增长。
3. 栈
栈起始于STACK_TOP,这个位置也就是TASK_SIZE(用户空间的最高可用地址,3:1划分的情况下,是3G),但是如果进程设置了PF_RANDOMIZE标记,那么起始点就是TASK_SIZE减去一个小的随机量,每个体系结构必须定义STACK_TOP。进程的参数列表和环境变量都是栈的初始数据。
4. 内存映射区
内存映射区起始于mm_struct->mmap_base,设置为TASK_UNMAPPED_BASE,这个宏是体系结构特定的,对于IA32来说,定义如下
(PAGE_ALIGN(TASK_SIZE / 3))
因此对于上面描述的地址空间划分,我们可以得到下图
但是这样布局有一个问题,就是堆的空间被限制在text_end到TASK_UNMAPPED_SIZE之间,也就是说不到1GB,继续增长就会破坏内存映射区。
而MMAP和stack却共用了接近2GB的空间。
因此一个新的进程布局在2.6.7后被提出来
这种布局方法,栈的大小被限制死了;而MMAP则变为向下增长和Heap共用接近3GB的地址空间,这样看起来就合理多了。
为确保stack和mmap直接冲突,在mmap上面设置了安全隔离区。