我有一个Linux二进制文件,没有源代码,可以在一台机器上运行,我想制作一个可以在同一架构的不同机器上运行的独立软件包。有什么方法可以达到这个目的?
在我的情况下,两台机器具有相同的体系结构,相同的Ubuntu内核,但目标机器没有make
并且/lib
和/usr
下的文件版本错误
我的一个想法是使用chroot
并重新创建二进制使用的文件系统的子集,可能使用strace
来确定它需要什么。是否有工具可以做到这一点?
对于后代,这是我如何确定流程打开的文件
#!/usr/bin/python
# source of trace_fileopen.py
# Runs command and prints all files that have been successfully opened with mode O_RDONLY
# example: trace_fileopen.py ls -l
import re, sys, subprocess, os
if __name__=='__main__':
strace_fn = '/tmp/strace.out'
strace_re = re.compile(r'([^(]+?)\((.*)\)\s*=\s*(\S+?)\s+(.*)$')
cmd = sys.argv[1]
nowhere = open('/dev/null','w')#
p = subprocess.Popen(['strace','-o', strace_fn]+sys.argv[1:], stdout=nowhere, stderr=nowhere)
sts = os.waitpid(p.pid, 0)[1]
output = []
for line in open(strace_fn):
# ignore lines like --- SIGCHLD (Child exited) @ 0 (0) ---
if not strace_re.match(line):
continue
(function,args,returnval,msg) = strace_re.findall(line)[0]
if function=='open' and returnval!='-1':
(fname,mode)=args.split(',',1)
if mode.strip()=='O_RDONLY':
if fname.startswith('"') and fname.endswith('"') and len(fname)>=2:
fname = fname[1:-1]
output.append(fname)
prev_line = ""
for line in sorted(output):
if line==prev_line:
continue
print line
prev_line = line
更新的
LD_LIBRARY_PATH
解决方案的问题在于/lib
被硬编码到解释器中并优先于LD_LIBRARY_PATH
,因此将首先加载本机版本。解释器被硬编码到二进制文件中。一种方法可能是修补解释器并将二进制文件运行为patched_interpreter mycommandline
问题是当mycommandline
以java
开头时,这不起作用,因为Java设置{{1}并重新启动自身,它转向旧的解释器。对我有用的解决方案是在文本编辑器中打开二进制文件,找到解释器(LD_LIBRARY_PATH
),并将其替换为修补解释器的相同长度路径
答案 0 :(得分:4)
正如其他人所提到的,静态链接是一种选择。除了与glibc的静态链接在每次发布时都会受到更多破坏(抱歉,没有参考;只是我的经验)。
您的chroot
想法可能有点过分。
据我所知,大多数商业产品使用的解决方案是使他们的“应用程序”成为设置LD_LIBRARY_PATH
的shell脚本,然后运行实际的可执行文件。这些方面的东西:
#!/bin/sh
here=`dirname "$0"`
export LD_LIBRARY_PATH="$here"/lib
exec "$here"/bin/my_app "$@"
然后,您只需转储lib/
下所有相关.so文件的副本,将您的可执行文件放在bin/
下,将脚本放在.
中,然后运送整棵树。< / p>
(要有生产价值,如果它是非空的话,请"$here"/lib
正确地添加LD_LIBRARY_PATH
等。)
[编辑,继续更新]
我认为你可能会对硬编码和不编码的内容感到困惑。 ld-linux-x86-64.so.2
是动态链接器本身;并且你的路径被硬编码到ELF头中是正确的。但其他库不是硬编码的;它们由动态链接器搜索,它将尊重LD_LIBRARY_PATH
。
如果你真的需要一个不同的ld-linux.so,而不是修补ELF头,只需运行动态链接器本身:
/path/to/my-ld-linux.so my_program <args>
这将使用您的链接器而不是ELF标头中列出的链接器。
修补可执行文件本身是邪恶的。请考虑一下在你搬家之后必须维护你的东西的穷人...... 没人会指望你手工砍掉ELF标题。 任何人都可以阅读shell脚本正在做什么。
只需我0.02美元。
答案 1 :(得分:2)
几乎肯定有更好的答案,但您可以使用ldd
命令(ls
二进制文件的示例)找出二进制文件需要哪些库:
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007ffffff18000)
librt.so.1 => /lib/librt.so.1 (0x00007f5ae565c000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00007f5ae543e000)
libacl.so.1 => /lib/libacl.so.1 (0x00007f5ae5235000)
libc.so.6 => /lib/libc.so.6 (0x00007f5ae4eb2000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f5ae4c95000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5ae588b000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f5ae4a90000)
libattr.so.1 => /lib/libattr.so.1 (0x00007f5ae488b000)
完成此操作后,您可以复制并将它们放在目标计算机上的适当位置。
答案 2 :(得分:2)
有CDE个软件可以完全按照您的要求进行操作。这是谷歌技术谈论它 http://www.youtube.com/watch?v=6XdwHo1BWwY