c++ 为什么可执行文件这么大? (为什么没有删除死代码?)

编译和链接此文件将导致1 KiB可执行文件:

#pragma comment(linker, "/Entry:mainCRTStartup") // No CRT code (reduce size)
#pragma comment(linker, "/Subsystem:Console")    // Needed if avoiding CRT

#define STRINGIFIER(x)    func##x
#define STRINGIFY(x)      STRINGIFIER(x)
#define G   int STRINGIFY(__COUNTER__)(void) { return __COUNTER__; }

int mainCRTStartup(void) { return 0; }  // Does nothing

#if 0
    // Every `G' generates a new, unused function
    G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G
    G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G G
#endif

当您将#if 0更改为#if 1)时,输出大小加倍至2 KiB。

尽管我的命令行选项包含了我可以想到的所有优化,但它似乎与迄今为止所有版本的Visual C都这样做:

/Ox /MD /link /fixed /OPT:ICF /OPT:REF

具体来说,我没有包含任何调试信息。

有人知道为什么/ OPT:REF不会导致链接器删除未使用的函数?

最佳答案
在广义上,编译器生成包含一堆汇编代码和支持信息的“对象记录”中的代码。链接器将这些对象记录链接在一起以创建可执行文件。

通常,编译器将为整个源文件创建单个对象记录。在这种情况下,链接器只能决定链接整个对象记录。由于在使用的对象记录中至少存在一个函数,所以必须链接所有这些函数。

在某些编译器上,您可以告诉它为每个函数生成一个单独的对象记录(一个对象文件可以有多个对象记录)。在这种情况下,如果链接器从未被调用,则可以决定省略一些对象记录。

/OPT的Microsoft文档:

/OPT:REF

LINK removes unreferenced packaged functions by default. An object contains packaged functions (COMDATs) if it has been compiled with the /Gy option. This optimization is called transitive COMDAT elimination. To override this default and keep unreferenced COMDATs in the program, specify /OPT:NOREF. You can use the /INCLUDE option to override the removal of a specific symbol.

/Gy编译器选项启用功能级链接。

作为参考,此功能也存在于gcc中:

-ffunction-sections
-fdata-sections

Place each function or data item into its own section in the output file if the target supports arbitrary sections. The name of the function or the name of the data item determines the section’s name in the output file.

Use these options on systems where the linker can perform optimizations to improve locality of reference in the instruction space. Most systems using the ELF object format and SPARC processors running Solaris 2 have linkers with such optimizations. AIX may have these optimizations in the future.

Only use these options when there are significant benefits from doing so. When you specify these options, the assembler and linker will create larger object and executable files and will also be slower. You will not be able to use “gprof” on all systems if you specify this option and you may have problems with debugging if you specify both this option and -g.

和ld中的配套选项:

–gc-sections

Enable garbage collection of unused input sections. It is ignored on targets that do not support this option. This option is not compatible with -r or –emit-relocs. The default behaviour (of not performing this garbage collection) can be restored by specifying –no-gc-sections on the command line.

转载注明原文:c++ 为什么可执行文件这么大? (为什么没有删除死代码?) - 代码日志