应用程序的内存布局

Posted

技术标签:

【中文标题】应用程序的内存布局【英文标题】:Memory Layout of application 【发布时间】:2010-09-09 12:26:01 【问题描述】:

下面的问题让我很头疼。假设我有两个平台 具有相同的硬件、相同的操作系统和相同的编译器。如果我完全编译 相同的应用程序,我可以确定两台机器上的内存布局完全相同吗?换句话说,两个应用程序具有完全相同的虚拟地址空间,或者是 很有可能不是这种情况。

感谢您对此的看法!

【问题讨论】:

你为什么想知道?你想达到什么要求布局相同? 我建议您重新表述您的问题,因为不同于平台的布局。操作系统允许将内存部分放在不同的位置,包括来自应用程序的一个实例。到另一个。 【参考方案1】:

你不能指望它。作为一项安全功能,某些操作系统(包括 Windows)会在一定程度上随机化内存布局。

(这是一个支持链接:http://blogs.msdn.com/b/winsdk/archive/2009/11/30/how-to-disable-address-space-layout-randomization-aslr.aspx)

【讨论】:

为了清楚起见,它是一个运行时特征:(en.wikipedia.org/wiki/Address_space_layout_randomization) 即使没有 ASLR,布局也可能依赖于动态库的加载顺序。许多此类库仅使用默认的“首选地址”,因此会发生冲突并随之发生重定位。【参考方案2】:

极不可能应用程序将在同一地址空间中执行在同一平台上,但在另一台计算机上。其他应用程序可能正在运行,这将影响操作系统加载您的应用程序的位置。

需要考虑的另一点是某些应用程序会按需加载运行时库(也称为 DLL 和共享库)。当您的应用程序运行时,应用程序可能会加载或不加载一些 DLL。

在非嵌入式平台中,大多数应用程序并不关心确切的物理内存位置,也不必担心它们每次都加载到相同的位置。大多数嵌入式平台每次都在同一个地方加载它们的应用程序,因为它们没有足够的内存来移动它。

由于这些案例和其他人提到的情况,请勿将 CONSTANT MEMORY LOCATION 原则编码到您的程序中。会发生非常糟糕的事情,尤其是难以追踪和调试。

【讨论】:

【参考方案3】:

除了 Steven 指出的堆栈地址等动态问题外,还有编译时间和静态布局方面。

我已经认为两台机器是彼此的精确克隆是一种非常特殊的情况,因为您可能在 CPU 版本、库等方面存在微小差异。然后一些编译器(可能取决于某些选项)也将编译时间和可执行文件中的日期。例如,如果您的两个主机名具有不同的长度,或者这使用了长度不同的日期格式,则不仅这些字符串会有所不同,而且所有其他静态变量都可能在地址空间中略有变化。

我记得 gcc 在自动构建的某些架构上遇到了困难,因为在第 2 阶段生成的编译器与在第 3 阶段生成的编译器不同,因为这些愚蠢的原因。

【讨论】:

【参考方案4】:

__TIME__ 宏扩展到(开始)编译时间。此外,已确定 独立于您编译的每个 .cpp 文件,链接器可以消除重复的字符串。

因此,根据编译速度的不同,您的可执行文件最终可能不仅包含不同的__TIME__ 字符串,甚至还有不同数量的__TIME__ 字符串。

如果你工作到很晚,你可以看到 __DATE__ 字符串相同的内容;)

【讨论】:

@John:如果一个编译的静态变量数量与另一个编译不同,那么这些变量在内存中的布局方式不可能相同。 是的,但不是很确定,因为相同数量的静态数据不会告诉你什么。 @John Dibling:非确定性正是 Robert 不能依赖两个二进制文件相同的原因,即使有限的测试表明并非如此。【参考方案5】:

它们是否可能具有相同的内存布局?是的,这是一种可能。这可能吗?不是真的。

正如其他人指出的那样,地址空间随机化和__TIME__ 宏之类的事情可能会导致地址空间不同(无论是在编译时还是在运行时进行更改)。根据我的经验,许多编译器在使用完全相同的输入在同一台机器上运行两次时不会产生相同的输出(函数以不同的顺序在内存中布局等)。

这是一个修辞/智力问题,还是这会导致您在编写程序时遇到某种问题?

【讨论】:

以上是关于应用程序的内存布局的主要内容,如果未能解决你的问题,请参考以下文章

有关可执行程序(进程)的内存布局的更多信息

关于Linux中程序的内存布局

虚拟内存布局内存的分工堆与栈

一文你就懂C程序内存布局

程序的内存布局

剖析程序的内存布局