简体   繁体   English

为什么可执行文件如此之大? (为什么不删除死代码?)

[英]Why is the executable so big? (Why isn't dead code removed?)

Compilng and linking this file results in a 1-KiB executable : 编译和链接此文件会生成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

When you change #if 0 to #if 1 ), the output size doubles to 2 KiB. 当您将#if 0更改为#if 1 ,输出大小将增加一倍至2 KiB。

It seems to do this with all versions of Visual C++ to date, even though my command-line options contain all optimizations I could think of: 它似乎与迄今为止所有版本的Visual C ++都这样做,即使我的命令行选项包含我能想到的所有优化:

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

and, specifically, I did not include any debugging information. 而且,具体来说,我没有包含任何调试信息。

Does anyone know why /OPT:REF is not causing the linker to remove the unused functions? 有谁知道为什么/OPT:REF没有导致链接器删除未使用的函数?

In broad terms... the compiler generates code in "object records" that contains a bunch of assembly code and supporting information. 从广义上讲,编译器在“对象记录”中生成代码,其中包含一堆汇编代码和支持信息。 The linker links these object records together to create an executable. 链接器将这些对象记录链接在一起以创建可执行文件。

Often a compiler will create a single object record for an entire source file. 编译器通常会为整个源文件创建单个对象记录。 In this case, the linker can only decide to link in the entire object record, or not. 在这种情况下,链接器只能决定是否链接整个对象记录。 Since there is at least one function in the object record that is used, it must link in all of it. 由于在对象记录中至少有一个函数,它必须在所有函数中链接。

On some compilers, you can tell it to generate a separate object record for each function (an object file can have multiple object records ). 在某些编译器上,您可以告诉它为每个函数生成单独的对象记录(对象文件可以有多个对象记录 )。 In this case, the linker can make the decision to omit some of the object records if they're never called. 在这种情况下,如果从未调用过,链接器可以决定省略某些对象记录。

From the Microsoft documentation for /OPT : / OPT的Microsoft文档:

/OPT:REF / OPT:REF

LINK removes unreferenced packaged functions by default. LINK默认删除未引用的打包函数。 An object contains packaged functions (COMDATs) if it has been compiled with the /Gy option. 如果对象包含已使用/ Gy选项编译的打包函数(COMDAT),则该对象包含该函数。 This optimization is called transitive COMDAT elimination. 此优化称为传递COMDAT消除。 To override this default and keep unreferenced COMDATs in the program, specify /OPT:NOREF. 要覆盖此默认值并在程序中保留未引用的COMDAT,请指定/ OPT:NOREF。 You can use the /INCLUDE option to override the removal of a specific symbol. 您可以使用/ INCLUDE选项覆盖特定符号的删除。

The /Gy compiler option enables function-level linking. /Gy编译器选项启用功能级链接。

For reference, this feature also exists in gcc: 作为参考,gcc中也存在此功能:

-ffunction-sections -ffunction截面
-fdata-sections -fdata截面

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. 大多数使用ELF对象格式的系统和运行Solaris 2的SPARC处理器都具有这种优化的链接器。 AIX may have these optimizations in the future. AIX可能会在将来进行这些优化。

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. 如果指定此选项,则无法在所有系统上使用“gprof”,如果同时指定此选项和-g,则可能无法进行调试。

And the companion option in ld: 和ld中的伴侣选项:

--gc-sections --gc截面

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. 此选项与-r或--emit-relocs不兼容。 The default behaviour (of not performing this garbage collection) can be restored by specifying --no-gc-sections on the command line. 可以通过在命令行上指定--no-gc-sections来恢复默认行为(不执行此垃圾收集)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM