写点什么

linux 动态链接的程序如何在其他系统上运行

作者:SkyFire
  • 2021 年 12 月 25 日
  • 本文字数:1965 字

    阅读完需:约 6 分钟

linux动态链接的程序如何在其他系统上运行

linux 动态链接的程序如何在其他系统上运行

linux 动态链接的程序在其他系统上运行分为两种情况:


  • 一些第三方库的 so 在目标系统上不存在或者版本不一致

  • 目标系统上的装载器与本地环境的装载器版本不一致(本地的装载器较新)


下面介绍下如何应对上面的情况。

找到并拷贝依赖

先使用 ldd 命令将可执行文件的依赖都找到,然后把相关库的文件(注意如果是符号链接一定要找到最终的文件)和可执行文件放在一起,如:



上面的 test 依赖下面的这些 so,对于这些 so,需要一个个处理:


  • 如果是符号链接,找到对应的文件

  • 将文件拷贝到当前目录,然后重命名为需要的符号


如上面就需要将/lib/x86_64-linux-gnu/libpthread-2.32.so拷贝为libpthread.so.0


需要注意的是


  • linux-vdso.so.1 这个文件是 linux 内核虚拟出来的,不需要处理。

  • /lib64/ld-linux-x86_64.so.2是应用程序的装载器,使用的是绝对路径。如果目标系统与本地的装载器版本相同,则不需要拷贝此文件。如果确认目标系统装载器的版本与本地不同,则需要将/lib64/ld-linux-x86-64.so.2也拷贝到一下。

目标系统与本地的装载器版本相同

如果目标系统与本地的装载器版本相同,可以直接在可执行文件所在目录下设置 LD_LIBRARY_PATH 环境变量的值,从而让加载器优先加载 LD_LIBRARY_PATH 下有的 so 文件。


如:我们的程序在目标系统/tmp/prog/ 下,对应的依赖库也拷贝到这里了,那么可以这样启动程序:


LD_LIBRARY_PATH=/tmp/prog/ /tmp/prog/test
复制代码


有很多手段可以达到这个目标,可以随意发挥。

目标系统与本地的装载器版本不同

如果目标系统与本地的装载器版本不同,就比较棘手一点,但是也不是完全没有办法。


当我们在 shell 中输入/tmp/prog/test时,加载器会去判断可执行文件的格式,如果时 elf 格式,则会去找他的.interp 段,这个段保存了加载这个程序的装载器。也就是上面图中的/lib64/ld-linux-x86-64.so.2,然后使用/lib64/ld-linux-x86-64.so.2将我们的目标程序加载起来。


注意这个路径是一个绝对路径,所以我们无法使用 LD_LIBRARY_PATH 的方式让他使用我们拷贝进去的ld-linux-x86-64.so.2


让我们看下/lib64/ld-linux-x86-64.so.2是怎么加载 elf 文件的,实际上/lib64/ld-linux-x86-64.so.2不仅是个 so,也是个可运行的 elf 文件。也就是说,可以在 shell 中直接/lib64/ld-linux-x86-64.so.2运行:


skyfire@DESKTOP-2661M5S ~/c/c/b/l/x/debug (master) [127]> /lib64/ld-linux-x86-64.so.2Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]You have invoked `ld.so', the helper program for shared library executables.This program usually lives in the file `/lib/ld.so', and special directivesin executable files using ELF shared libraries tell the system's programloader to load the helper program from this file.  This helper program loadsthe shared libraries needed by the program executable, prepares the programto run, and runs it.  You may invoke this helper program directly from thecommand line to load and run an ELF executable file; this is like executingthat file itself, but always uses this helper program from the file youspecified, instead of the helper program file specified in the executablefile you run.  This is mostly of use for maintainers to test new versionsof this helper program; chances are you did not intend to run this program.
--list list all dependencies and how they are resolved --verify verify that given object really is a dynamically linked object we can handle --inhibit-cache Do not use /etc/ld.so.cache --library-path PATH use given PATH instead of content of the environment variable LD_LIBRARY_PATH --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names in LIST --audit LIST use objects named in LIST as auditors --preload LIST preload objects named in LIST
复制代码


可以看到,他其实是将 elf 文件当做一个参数传入的。然后根据一些参数加载。


而 ld 本身一定是个静态链接的程序(否则谁来动态链接它呢?)


因此我们可以使用命令行:


/tmp/prog/ld-linux-x86-64.so.2 --library-path /tmp/prog/ /tmp/prog/test
复制代码


来加载我们的程序,此时我们的系统就不再依赖目标系统的装载器了。

总结

解决此问题需要对 Linux 的应用程序的动态链接和装载有一定了解,此处涉及两个知识点:


  • 动态链接器优先查找 LD_LIBRARY_PATH 环境变量下的动态库

  • 动态链接器 ld 不仅仅是一个共享库,还是一个可以直接执行的文件,其自身是静态链接的。

发布于: 3 小时前
用户头像

SkyFire

关注

还未添加个人签名 2018.10.13 加入

还未添加个人简介

评论

发布
暂无评论
linux动态链接的程序如何在其他系统上运行