GCC 4.5与4.4链接依赖关系

时间:2012-01-04 10:49:24

标签: gcc gcc4

在尝试在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

1 个答案:

答案 0 :(得分:11)

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

  

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

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

GCC 4.4和GCC 4.5之间的某个时间(显然,参见一些参考文献here - 找不到任何真正权威的东西),默认值从递归搜索更改为无递归搜索(如您所见)与较新的海湾合作委员会)。

在任何情况下,您都可以(并且应该)通过在最后的链接步骤中指定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 .