【问题标题】:Microsoft C/C++ linker optimization failing to discard unused code/dataMicrosoft C/C++ 链接器优化未能丢弃未使用的代码/数据
【发布时间】:2014-03-28 00:27:31
【问题描述】:

我正在编写一个包含不同压缩算法的 C++ 库,并允许用户指定一个特定的库,然后在用户调用 Compress()/Uncompress() 时使用该库。

问题:我使用的一些外部库(例如 zlib)是严格的 C,并且由于某种原因,链接器不会像您一样优化所有 zlib 函数和数据'期待。

示例:如果用户选择他希望使用 bzip,则没有指向 zlib 的代码路径,因此不应将任何 zlib 代码链接/包含在最终二进制文件中。事实上,在查看 /VERBOSE 链接器输出或生成的 .map 文件时,链接器甚至丢弃了我的包装 zlib 的 C++ 类。但是,大约 30KB 的 zlib 代码仍然包含在二进制文件中。

测试重现:一个简单的控制台应用程序,其 main 返回 0,但在 Visual Studio 项目中包含 zlib 源文件,还将添加大约 30KB 的额外代码。显然根本没有调用任何 zlib 函数的代码路径,那么为什么它仍然包含在可执行文件中? 地图文件中的 Zlib 符号:

0001:00000000       _adler32                   00401000 f   adler32.obj
0001:00002470       __tr_stored_block          00403470 f   trees.obj
0001:00002510       __tr_flush_block           00403510 f   trees.obj
...
0002:00001cc0       _z_errmsg                  0040bcc0     zutil.obj
0002:00002330       __dist_code                0040c330     trees.obj
0002:00002530       __length_code              0040c530     trees.obj
0002:00002720       _inflate_copyright         0040c720     inftrees.obj
0002:000039a0       _deflate_copyright         0040d9a0     deflate.obj
0002:00005a68       ??_C@_00CNPNBAHC@?$AA@     0040fa68     gzlib.obj
0002:00005a6c       ??_C@_0BF@CJFPCCEG@incompatible?5version?$AA@ 0040fa6c     zutil.obj
0002:00005a84       ??_C@_0N@DFPGLBGC@buffer?5error?$AA@ 0040fa84     zutil.obj
0002:00005a94       ??_C@_0BE@OGGJBMCE@insufficient?5memory?$AA@ 0040fa94     zutil.obj
0002:00005aa8       ??_C@_0L@HAHMBNLP@data?5error?$AA@ 0040faa8     zutil.obj
0002:00005ab4       ??_C@_0N@MKKNPMJD@stream?5error?$AA@ 0040fab4     zutil.obj
0002:00005ac4       ??_C@_0L@KIJFAKBJ@file?5error?$AA@ 0040fac4     zutil.obj
0002:00005ad0       ??_C@_0L@FNAOCBOG@stream?5end?$AA@ 0040fad0     zutil.obj
0002:00005adc       ??_C@_0BA@MOKMMFOD@need?5dictionary?$AA@ 0040fadc     zutil.obj
...
0001:00000270       _crc32_little              00401270 f    CIL library: CIL module
0001:00000530       _flush_pending             00401530 f    CIL library: CIL module
0001:00000580       _longest_match             00401580 f    CIL library: CIL module
0001:000006e0       _fill_window               004016e0 f    CIL library: CIL module
0001:00000920       _deflate_stored            00401920 f    CIL library: CIL module
0001:00000c10       _deflate_fast              00401c10 f    CIL library: CIL module
0001:00001000       _deflate_slow              00402000 f    CIL library: CIL module
0001:00001510       _init_block                00402510 f    CIL library: CIL module
0001:00001590       _pqdownheap                00402590 f    CIL library: CIL module
0001:00001670       _gen_bitlen                00402670 f    CIL library: CIL module
0001:00001870       _gen_codes                 00402870 f    CIL library: CIL module
0001:000018f0       _build_tree                004028f0 f    CIL library: CIL module
0001:00001af0       _scan_tree                 00402af0 f    CIL library: CIL module
0001:00001bd0       _send_tree                 00402bd0 f    CIL library: CIL module
0001:00002150       _build_bl_tree             00403150 f    CIL library: CIL module
0001:00002220       _send_all_trees            00403220 f    CIL library: CIL module
0001:00002760       _compress_block            00403760 f    CIL library: CIL module
0001:00002b40       _detect_data_type          00403b40 f    CIL library: CIL module
0001:00002bb0       _bi_flush                  00403bb0 f    CIL library: CIL module
0001:00002c30       _copy_block                00403c30 f    CIL library: CIL module

推测/请求帮助:我不是链接器专家,但似乎主要的罪魁祸首是 const 数组形式的数据。例如,由于在 zlib 的 deflate.c 的第 131 行定义了一个数组表,所以引入了所有 CIL 模块和一些其他函数:

local const config configuration_table[10] = {
/*      good lazy nice chain */
/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
/* 2 */ {4,    5, 16,    8, deflate_fast},
/* 3 */ {4,    6, 32,   32, deflate_fast},

/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
/* 5 */ {8,   16, 32,   32, deflate_slow},
/* 6 */ {8,   16, 128, 128, deflate_slow},
/* 7 */ {8,   32, 128, 256, deflate_slow},
/* 8 */ {32, 128, 258, 1024, deflate_slow},
/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */

因此,链接器会看到对函数的引用,并将它们全部链接起来。

有人知道这是为什么吗?如果我将 zlib 和其他相关库重建为 C++,我的库会更好地工作吗?是否存在可供我使用的解决方案,让我的库仅成功链接所需的库,而不是拉动所有其他压缩库?

感谢任何帮助!

【问题讨论】:

  • 是否启用优化?
  • 已启用优化,包括 c/c++ 编译器代码生成中的 /Gy 以及链接器 /OPT:REF 和 /OPT:ICF。
  • 该表包含指向函数的指针。如果使用了该表(或定义它的对象),则所有这些函数也将被使用,因为它们的地址已被占用。
  • 问题是这个测试项目中唯一的函数是:#include int wmain( int argc, wchar_t* argv[] ) { return 0; .... 所以对这个表或任何 zlib 函数的引用绝对为零。该表显然在 zlib 本身中使用,但我的主源文件没有引用任何 zlib。
  • 有同样的问题..

标签: c visual-c++ linker


【解决方案1】:

我遇到了同样的问题,我可以通过添加 /Gw 编译器开关来解决它。它将从最终的可执行文件中删除未使用的全局数据。更多信息在这里:https://blogs.msdn.microsoft.com/vcblog/2013/09/11/introducing-gw-compiler-switch/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    相关资源
    最近更新 更多