是否允许 C++ 编译器发出编译同一程序的不同机器代码?

Posted

技术标签:

【中文标题】是否允许 C++ 编译器发出编译同一程序的不同机器代码?【英文标题】:Is a C++ compiler allowed to emit different machine code compiling the same program? 【发布时间】:2011-03-04 11:48:38 【问题描述】:

考虑一种情况。我们有一些特定的 C++ 编译器、一组特定的编译器设置和一个特定的 C++ 程序。

我们使用该编译器和这些设置编译该特定程序两次,每次都进行“干净编译”。

发出的机器代码应该相同(我不是指时间戳和其他花里胡哨的东西,我的意思是只有将要执行的真实代码)还是允许它在不同的编译中有所不同?

【问题讨论】:

@Neil Butterworth 回答了同样的问题。 IIRC,他解释了为什么即使一切似乎都相同,编译器也会产生不同的输出。我正在寻找它:) 这听起来像是一个技巧问题;) 如果编译器在某些情况下使用统计算法,那么是的,它可能会产生稍微不同的代码,即使用替代寄存器或代码布局。 标准是否说明了机器代码?不?那么,允许any 输出保留标准中指定的语义。尔格:是的。 您的编译器是否设置了随机化函数地址以防止有针对性的缓冲区溢出攻击? 【参考方案1】:

C++ 标准当然没有说明任何事情来防止这种情况发生。然而实际上,编译器通常是确定性的,所以给定相同的输入,它会产生相同的输出。

真正的问题主要是它认为环境的哪些部分作为其输入——有一些似乎假设构建机器的特征反映了目标的特征,并改变了它们的输出基于构建环境中隐含而不是明确声明的“输入”,例如通过编译器标志。也就是说,即使这样也相对不寻常。规范是输出依赖于显式输入(输入文件、命令行标志等)

顺便说一句,我只能想到一件“自发”改变的相当明显的事情:一些编译器和/或链接器将时间戳嵌入到它们的输出文件中,因此输出文件的几个字节会从一个构建更改为下一个构建--但这只会在文件中嵌入的元数据中,而不是对生成的实际代码的更改。

【讨论】:

我会为一个即时发明优化的非确定性编译器提供什么。 Visual Studio 提供配置文件引导优化。【参考方案2】:

根据标准中的 as-if 规则,只要符合标准的程序(例如,没有未定义的行为)无法区分,编译器就可以为所欲为。换句话说,只要程序产生相同的输出,标准中就没有禁止这样做的限制。

从实际的角度来看,我不会使用执行此操作的编译器来构建生产软件。我希望能够重新编译两年前发布的版本(使用相同的编译器等)并生成相同的机器代码。我不想担心我无法重现错误的原因是编译器决定今天做一些稍微不同的事情。

【讨论】:

出于多种目的,让编译器的输出是完全确定的,即使它不是最优的也是很有用的。例如,如果正在为开源投票机编译代码,则应该使用开源交叉编译器,无论编译器本身运行的环境如何,它总是会产生位相同的输出。如果通过多种独立方式从源代码引导的编译器版本都生成相同的代码,这将非常强烈地暗示编译器没有隐藏任何不在源代码中的“陷阱”。【参考方案3】:

无法保证它们会相同。也照http://www.mingw.org/wiki/My_executable_is_sometimes_different

当我编译和重新编译相同的源代码时,我的可执行文件有时会有所不同。这正常吗?

是的,默认情况下,根据设计,~MinGW 的 GCC 不会产生 ConsistentOutput,除非你修补它。

编辑:发现 this post 似乎解释了如何使它们相同。

【讨论】:

我点击了链接,但没有解释原因! @martin York 用另一个链接更新了我的帖子,以使它们相同。【参考方案4】:

我敢打赌,由于某些元数据编译器写入,它每次都会有所不同(例如,c# 编译的 dll 总是在某些字节上有所不同,即使我连续“构建”两次而不更改任何内容)。但无论如何,我永远不会相信它不会改变。

【讨论】:

以上是关于是否允许 C++ 编译器发出编译同一程序的不同机器代码?的主要内容,如果未能解决你的问题,请参考以下文章

同一个C语言程序,若在两台不同指令系统的机器上运行,编译后的程序是不是一样?能否用同一个编译器编译?

是否有编译为机器代码的 C C++ C# 编译器 [关闭]

编译器是否特定于操作系统?

允许写入/读取的在线 C++ 编译器

C++的多态总结(静态&动态)

带有 2 个编译器的 C++ [关闭]