5

这个问题有一些关于 SO 的答案,但我的略有不同。在标记为重复之前,请试一试。

MSVC 一直提供 /Gy编译器选项,以使相同的函数能够折叠到 COMDAT 部分中。同时,链接器还提供了 /OPT:ICF 选项。我的理解是否正确,这两个选项必须结合使用?也就是说,虽然前者将功能打包到 COMDAT 中,但后者消除了多余的 COMDAT。那是对的吗?

如果是,那么我们要么都使用,要么都关闭?

4

2 回答 2

3

来自与我离线交流的人的回答。帮助我更好地理解这些选项。

====================================

这基本上是正确的。假设我们只谈论 C 或 C++,但没有成员函数。如果没有 /Gy,编译器会创建在某种意义上不可约的目标文件。如果链接器只需要对象中的一个函数,它就会全部获取。这是库编程中的一个特别考虑因素,因此,如果您打算善待库的用户,您应该将库编写为许多小目标文件,通常每个对象一个非静态函数,以便库不会因为必须携带实际上从未执行过的代码而膨胀。

使用 /Gy,编译器创建具有 COMDAT 的目标文件。每个函数都在它自己的 COMDAT 中,在某种程度上它是一个迷你对象。如果链接器只需要对象中的一个函数,它可以只挑出那个函数。链接器的 /OPT 开关让您可以控制链接器对这种选择性所做的事情 - 但没有 /Gy 就没有任何选择。

或者很少。例如,至少可以想象链接器可以折叠函数,这些函数是目标文件中的全部代码,并且恰好具有相同的代码。当然可以想象,链接器可以消除一个不包含任何引用的整个目标文件。毕竟,它是通过库中的目标文件来做到这一点的。然而,实践中的规则曾经是,如果您将非 COMDAT 目标文件添加到链接器的命令行,那么即使未引用,您也希望在二进制文件中使用它。可以想象的和已经完成的之间的差异通常是巨大的。

那么,最好坚持快速回答。链接器选项受益于能够从每个目标文件中分离函数(和变量),但分离取决于已组织到 COMDAT 中的代码和数据,这是编译器的工作。

====================================

于 2016-11-14T20:29:52.940 回答
1

正如Raymond Chen 在 2013 年 1 月回答的那样

正如 /Gy 的文档中所解释的,如果您通过 /OPT:REF 请求,函数级链接允许在“未使用函数”传递期间丢弃函数。它不会改变实际的经典链接模型。标志名称具有误导性。这不是“执行功能级链接”。它只是通过告诉链接器函数在哪里开始和结束来启用它。与其说是函数级链接,不如说是函数级取消链接。-雷蒙德

(这个片段在进一步的上下文中可能更有意义:这里是关于经典链接模型的帖子:1、2

简而言之 - 是的。如果您激活一个开关而没有另一个开关,则不会产生明显的影响。

于 2016-11-14T07:27:30.267 回答