共享库中库函数的选择性静态链接

Kla*_*ing 7 linux shared-libraries ld static-linking

我想创建一个使用第三方静态库中的函数的共享库.例如,foobarlibfoobar.a.我知道我的主要应用程序也在使用foo并将导出该符号.所以我只是想链接bar以保存代码大小并保持'foo'未解析(因为它将由主应用程序提供).如果我包含libfoobar.a,链接器ld将在我的共享库中包含这两个函数.如果我不包括libfoobar.a,我的库将无法访问功能,bar因为应用程序本身没有链接bar.问题:

  • 有没有办法告诉ld在构建共享库时只解析某些符号?
  • 打开libfoobar.a到一个共享库?
  • 提取包含文件功能barlibfoobar.a,并指定在连接线?
  • 不用担心,运行时加载器bar将从您的应用程序中使用,因此bar不会加载共享库中的副本?

Kla*_*ing 4

以下几点试图回答我提出的问题:

  • ld似乎不允许您省略静态库中某些符号的链接。使用--just-symbolsor --undefined(或EXTERN链接描述文件命令)不会阻止ld链接符号。
  • 将静态库libfoobar.a转换为共享库libfoobar.so.1.0,并导出所有可见符号。您还可以使用--version-script其他方法仅导出符号的子集。

    ld -shared -soname libfoobar.so.1 -o libfoobar.so.1.0 --whole-archive libfoobar.a --no-whole-archive

  • 从静态库的副本中删除存档成员比提取它们更好,因为可能存在必须管理的内部依赖项。例如,假设您要导出所有符号,则可以从主可执行文件生成映射文件。然后,您可以 grep 查找可执行文件从静态库副本中拉入的所有存档成员,并将它们从副本中删除。因此,当您的 DSO 在静态库中链接时,它将留下相同的符号未解析。

  • 如果使用该选项编译可执行文件,则可以将主可执行文件指定为 DSO 的共享库--pie。如果链接命令中的静态库位于 DSO 之前,则 DSO 将首先链接到可执行文件。LD_LIBRARY_PATH需要注意的是,主可执行文件必须通过或可用-rpath。此外,使用strace表明,由于可执行文件是您的库的依赖项,因此当您的 DSO 加载时它会再次加载。

    ld -shared -rpath '$ORIGIN' -L. -lc -ldl -o DSO.so DSO.o app libfoobar.a

  • 动态链接器将首先使用可执行文件的foo版本,除非您使用该标志调用dlopen()RTLD_DEEPBIND。使用strace显示整个 DSO 是通过文件映射mmap2()到内存中的。然而,维基百科声称,对于 mmap,“在访问特定位置后,从磁盘的实际读取是以“惰性”方式执行的。” 如果这是 true,则不会加载重复的foo 。请注意,仅当您的 DSO导出函数foo时才会发生覆盖。否则,只要 DSO 调用foo ,就会使用静态链接到 DSO的函数foo

总之,如果mmap()使用惰性读取,那么最好的解决方案是以正常方式链接 DSO,并让动态链接器和 linux 处理剩下的事情。