有没有办法在链接时设置精灵需要的字段?

时间:2017-07-21 12:12:59

标签: c++ gcc ld libstdc++

给出一个可执行文件:

>objdump -x someprog | grep c++
NEEDED               libstdc++.so.6

我想将要求更改为完整版(包括次要版本和补丁级别):

>objdump -x someprog | grep c++
NEEDED               libstdc++.so.6.0.22

我知道有两种方法可以做到这一点:

  1. 根据此问题(Forcing or preventing use of a particular minor version of libstdc++
  2. 创建一个虚拟库
  3. 使用patchelf
  4.     >patchelf --add-needed libstdc++.so.6.0.22 someprog
        >objdump -x someprog | grep c++
        NEEDED               libstdc++.so.6
        NEEDED               libstdc++.so.6.0.22
    

    (我还没找到--replace-needed的工作命令行)

    这些对我来说都像黑客。 有没有办法在编译或链接时使用适当的-Wl标志来实现gcc?

    理想情况下,我想避免使用-nostdlib,因为这需要我特定的不仅仅是libstd ++而是libc以及我想要标准版本的所有其他内容。

    对于常规库,仅链接到特定版本对于libstdc ++来说已经足够了(或者我怀疑-stdlib会覆盖我提供的后续完全限定名称)。

    背景:我的可执行文件需要的libstdc++版本比系统上安装的更高版本。不幸的是,安装的版本可能是相同的主要版本,如果是这样,ld将很乐意使用系统版本,因为它匹配 soname libstdc++.so.6

    我不想静态链接,因为我实际上想要安装许多共享相同C ++运行时的小程序,这会大大增加安装量。

    有关我的(图书馆)搜索路径的一些信息可在此处获取:

      

    ld --verbose | grep SEARCH_DIR   SEARCH_DIR("在/ usr / x86_64的-红帽-LINUX / lib64下&#34); SEARCH_DIR("在/ usr / lib64下&#34); SEARCH_DIR("在/ usr /本地/ lib64下&#34); SEARCH_DIR(" / lib64下&#34); SEARCH_DIR("在/ usr / x86_64的-红帽-LINUX / LIB&#34); SEARCH_DIR("在/ usr / local / lib目录&#34); SEARCH_DIR(" / lib中&#34); SEARCH_DIR(" / usr / lib中&#34);

    在我的情况下很明显,在可执行文件的RPATH之前搜索/ usr / lib64:

    >objdump -x /opt/foo/bin/bar | grep PATH
    RPATH                $ORIGIN/../lib64/private:$ORIGIN/../lib64:$ORIGIN/
    

    man ld.so建议搜索顺序为:

      

    如果库依赖项不包含斜杠,则搜索它   按以下顺序:   

       o  (ELF only) Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist.  Use of DT_RPATH is deprecated.
    
       o  Using the environment variable LD_LIBRARY_PATH.  Except if the executable is a set-user-ID/set-group-ID binary, in which case it is ignored.
    
       o  (ELF only) Using the directories specified in the DT_RUNPATH dynamic section attribute of the binary if present.
    
       o  From the cache file /etc/ld.so.cache, which contains a compiled list of candidate libraries previously found in the augmented library path.  If, however, the binary was linked with the  -z  node‐
          flib linker option, libraries in the default library paths are skipped.  Libraries installed in hardware capability directories (see below) are preferred to other libraries.
    
       o  In the default path /lib, and then /usr/lib.  If the binary was linked with the -z nodeflib linker option, this step is skipped.
    

    同样https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf

    两者似乎都被实际使用所压倒,但实际情况并非如此。 需要的是寻找符号链接:

    >LD_LIBRARY_PATH= LD_DEBUG=libs ldd /opt/foo/bin/bar
     21720:     find library=libstdc++.so.6 [0]; searching
     21720:      search path=/opt/foo/bin/../lib64/private:/opt/foo/bin/../lib64:/opt/foo/bin                (RPATH from file /opt/foo/bin/bar)
     21720:       trying file=/opt/foo/bin/../lib64/private/libstdc++.so.6
    

    这是与我install shared imported library with necessary links的另一个问题的互动,其中的建议是不需要链接。 如果您没有指定完整的语义版本,那么它们显然是

2 个答案:

答案 0 :(得分:1)

这不起作用,因为libstdc++.so.6.0.22将导出与系统libstdc ++相同的符号,并且最终会在两个库之间混合使用(假设您确实更改了较新的libstdc ++版本的soname)。

您应该静态链接整个libstdc ++(这可能需要库的静态PIC变体)而不导出任何符号(可能带有链接器版本脚本),或静态链接新符号。

第二种方法似乎是目前最好的选择:它允许您使用大多数新语言功能,但您仍然与系统的其余部分保持很大程度的互操作性(特别是如果您使用{{1配置GCC)并且您不必安装任何其他共享对象进行部署。这就是Developer Toolset software collection提供更新版GCC的方式(我也相信SUSE Linux Toolchain Module)。如果C ++对象通过共享对象边界(包括异常处理)传递,则完全静态链接会导致问题,并且这种选择性静态链接可以避免许多这些问题。

答案 1 :(得分:1)

我想我已回答了我的问题,但不是我实际问过的问题。

RPATH之前搜索

LD_LIBRARY_PATH/usr/lib64/libstdc++.so.6被提取而不是libstdc++.so.6.0.22的原因是没有从/where/i/installed/libstdc++.so.6/where/i/installed/libstdc++.so.6.0.22

的符号链接

因此规则遵循您的平台的标准(他们是明智的)。在这种情况下: 每当您安装共享库时,也要安装预期的链接。

我认为我提出的实际问题在技术上仍然很有趣,所以如果有人有一个(甚至几年后),我仍会接受更好的答案。