动态库“转发”

时间:2015-03-10 10:44:07

标签: c linker shared-libraries

[编辑:简而言之,问题是:当我链接到与另一个动态库链接的动态库时,我是否必须明确地链接到那个?]

我在一个软件中看到了类似的东西。它不起作用,现在我想知道它是否应该起作用。我可以链接一个图书馆" bar"动态地对抗另一个图书馆" foo"然后链接到该库以访问来自" foo"的符号。 (因为" bar"应该想要链接到" foo")? (我正在使用linux和gcc 4.8.2以防万一。)

具体地说,我有以下三个文件。现在我做了

gcc -c -Wall -Werror -fpic foo.c
gcc -shared -olibfoo.so foo.o

我通常会这样做

gcc -o program main.c -L. -lfoo

获得一个有效的计划。相反,我做了

gcc -shared -olibbar.so -L. -lfoo
gcc -o program main.c -L. -lbar

这不起作用:

/tmp/cciNSTyI.o: In function `main':
main.c:(.text+0xf): undefined reference to `foo'
collect2: error: ld returned 1 exit status

应该吗?

foo.h中

#ifndef foo_h__
#define foo_h__

extern void foo(void);

#endif

foo.c的

#include <stdio.h>

void foo(void)
{
  puts("foo");
}

的main.c

#include <stdio.h>
#include "foo.h"

int main(void)
{
  puts("Library test...");
  foo();
  return 0;
}

编辑:我写了一篇关于我对下面发生的事情的理解的答案。

我还不太清楚的一点是参数的顺序:如果(使用文件bar.c,就像在答案中那样)我将栏与行连接起来(注意&#34;栏的位置的.o&#34)

gcc -o program main.c -L. -lbar
gcc -shared -olibbar.so -L. -lfoo bar.o
然后它&#34; bar&#34;不依赖于&#34; foo&#34;:

> readelf -d libbar.so
Dynamic section at offset 0xe18 contains 24 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000c (INIT)               0x5a8
 [...]

3 个答案:

答案 0 :(得分:1)

不,不可能“转发”动态链接库。

当您静态或动态地链接任何库时,实际上您可以使主要可执行文件调用链接库中定义的函数/符号。

在您的情况下,库bar没有定义函数foo()。因此,在创建bar.so时,生成的符号将在主可执行文件的符号表中注册 - program。因为bar lib中的符号不​​包含任何名为foo()的函数,它不会在program的符号表中注册。因此,当foo()在时间内被调用时,加载器会尝试在编译foo()期间找到在您链接的所有库中定义program的.so。因此运行时错误。它没有显示编译时错误,因为您已将foo.h头文件包含在其中。

您需要显式链接要在编译代码中引用的符号(函数,变量,常量等)的所有库。

答案 1 :(得分:1)

  

当我链接到与另一个动态库链接的动态库时,我是否还必须明确链接到该动态库?

没有。

其他库必须链接到它需要的共享库,否则它将是一个巨大的fuster cluck(你用.a文件得到的那个)。

想象一下,其他人将共享库依赖项添加到您使用的共享库中。这会导致您的应用程序在链接时(最多)或运行时失败。这就是共享库带有自己的依赖关系的原因。

您可以使用readelf实用程序来检查共享库依赖项,例如:

$ readelf -d /usr/lib64/libboost_wave-mt.so

Dynamic section at offset 0x12fd58 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libboost_filesystem-mt.so.5]
 0x0000000000000001 (NEEDED)             Shared library: [libboost_thread-mt.so.5]
 0x0000000000000001 (NEEDED)             Shared library: [libboost_date_time-mt.so.5]
 0x0000000000000001 (NEEDED)             Shared library: [libboost_system-mt.so.5]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libboost_wave-mt.so.5]
 0x000000000000000c (INIT)               0xb49f0
 0x000000000000000d (FINI)               0x10c018
 0x000000006ffffef5 (GNU_HASH)           0x1b8
 0x0000000000000005 (STRTAB)             0xbe08
 0x0000000000000006 (SYMTAB)             0x2cb8
 0x000000000000000a (STRSZ)              637705 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x3308a8
 0x0000000000000002 (PLTRELSZ)           7584 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0xb2c50
 0x0000000000000007 (RELA)               0xa8600
 0x0000000000000008 (RELASZ)             42576 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0xa8530
 0x000000006fffffff (VERNEEDNUM)         4
 0x000000006ffffff0 (VERSYM)             0xa7912
 0x000000006ffffff9 (RELACOUNT)          405
 0x0000000000000000 (NULL)               0x0

注意NEEDED属性 - 这些是加载此共享库时自动加载的共享库。


gcc -shared -olibbar.so -L. -lfoo

您从共享库生成共享库。在这种情况下,您需要使用--relocatable链接器选项部分链接

gcc -shared -Wl,--relocatable -olibbar.so -L. -lfoo

答案 2 :(得分:0)

这是对Maxim Egorushkin的回答(特别是使用readelf是有启发性的)。

首先,似乎只有图书馆被标记为&#34; NEEDED&#34;如果它们实际上需要在任何地方,即如果它们所定义的某些符号被使用的话。在问题的例子中,当然不是这样。

其次,即使通过这些依赖关系&#34; foo&#34;最终被链接在一起,它的符号仍然不能用于main.c,除非它是明确链接的。

要验证此行为,请考虑文件

bar.h

#ifndef bar_h__
#define bar_h__

extern void bar(void);

#endif

bar.c

#include <stdio.h>
#include "foo.h"

void bar(void)
{
  foo();
  puts("bar");
}

通过

编译和链接
gcc -o program main.c -L. -lbar
gcc -shared -olibbar.so -L. -lfoo bar.o

然后&#34; bar&#34;取决于&#34; foo&#34; (与答案不同):

> readelf -d libbar.so
Dynamic section at offset 0xe08 contains 25 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000c (INIT)               0x5b0

如果一个人取代每个&#34; foo&#34;通过&#34; bar&#34;在上面的main.c文件中,可以编译并将所有内容链接到工作程序

gcc -o program main.c -L. -lbar -Wl,-rpath-link .

如果一个人保持&#34; foo&#34; -lines,则链接失败,因为无法解析foo符号(该程序甚至没有链接到&#34; bar&#34;)。 / p>

有趣的案例是调用两个&#34; foo&#34;和&#34; bar&#34;发生。现在main.c与&#34; bar&#34;与&#34; foo&#34;相关联,但&#34; foo&#34;中的符号仍然无法使用main.c。

这种行为实际上是有道理的,因为main.c可能依赖于定义函数foo()的不同库,然后它不想知道&#34; bar&#34;使用。如果需要这种行为,那么也不要优化&#34; NEEDing&#34;不需要的图书馆是有效的。