【问题标题】:Can I change 'rpath' in an already compiled binary?我可以在已编译的二进制文件中更改“rpath”吗?
【发布时间】:2012-11-25 23:43:47
【问题描述】:

我有一个计划用于废料堆的旧可执行文件,但它还没有。它依赖于一些已从我的环境中删除的库,但我有一些存根库可以正常工作。我想将此可执行文件指向这些存根库。是的,我可以设置 LD_LIBRARY_PATH,但是这个可执行文件是从许多脚本和许多用户中调用的,我很想在一个地方修复它。

我没有这方面的来源,而且很难得到。我在想 - 我可以编辑这个文件,使用一个 ELF 感知编辑器,并添加一个简单的 PATH 到 rpath 让它命中新的库吗?这可能吗,或者一旦你创建了一个 ELF 二进制文件,你将东西固定到位置并且它们不能移动?

【问题讨论】:

  • 将其包装成一个设置 LD_LIBRARY_PATH 并调用二进制文件的 shellscript。将 shell 脚本放在调用者的 PATH 中。
  • LD_LIBRARY_PATH 由子进程继承。你可能不想要那个。
  • @will 是的,我已经说过我不想那样做。 :)

标签: linux linker elf


【解决方案1】:

有一个比chrpath 更通用的工具,叫做patchelf。它最初是为为 Nix 和 NixOS(打包系统和 GNU/Linux 发行版)制作包而创建的。

如果二进制文件中没有 rpath(这里称为 rdsamp),chrpath 会失败:

chrpath -r '$ORIGIN/../lib64' rdsamp 
rdsamp: no rpath or runpath tag found.

另一方面,

patchelf --set-rpath '$ORIGIN/../lib64' rdsamp

成功就好了。

【讨论】:

  • 特别是,patchelf 能够将 rpath 添加到不包含 rpath 的二进制文件中 - 其中chrpath 似乎只能修改已经存在的条目。
  • 作为一般说明,值得了解rpathrunpath 之间的细微区别。基本上,一个可以覆盖LD_LIBRARY_PATH 而另一个不能。详情请见blog.tremily.us/posts/rpath
  • 令人讨厌的是chrpathpatchelf 的术语都很草率。例如,上面显示的patchelf 命令将更改runpath,但不会更改rpath,除非您还提供--force-rpath 选项。
  • @superbatfish 是的,但差异通常并不重要。 patchelf 的更改日志中的此条目对此进行了解释:“--set-rpath--shrink-rpath--print-rpath 现在更喜欢 DT_RUNPATH 而不是 DT_RPATH,后者已过时。更新时,如果两者都存在,则两者都会更新。如果仅存在 DT_RPATH,则除非指定 --force-rpath,否则将转换为 DT_RUNPATH。如果两者都不存在,则添加 DT_RUNPATH,除非指定 --force-rpath,在这种情况下添加 DT_RPATH。出于兼容性原因,选项的名称可能保持不变。
  • 到目前为止最好的答案,这应该是公认的答案!
【解决方案2】:

有一个名为 chrpath 的工具可以做到这一点 - 它可能在您的发行版包中提供。

【讨论】:

  • 只是给mac用户的一个注释,install_name_tool可以使用-rpath标志来做到这一点
  • 如果报错:<binary>: no rpath or runpath tag found.,不能用chrpath代替,但是这种情况下可以用patchelfpatchelf --set-rpath /path/to/libaries <binary>
  • 如果可能的话,我更喜欢 chrpath,因为虽然它更通用,但 patchelf 有一些长期存在的错误,会大大增加库/可执行文件的大小。
  • @taranaki:你说的是哪个版本的 patchelf?
  • chrpath 有一个严重的限制:它只能用相等或更短的长度替换 RPATH(rpath 版本 0.16 的手册页)
【解决方案3】:

正如@user7610 所说,正确的方法是使用patchelf 工具。

但是,我觉得我可以给出一个更全面的答案,涵盖所有需要执行此操作的命令。

有关该主题的综合文章,请点击here

首先,很多开发者都在谈论RPATH,但实际上他们的意思是RUNPATH。这是两个不同的可选动态部分,加载器处理它们的方式非常不同。您可以在我之前提到的链接中详细了解它们之间的区别。

现在,请记住:

  • 如果设置了RUNPATH,则忽略RPATH
  • RPATH 已弃用,应避免使用
  • RUNPATH 是首选,因为它可以被 LD_LIBRARY_PATH 覆盖

查看当前的 R[UN]PATH

readelf -d <path-to-elf> | egrep "RPATH|RUNPATH"

清除 R[UN]PATH

patchelf --remove-rpath <path-to-elf>

注意事项:

  • 同时删除 RPATHRUNPATH

将值添加到 R[UN]PATH

patchelf [--force-rpath] --set-rpath "<desired-rpath>" <path-to-elf>

注意事项:

  • &lt;desired-path&gt; 是一个冒号分隔的目录列表,例如:/my/libs:/my/other/libs
  • 如果指定--force-rpath,则设置RPATH,否则设置RUNPATH

【讨论】:

  • -Wl,-R,&lt;desired-rpath&gt; -Wl,--enable-new-dtags 设置DT_RUNPATH,这是大多数人应该使用的。 RUNPATH 可以被LD_LIBRARY_PATH 覆盖,所以人们不应该使用--force-rpath
  • @jww 我看到我没有添加关于 RPATH 弃用的评论,所以我刚刚添加了一条。谢谢!
  • 请注意,示例&lt;desired-path&gt; 使用冒号;它应该是一个逗号(即:/my/libs,/my/other/libs)。
  • RPATH 可能已被弃用,但使用 RUNPATH 可能会导致“意外”极端情况。例如,参见qt.io/blog/2011/10/28/rpath-and-runpath
  • "...冒号(不是逗号)分隔...".
【解决方案4】:

这对我有用,将 XORIGIN 替换为 $ORIGIN。

chrpath -r '\$\ORIGIN/../lib64' httpd

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-13
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    相关资源
    最近更新 更多