4

我最近发现了 LLVM 的链接器,它因链接lld速度非常快而受到称赞。事实上,我对其进行了测试,结果非常棒,与gold.

但是,在谈到链接时优化时,我的知识是有限的。据我通过阅读互联网上的资料了解到,目标文件中产生了一些额外的代码,代表一些内部编译器结构,然后在链接阶段使用。因此,我担心的是链接时优化(及其好处)是否受此编译器/链接器组合的影响。我将不胜感激有关此事的一些解释!

我使用gcc了版本9.2.0lld版本10.0.0

我用于生成目标文件的命令:

/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -O3 -g -DNDEBUG -o my_object.cpp.o -c my_source_file.cpp

对于链接:

#-fuse-ld=gold
/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -pie -fuse-ld=gold -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -static-libstdc++ -static-libgcc -Wl,--threads -Wl,--thread-count,1
#-fuse-ld=lld
/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -pie -fuse-ld=lld -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -static-libstdc++ -static-libgcc -Wl,--threads -Wl,
4

1 回答 1

4

我做了一些研究,最后自己得出结论,如果我们lld在编译时使用gcc. 我做了什么:

基于这个有点模糊的介绍:https://www.slideshare.net/chimerawang/gcc-lto,我发现链接器不是直接进行优化,而是在读取所有目标文件中的所有符号后,他将信息传递给lto-wrapper谁,然后通过其他一些流程进行优化。因此,我使用hello-worldcpp 文件进行了测试,并使用标志对其进行了编译,-v并且确实看到了前面提到的连续调用(collect2(linker) -> lto-wrapper-> lto1)。但这在使用默认链接器或gold链接器时。当我使用-fuse-ld=lld标志时,只collect2调用了进程。而这第一件事让我相信 LTO 根本没有完成。

但是,嘿,也许lld链接器内部化了 LTO 进程,所以它在不调用任何其他进程的情况下完成。所以我又做了一个测试,看看LTO是否完成(基于这篇文章)。基本上从一个 cpp 文件中,我调用了 100 000 000 次在其他 cpp 文件中定义的函数,该函数什么都不做。使用基本-O2优化,生成的二进制文件运行时间约为 200 毫秒,因为编译器无法优化无用的函数调用。当同时使用-flto标志和其中一个ldgold链接器时,生成的二进制文件在 ~2 ms 内运行。但是当使用lld链接器时,生成的二进制文件也可以在大约 200 毫秒内运行。因此,使用 lto 时运行速度与没有 ltolld时一样慢。lld没有任何优化的迹象。
这里要提到的是,使用lld链接器,如果不使用-ffat-lto-objects. 该标志使目标文件变大,因为编译器不仅转储 lto 代码,还转储可以在没有 lto 的情况下链接的代码。

因此,考虑到二进制链接的时间性能lld以及对象需要编译的事实-ffat-lto-objects,我得出结论,当使用lld链接器时,根本没有实现LTO,而是lld使用编译器生成的非LTO代码为了链接二进制文件。

于 2019-10-03T15:11:08.433 回答