关于Linux程序内存布局模式的问题
下图引自该书关于Linux程序内存布局模式的问题,linux,memory-management,linux-kernel,Linux,Memory Management,Linux Kernel,下图引自该书 为什么程序内存区域限制在0xbffffff和0x8048000之间?这一选择背后的理由是什么?这个地区以外有什么 这张图片显示的应该是一个32位程序。64位程序的内存布局是什么 图中提到“启动时”,那么在运行期间布局会发生变化吗 最后,Linux内核也遵循这种布局吗 32位x86上的Linux传统上有3G/1G用户/内核划分 用户空间内存始终映射在0x00000000-0xBFFFFFFF范围内(即4GB中可以在32位模式下直接寻址的较低3GB)。在进程之间切换时,将重新映
- 为什么程序内存区域限制在
和0xbffffff
之间?这一选择背后的理由是什么?这个地区以外有什么0x8048000
- 这张图片显示的应该是一个32位程序。64位程序的内存布局是什么
- 图中提到“启动时”,那么在运行期间布局会发生变化吗
- 最后,Linux内核也遵循这种布局吗
- 32位x86上的Linux传统上有3G/1G用户/内核划分
- 用户空间内存始终映射在0x00000000-0xBFFFFFFF范围内(即4GB中可以在32位模式下直接寻址的较低3GB)。在进程之间切换时,将重新映射整个空间
- 内核内存始终映射到0xC0000000-0xFFFFFFFF范围(上限1GB)。它在用户空间的特权级别是不可访问的,但当上下文切换到内核时,它可以访问其所有内存,而无需重新映射任何内容
- 在x86上,堆栈向下增长(从高位开始,向低位地址移动)。这在CPU设计中几乎是一个任意的决定(这就是
/push
/pop
调用
/
指令对ret
所做的)。Linux在这个范围的顶端启动它 相反,默认情况下,程序数据映射到低端。从历史上看,内核映射在%esp
下方,因此可供用户空间使用的最低地址位于该地址上方。这不再正确,但它解释了原始的0x08000000
加载地址0x0804000
- 中间的空间用于堆。通过调用
或brk()
将“Break”标记向上/向下移动;下面的内存可供程序使用。从历史上看,C运行时将程序分解以满足sbrk()
的空间要求malloc
- 在当前64位x86 CPU上,只有地址0x0000000000000000-0x00007FFFFFFFFFFFFFFF和0xFFFF80000000000-0xFFFFFFFFFFFFFF是规范的。64位指针,但“只有”48位的可用地址空间。(这是256TB,所以我们需要一段时间才能达到该限制。)如果您尝试访问任何非规范地址(0x000008000000000-0xFFFF7FFFFFFFFFFF),硬件将触发故障。Linux在下半部分映射用户空间,在上半部分映射内核 堆栈仍在向下增长,因此Linux仍会朝着范围的顶部启动,而固定映射则朝着底部启动,堆在其上方增长
- 对。除了程序分解会随着堆的增长和收缩而上下移动外,程序还可以使用
/mmap
将各种内容映射/取消映射到其地址空间,例如文件、共享内存、匿名内存等。事实上,现在的C运行时除了操纵程序中断之外,还将匿名内存映射成块munmap
- 内核本身位于32位x86上的上1G和64位x86上的上128TB。它的布局对用户空间来说基本上不重要(也不可见),但包括诸如每个内核线程的堆栈和每个用户线程的内核端、页表、缓存、DMA缓冲区等
NULL
是一个错误的地址(这可能会导致它是否实际有效),内核现在强制执行默认为64k的地址
现在的Linux(现在已经超过十年了)将数据映射到一个极高的地址,因此堆栈从这个地址开始。从前,vsyscall页也在上面,但现在它位于内核空间的一页中
由于错误,所有地址都可能被乱排。这在32位地址空间上不是很有效(由于页面对齐,不能将较低的12位随机化,可能由于其他限制而使其随机化),但在64位模式下有很多位。- 32位x86上的Linux传统上有3G/1G用户/内核划分
- 用户空间内存始终映射在0x00000000-0xBFFFFFFF范围内(即4GB中可以在32位模式下直接寻址的较低3GB)。在进程之间切换时,将重新映射整个空间
- 内核内存始终映射到0xC0000000-0xFFFFFFFF范围(上限1GB)。它在用户空间的特权级别是不可访问的,但当上下文切换到内核时,它可以访问其所有内存,而无需重新映射任何内容
- 在x86上,堆栈向下增长(从高位开始,向低位地址移动)。这在CPU设计中几乎是一个任意的决定(这就是
/push
/pop
调用
/
指令对ret
所做的)。Linux在这个范围的顶端启动它 相反,默认情况下,程序数据映射到低端。从历史上看,内核映射在%esp
下方,因此可供用户空间使用的最低地址位于该地址上方。这不再正确,但它解释了原始的0x08000000
加载地址0x0804000
- 中间的空间用于堆。通过调用
或brk()
将“Break”标记向上/向下移动;下面的内存可供程序使用。从历史上看,C运行时将程序分解以满足sbrk()
的空间要求malloc
- 在当前64位x86 CPU上,