如何调试debian系统上的(慢)链接器

时间:2009-06-24 19:25:07

标签: linux performance debugging linker profiling

在我的公司,我们的链接器(ld 2.17)有一个非常烦人的问题。它在一个相对较快的系统(Core Duo,2GB Ram)上链接非常慢,我现在不知道如何解决这个问题。编译一个相对较大的项目大约需要5到10分钟(在我的Gentoo系统上需要大约5秒钟的时间)。

我个人认为这是一个巨大的生产力杀手,至少对我而言。我们尝试使用更新版本的ld(2.19)但没有任何成功。我在#freenode上问#debian,但这个问题似乎很独特。我没有在网上找到有关类似问题的任何信息。它只在我们使用调试符号构建时才会发生。我将gcc调试信息标志更改为-g,-g3和-ggdb,但这也无济于事。

所以我的问题是,您如何分析和调试链接器?我从来没有做过这样的事情,我也找不到任何关于它的文件。基本上任何合理的gprof gmon.out都会非常有用,因为我可以向binutils开发人员询问具体问题。我完全没有注意到这一点。

编辑:我们'修复'我们在大多数系统上切换到debian lenny的问题。谢谢你的答案!

4 个答案:

答案 0 :(得分:6)

您可以尝试黄金(binutils-gold)而不是ld。 它应该更快。

以下是Wikipedia Gold(linker)

的引用
  

写黄金的动机是   制作一个比它更快的链接器   GNU链接器[3],特别适用于大型   用C ++编写的应用程序。

黄金作者伊恩兰斯泰勒(Ian Lance Taylor)发表了an (longish) article about linkers,他解释了他写黄金的主题,以及为什么大多数链接器都很慢。如果您对链接器的内部工作感兴趣,那么本文值得一读。

答案 1 :(得分:5)

如果你正在观察减速运行gcc(而不是直接将链接器作为ld运行),请尝试使用

进行编译
$ gcc -save-temps -v [... rest of your command line ...]

这将打印出所有中间命令,例如内部collect2和最终ld,并确保即使在命令完成后传递给这些命令的对象仍将保留在磁盘上

然后你应该能够单独运行命令以找到最差的阶段,然后使用不同的选项或分析来运行它。

例如,

$ echo 'int main() {}' > test.c
$ gcc -save-temps -v test.c
Using built-in specs.
Target: x86_64-pc-linux-gnu
Configured with: /var/tmp/paludis/sys-devel-gcc-4.3.3-r2/work/gcc-4.3.3/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.3.3 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.3.3 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.3.3/man --infodir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.3.3/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --enable-multilib --enable-libmudflap --disable-libssp --enable-libgomp --enable-cld --disable-libgcj --enable-objc-gc --enable-languages=c,c++,objc,obj-c++,treelang,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo 4.3.3-r2 p1.1, pie-10.1.5'
Thread model: posix
gcc version 4.3.3 (Gentoo 4.3.3-r2 p1.1, pie-10.1.5)
COLLECT_GCC_OPTIONS='-save-temps' '-v' '-mtune=generic'
 /usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/cc1 -E -quiet -v test.c -D_FORTIFY_SOURCE=2 -mtune=generic -fpch-preprocess -o test.i
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include  search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-save-temps' '-v' '-mtune=generic'
 /usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/cc1 -fpreprocessed test.i -quiet -dumpbase test.c -mtune=generic -auxbase test -version -o test.s
GNU C (Gentoo 4.3.3-r2 p1.1, pie-10.1.5) version 4.3.3 (x86_64-pc-linux-gnu)
        compiled by GNU C version 4.3.3, GMP version 4.2.4, MPFR version 2.4.1-p5.
warning: GMP header version 4.2.4 differs from library version 4.3.1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 20f3dbffbfd03e5311a257ae1239cd71
COLLECT_GCC_OPTIONS='-save-temps' '-v' '-mtune=generic'
 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/bin/as -V -Qy -o test.o test.s
GNU assembler version 2.19.1 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.19.1
COMPILER_PATH=/usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/libexec/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/libexec/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/bin/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-save-temps' '-v' '-mtune=generic'
 /usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/collect2 --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../.. test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crtn.o
$ ls
a.out  test.c  test.i  test.o  test.s
$ /usr/libexec/gcc/x86_64-pc-linux-gnu/4.3.3/collect2 --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../.. test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crtn.o
$ .../collect2 -v ...
collect2 version 4.3.3 (x86-64 Linux/ELF)
/usr/bin/ld -v --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtbegin.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../.. test.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/crtend.o /usr/lib/gcc/x86_64-pc-linux-gnu/4.3.3/../../../../lib64/crtn.o
GNU ld (GNU Binutils) 2.19.1
$ 

如果您需要帮助构建ld的调试版本,这里有一个快速的方法可以帮助您。

$ sudo apt-get install build-essential dpkg-dev
$ sudo apt-get build-dep binutils
$ apt-get source binutils
$ cd binutils-*
$ DEB_BUILD_OPTIONS='debug noopt nostrip' dpkg-buildpackage -uc -us
$ cd ..
$ sudo dpkg -i *.deb

但是,我建议使用schrootsbuild来避免污染您自己的系统,而不是快速入侵。

答案 2 :(得分:3)

回答剖析问题;您应该查看OProfile - 这是一个系统级的分析器,可以分析多个正在运行的进程。它应该允许您识别链接的哪个子流程花费最多的时间,并且还将显示花费最多时间的功能。

答案 3 :(得分:1)

我想建议两种方法来检查:

  1. 使用strace检查链接器加载/解析链接的文件;有了这个,你可能知道链接器是否有任何不必要的路径。
  2. 使用带有-verbose选项的ld来了解ld正在做什么。五分钟与五秒相比不应该是链接器的问题,它应该是您的主机或某些选项的一些问题。