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

Is there a way to set the elf NEEDED field at link time?

本文关键字:精灵 字段 设置 链接 有没有      更新时间:2023-10-16

给定一个可执行文件,使得:

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

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

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

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

  1. 根据此问题创建一个虚拟库(强制或阻止使用特定的次要版本的libstdc++(
  2. 使用补丁
>patchelf --add-need libstdc++.so.6.0.22 someprog>objdump -x someprog |grep c++ NEED libstdc++.so.6 需要libstdc++.so.6.0.22

(我还没有找到--replace-need的工作命令行(

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

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

对于常规库,只需链接到特定版本就足以满足libstdc++的需求,它不是(或者更确切地说,我怀疑-stdlib覆盖了我提供的后续完全限定名称(。

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

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


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

ld --verbose | grep SEARCH_DIR SEARCH_DIR("/usr/x86_64-redhat-linux/lib64"(;SEARCH_DIR("/usr/lib64"(;SEARCH_DIR("/usr/local/lib64"(;SEARCH_DIR("/lib64"(;SEARCH_DIR("/usr/x86_64-redhat-linux/lib"(;SEARCH_DIR("/usr/local/lib"(;SEARCH_DIR("/lib"(;SEARCH_DIR("/usr/lib"(;

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

>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

这是与我安装共享导入库的另一个问题的交互,其中包含必要的链接,其中建议不需要链接。 如果未指定完整的语义版本,则显然需要它们。

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

您应该静态链接整个libstdc++(这可能需要库的静态PIC变体(并且不导出任何符号(可能使用链接器版本脚本(,或者仅静态链接新符号。

第二种方法似乎是目前最好的选择:它允许您使用大多数新的语言功能,但您仍然与系统的其余部分具有很大程度的互操作性(特别是如果您使用--with-default-libstdcxx-abi=gcc4-compatible配置 GCC(,并且您不必安装任何其他共享对象进行部署。 这就是 Developer Toolset 软件集合提供较新版本 GCC 的方式(我相信 SUSE Linux Toolchain Module( 也是如此(。 如果C++对象跨共享对象边界传递(包括异常处理(,则完全静态链接会导致问题,而这种选择性静态链接避免了其中的许多问题。

我想我已经回答了我的问题,尽管不是我实际提出的问题。

RPATHLD_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之间没有象征性联系

因此,规则是遵循您平台的标准(在合理的情况下(。在这种情况下:每当您安装共享库时,也要安装所需的链接。

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