【问题标题】:GCC 4.5 vs 4.4 linking with dependenciesGCC 4.5 vs 4.4 与依赖项链接
【发布时间】:2012-02-02 06:40:25
【问题描述】:

尝试在 GCC 4.4 和 GCC 4.5 上执行相同操作时,我观察到不同之处。因为我正在使用的代码是专有的,所以我无法提供它,但我发现这个简单的测试用例也发生了类似的失败。

我基本上想要做的是让一个共享库 (libb) 依赖于另一个共享库 (liba)。加载 libb 时,我假设 liba 也应该加载 - 即使 libb 不一定使用 liba 中的符号。

我观察到的是,当我使用 GCC 4.4 编译时,我观察到 liba 已加载,但如果我使用 GCC 4.5 编译,则未加载 libb。

我有一个包含两个文件 a.c 和 b.c 的小测试用例。文件内容:

//a.c
int a(){ 
    return 0; 
}

//b.c
int b(){
    return 0;
}
//c.c
#include <stdio.h>
int a();
int b();

int main()
{
    printf("%d\n", a()+b());
    return 0;
}
//test.sh    
$CC -o liba.so a.c -shared
$CC -o libb.so b.c -shared -L. -la -Wl,-rpath-link .
$CC c.c -L. -lb -Wl,-rpath-link .
LD_LIBRARY_PATH=. ./a.out

这是我使用不同版本的 GCC 的输出

$ CC=gcc-4.4 ./test.sh
1
$ CC=gcc-4.5 ./test.sh
/tmp/cceJhAqy.o: In function `main':
c.c:(.text+0xf): undefined reference to `a'
collect2: ld returned 1 exit status
./test.sh: line 4: ./a.out: No such file or directory
$ CC=gcc-4.6 ./test.sh
/tmp/ccoovR0x.o: In function `main':
c.c:(.text+0xf): undefined reference to `a'
collect2: ld returned 1 exit status
./test.sh: line 4: ./a.out: No such file or directory
$ 

谁能解释发生了什么?另一个额外的信息是 libb.so 上的 ldd 确实在 GCC 4.4 上显示 liba.so,但在 GCC 4.5 上不显示。

编辑

我将 test.sh 更改为以下内容:

$CC -shared -o liba.so a.c
$CC -L. -Wl,--no-as-needed -Wl,--copy-dt-needed-entries -la -shared -o libb.so b.c -Wl,-rpath-link . 
$CC -L. c.c -lb -Wl,-rpath-link . 
LD_LIBRARY_PATH=. ./a.out

这在 GCC 4.5 中给出了以下输出:

/usr/bin/ld: /tmp/cc5IJ8Ks.o: undefined reference to symbol 'a'
/usr/bin/ld: note: 'a' is defined in DSO ./liba.so so try adding it to the linker command line
./liba.so: could not read symbols: Invalid operation
collect2: ld returned 1 exit status
./test.sh: line 4: ./a.out: No such file or directory

【问题讨论】:

  • 我的构建环境是 Ubuntu 11.10 x86-64
  • 在 Debian 6.0.3 上,打包的 GCC 4.4 可以毫无问题地处理示例。打包的 GCC 4.3 抱怨缺少 -fPIC 标志。

标签: gcc gcc4


【解决方案1】:

ld 在链接过程中处理DT_NEEDED 库的方式似乎发生了变化。这是当前man ld的相关部分:

带有--copy-dt-needed-entries命令中提到的动态库 行将被递归搜索,跟随它们的 DT_NEEDED 标记到其他库,以解析输出二进制文件所需的符号。随着 默认设置,但是搜索跟随它的动态库将随着动态库本身而停止。不会遍历任何 DT_NEEDED 链接 解析符号。

--copy-dt-needed-entries 部分的一部分)。

在 GCC 4.4 和 GCC 4.5 之间的某个时间(显然,请参阅一些参考资料 here - 找不到任何真正权威的东西),默认值从递归搜索更改为无递归搜索(正如您在较新的 GCC)。

在任何情况下,您都可以(并且应该)通过在最后的链接步骤中指定 liba 来修复它:

$CC c.c -L. -lb -la -Wl,-rpath-link .

您可以通过使用较新的编译器和此命令行运行来检查此链接器设置是否确实(至少是部分)问题:

$CC c.c -L. -Wl,--copy-dt-needed-entries -lb -Wl,--no-copy-dt-needed-entries \
         -Wl,-rpath-link .

【讨论】:

  • 这将是一个很好的解释,但添加标志不会改变结果。我尝试在构建 libb.so 和构建 c.c 时添加它们
  • 作为参考,我的 LD 版本是 GNU ld (GNU Binutils for Ubuntu) 2.21.53.20110810
  • 这些标志只在最终链接上需要,在构建.so 文件时不需要。无论如何,真正的解决方法是将您的可执行文件与libb liba 链接。 (我在 ld 2.22。)
  • 这确实不是一个选项,因为 c.c 可能是客户代码,他们只会看到 libb。我真正想要的是某种方式来强制在加载 libb 时加载 liba。
  • 这个答案是无价的,也解决了my problem。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多