2011-01-27 34 views
4

我问自己以下问题,当我在讨论this的话题。垃圾从其他链接单元

是否有这样的情况,当翻译单元中的一些未使用的代码将链接到GCC和VC++等流行编译器的最终可执行代码(当然是发布模式)?

例如,假设我们有2个编译单元:

//A.hpp 
//Here are declarations of some classes, functions, extern variables etc. 

和源文件

//A.cpp 
//defination of A.hpp declarations 

最后主要

//main.cpp 
//including A.hpp library 
#include "A.hpp" 
//here we will use some stuff from A.hpp library, but not everything 

我的问题是。如果在main.cpp中,不是所有来自A.hpp的东西都被使用了?链接器会删除所有未使用的代码,或者在某些情况下,当一些未使用的代码可以与可执行文件链接时?

编辑:我对G ++和VC++链接器感兴趣。

编辑:当然我的意思是在发布模式。

编辑:我开始赏金这个问题得到很好的和完整的答案。我在等待答案,这将解释在哪些情况下,g ++和VC++链接程序正在链接垃圾以及它们能够从可执行文件中删除哪些类型的代码(不需要的函数,不需要的全局变量,不需要的类定义等等)以及为什么他们不能删除某些不需要的东西。

+1

请指定编译器。 – leppie 2011-01-27 10:37:55

+0

对于GCC,在SO上搜索`-gc-sections`。我以前回答过这个问题。我认为它被称为VC++的函数级链接。 – leppie 2011-01-27 11:24:45

回答

4

正如其他海报所示,链接器通常不会在构建最终可执行文件之前删除死代码。但是,通常可以使用优化设置来强制链接器尝试执行此操作。

对于GCC,这两个阶段完成:

  1. 首先编译数据,而是告诉编译器翻译单元内的代码到单独的部分分开。这将为函数,类和外部变量通过使用以下两种编译器标志来完成:

    -fdata截面-ffunction截面

  2. 链接的转换单元一起使用的连接器优化标志(这将导致链接器丢弃未引用部分):

    轮候册, - GC-部分

所以,如果你曾要求TEST.CPP是曾在其声明的两个函数一个文件,但其中一人未使用,你可以省略未使用的一个使用下面的命令到GCC(克++):

gcc -Os -fdata-sections -ffunction-sections test.cpp -o test.o -Wl,--gc-sections 

(注意-Os是一个额外的连接体标志,告诉GCC以优化尺寸)

我也读的地方,连接静态库虽然不同。在这种情况下,GCC自动省略未使用的符号。也许另一张海报可以证实/反驳这一点。

至于MSVC,正如其他人所说的,功能级别链接完成同样的事情。 我相信,这个编译器标志(理清段):

/Gy 

然后链接标志(丢弃未使用的部分):

/OPT:REF 

编辑:经过进一步的研究,我认为GCC自动为静态库做这件事是错误的。

1

链接器不会删除代码。

您仍然可以在代码中动态地通过dlsym访问它。

1

一般来说,连接器往往包括一切从在命令行上明确传递的对象文件,但只有在这些目标文件从拉包含以解决目标文件已经链接的外部引用所需的符号的静态库。

但是,链接器可能会决定放弃从不被调用的函数或从未被引用的数据。确切的细节将取决于编译器和链接器开关。

在C++代码中,如果源文件被显式编译并链接到您的应用程序,那么我会期望包含静态存储持续时间的构造函数和/或析构函数的对象将被包含,并且它们的构造函数/析构函数将运行在适当的时候。因此,从这些构造函数或析构函数调用的任何代码都必须位于最终的可执行文件中。但是,如果代码没有从任何地方调用,那么你不能编写程序来判断代码是否包含在内,而不使用像dlsym这样的东西,所以链接器可能会忽略将它包含在最终的可执行文件中。

我也期待这样的,他们可以通过dlsym发现(而这仅仅是可执行可见“隐藏”符号)与全球知名度定义的任何符号会出现在最终的可执行文件。但是,这是一种期望,而不是我通过测试或阅读文档所证实的内容。

0

如果你想确保代码在你的可执行文件中,即使它没有在它内部被调用,你可以加载它作为一个静态感知动态链接库(一个静态感知库是一个自动加载到程序加载时的内存,与将字符串传递给加载库的函数并随后手动搜索钩子的功能相反)