C中的内存起始位置

时间:2014-10-09 07:35:41

标签: c memory memory-layout

我正在研究给定进程的内存布局。我注意到每个进程的起始内存位置不是0.在这个website上,TEXT从0x08048000开始。一个原因可以是使用NULL指针区分地址。我只是想知道是否还有其他好的理由?感谢。

3 个答案:

答案 0 :(得分:3)

空指针实际上不必为0.在C标准中保证当在指针的上下文中给出0值时它被视为{{1编译器。

但是你在源代码中使用的0只是 syntactic sugar ,它与实际的物理地址无关,空指针值是"指向"到。

有关详细信息,请参阅:

您的操作系统上的应用程序有其独特的地址空间,它被视为连续的内存块(内存不是物理上连续的,它只是"印象"操作系统给每个程序。)

在大多数情况下,每个进程的虚拟内存空间都以类似且可预测的方式布局(这是Linux进程中的内存布局,32位模式):

Memory layout in a Linux process (图片来自Anatomy of a Program in Memory

查看文本段(x86上的默认.text基础是0x08048000,由静态绑定的默认链接描述文件选择)。

为什么神奇的0x08048000?可能是因为Linux从System V i386 ABI中借用了该地址。

......为什么System V使用0x08048000?

  

选择该值以容纳.text部分下面的堆栈,   向下发展。 0x48000字节可以由同一页面映射   .text部分已经需要的表(从而保存了一个页表   在大多数情况下),而剩余的0x08000000将允许更多的空间   对于渴望堆栈的应用程序。

有什么低于0x08048000吗?什么都没有(它只有128M),但是you can pretty much map anything you desire there, using the mmap() system call

另见:

答案 1 :(得分:2)

我认为这总结了一下:

  

每个进程都有自己的一组页表,但有一个问题。启用虚拟地址后,它们将应用于计算机中运行的所有软件,包括内核本身。因此,必须为内核保留一部分虚拟地址空间。

因此,虽然该过程获得了自己的地址空间。如果不向内核分配块,它将无法解决内核代码和数据。

这始终是它出现的第一个内存块,因此包含地址0.用户模式空间超出此范围,因此堆栈和堆都驻留在这里。

区别于NULL指针

即使用户模式空间在地址0处开始,也不会有任何数据分配给地址0,因为它将位于堆栈或堆中,而这些数据本身不会从用户区的开头。因此,NULL(值0)仍然可以使用,并且不是此布局的原因。

然而,与NULL和第一个块是内核内存相关的一个好处是任何读取/写入NULL的尝试都会引发分段错误。

答案 2 :(得分:0)

loader segments 中的二进制文件加载到内存中:text(常量),数据,代码。没有必要从0开始,因为C有来自bug的访问的问题,就像a[i]中甚至是危险的一样。这允许(在某些处理器上)拦截分段错误。

这将是C运行时从0引入线性地址空间。这可能是可以想象的,其中C是操作系统的实现语言。但没有任何目的;让堆从0开始。内存模型是一个段。某些处理器可能会保护代码段不被修改。

在段中,分配发生在C运行时管理的内存块中。

我可以补充一点,操作系统本身经常使用物理0及以上。