ld.gold使用指南

一、背景

gcc将源码编译为.o,然后linker将.o连接为.so或者可执行程序,linker可以使用ld.bfd、ld.gold或者lld。


ld.bfd在binutils软件包中,是最常用的linker;ld.gold也在binutils软件包中,速度比ld.bfd快不少,但是内核以及其他一些项目不支持;lld是llvm的linker,据说比ld.gold更快,但是没怎么了解过,本文不讨论lld。


二、启用ld.gold

ubuntu上,可以sudo apt-get install binutils-gold安装ld.gold;如果是自己编译工具链,那么gcc和binutils进行configure时,都需要指定--enable-gold。

使用gcc时,需要指定参数-fuse-ld=gold。


如果想调试,确认使用的连接器是哪个,可以使用gcc参数-print-prog-name=ld。


三、dt-needed的问题

假设可执行程序exe1使用了so1和so2中的函数,so1使用了so2的函数。编译so1时,肯定需要指定-lso2;编译exe1时,肯定需要指定-lso1,但是exe1间接依赖了so2,是否需要指定-lso2呢?


ld.bfd在低于2.22版本时,可以不指定,不会报错,但是存在风险。假设哪一天,so1对外接口不变,但是不再使用so2中的函数了,也不添加-lso2。那么exe1编译时又没写-lso2,会出现编译问题以及运行问题。


ld.bfd高于2.22版本时,默认需要指定-lso2,否则会报错。但是也可以添加--copy-dt-needed-entries参数,来避免报错,这种方式不推荐。


ld.gold,不支持--copy-dt-needed-entries参数,必须指定-lso2。


四、hash table的问题

切换ld.gold后,遇到了一个问题。dlopen某个很大的.so时,ld.bfd只需要0.3s左右,ld.gold需要1s左右,性能不满足要求。


经过各种排查,最后readelf -S 看到,使用ld.gold编译出来的.so,缺少了一个.gnu.hash段,也就是DT_GNU_HASH。


参考文献2 中可以看到,解析符号的字符串时,有两种hash方式,sysv和gnu,gnu要比sysv快50%左右。所以,添加gcc参数-Wl,--hash-style=gnu或者-Wl,--hash-style=both来启用gnu hash。


五、结论

使用ld.gold,单纯看连接时间的话,确实减少了很多。但是连接时间在整体编译中,占的比例并不高,所以整体编译大概节约了5%左右。

使用ld.gold,即使使用了gnu hash,.so的载入还是会慢一些,大约慢4%左右。


以上数据仅供参考,具体项目需要自行测试。


参考文献

1、UnderstandingDSOLinkChange:http://fedoraproject.org/wiki/UnderstandingDSOLinkChange

2、ELF: better symbol lookup via DT_GNU_HASH:https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/

3、binutils-2.22: ld and --copy-dt-needed-entries:https://lists.freebsd.org/pipermail/freebsd-current/2011-December/030114.html


你可能感兴趣的:(编译)