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/
下,对应的依赖库也拷贝到这里了,那么可以这样启动程序:
有很多手段可以达到这个目标,可以随意发挥。
目标系统与本地的装载器版本不同
如果目标系统与本地的装载器版本不同,就比较棘手一点,但是也不是完全没有办法。
当我们在 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
运行:
可以看到,他其实是将 elf 文件当做一个参数传入的。然后根据一些参数加载。
而 ld 本身一定是个静态链接的程序(否则谁来动态链接它呢?)
因此我们可以使用命令行:
来加载我们的程序,此时我们的系统就不再依赖目标系统的装载器了。
总结
解决此问题需要对 Linux 的应用程序的动态链接和装载有一定了解,此处涉及两个知识点:
动态链接器优先查找 LD_LIBRARY_PATH 环境变量下的动态库
动态链接器 ld 不仅仅是一个共享库,还是一个可以直接执行的文件,其自身是静态链接的。
版权声明: 本文为 InfoQ 作者【SkyFire】的原创文章。
原文链接:【http://xie.infoq.cn/article/45da4853d57268f85a4bb3b1a】。文章转载请联系作者。
评论