我正在处理一个被编译为共享对象的大型项目。使用DWARF-2符号(-g -feliminate-unused-debug-types
)进行编译会导致.debug_info
大约为700M。
如果我添加-feliminate-dwarf2-dups
,链接器就会死掉:
error adding symbols: Memory exhausted
ld returned 1 exit status
这是在具有4G RAM的系统上。由于这需要在各种系统上进行编译,因此不能接受超过4G RAM的消耗。我尝试将--no-keep-memory
传递给ld
,但仍然失败。
ld通常通过缓存内存中输入文件的符号表来优化内存使用速度。此选项告诉ld通过重新读取符号表来优化内存使用。如果在链接大型可执行文件时ld内存空间不足,则可能需要这样做。
我猜ld
加载内存中的所有符号然后去寻找dupes,这需要将内存存储在磁盘上的内存的5倍以上。
有一种简单的方法可以逐步增加吗?像:
我可以将文件一两个链接到临时存档中,然后将这两个文件链接起来,等等,但我真的不想更改此项目的构建过程。也许我可以使用objcopy
删除这些段,单独执行dupe消除,然后将调试部分插入到最终的ELF中?
还有其他工具可以执行这些DWARF合并吗? dwarfdump
仅读取文件。或者,我可以调用gcc
/ ld
来执行此操作,而不是实际链接文件吗?
答案 0 :(得分:3)
我知道有两种减少DWARF大小的方法。你想要哪一个取决于你的预期目的。
Fedora(也许还有其他发行版,我不知道)使用dwz
工具来压缩DWARF。这可以在事实之后起作用:您链接您的程序或共享库,然后运行dwz
。这是一个"语义"压缩器,意味着它理解DWARF并将其重写为更小的形式。在DWARF术语中,它生成部分CU并以这种方式共享数据。 dwz
还有一种模式,可以跨不同的可执行文件压缩数据,以便更多地共享。
dwz
产生最佳压缩效果。主要缺点是它不适合开发人员工作流程 - 它有点慢,使用大量内存等等。虽然它对发行版很有用,我认为这是合适的对于其他一些部署情况。
压缩debuginfo的另一个好方法是使用-fdebug-types-section
标志来gcc。这会更改DWARF输出以将大型类型放入其自己的部分中。这些类型由其内容进行散列;然后链接器会自动合并这些部分。
这种方法产生了不错的压缩,因为类型是DWARF的重要组成部分;具有良好的性能,因为在链接器中以这种方式合并相同的部分是便宜的。主要的缺点是压缩不是很好。
gdb理解这两种压缩。其他工具的支持更加不稳定。
答案 1 :(得分:2)
除了Tom Tromey的建议之外,你可以做的另一件事就是为例如构建交叉编译器x86_64
系统,针对您的各种系统。
这完全消除了链接器内存的4GB限制,并且速度可能更快(各种各样的小型系统可能都有笨拙的CPU,因此在强大的开发机器上进行交叉编译时,在它们上构建本机可能需要数小时只花几分钟。
或者您可以使用-fsplit-dwarf
- 无需将调试位链接到最终的共享库中;你可以将它们分开。
<强>更新强>
我们已经使用了交叉编译器。问题在于,并非我们用于构建机器的所有x86_64系统都足以对其进行优化。
在这种情况下,您没有硬 4GB的要求,并且您声称这是不可接受的是伪造的。你可以获得64GB的RAM大约500美元,并加速一切。
开发人员可能希望在其主系统上运行构建
如果您的开发人员的主系统少于16GB,那么您就是在浪费时间。
关于-fsplit-dwarf,如果它是远程构建的,我仍然需要下载符号,所以几乎没有收获
增益是你可以构建你的二进制文件。
答案 2 :(得分:1)
嗯,另一件要尝试的是使用&#34; gold&#34;链接器,用于构建大型应用程序可能更快/更好,链接:https://en.wikipedia.org/wiki/Gold_(linker)
黄金链接器和拆分调试信息对我来说也很有用。
&#34; Fission在GCC 4.7中实现,需要最近版本的objcopy和黄金链接器的支持。
使用-gsplit-dwarf选项可以在编译时生成拆分DWARF。此选项必须与-c一起使用;在同一步骤中编译和链接时不能使用裂变。
在链接时使用gold链接器的--gdb-index选项(-Wl, - gdb或g ++链接时的gdb-index)来创建允许GDB定位和读取的.gdb_index部分。 .dwo文件,因为它需要它们。&#34;