I have a Linux binary, without sources, that works on one machine, and I'd like to make a self-contained package that would run on a different machine of the same architecture. What is a way of achieving this?
In my case, both machines have the same architecture, same Ubuntu kernel, but target machine doesn't have make
and has wrong version of files under /lib
and /usr
One idea I had was to use chroot
and recreate a subset of the filesystem that the binary uses, possibly using strace
to figure out what it needs. Is there a tool that does this already?
For posterity, here's how I figure out which files a process opens
#!/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
Update
The problem with LD_LIBRARY_PATH
solutions is that /lib
is hardcoded into interpreter and takes precedence over LD_LIBRARY_PATH
, so native versions will get loaded first. The interpreter is hardcoded into the binary. One approach might be to patch the interpreter and run the binary as patched_interpreter mycommandline
Problem is that when mycommandline
is starts with java
, this doesn't work because Java sets-up LD_LIBRARY_PATH
and restarts itself, which resorts to the old interpreter. A solution that worked for me was to open the binary in the text editor, find the interpreter (/lib/ld-linux-x86-64.so.2
), and replace it with same-length path to the patched interpreter
There are almost certainly better answers, but you can find out what libraries the binary needs with the
ldd
command (example for thels
binary):Once you have this, you could make copies and put them in the proper locations on the target machine.
As others have mentioned, static linking is one option. Except static linking with glibc gets a little more broken with every release (sorry, no reference; just my experience).
Your
chroot
idea is probably overkill.The solution most commercial products use, as far as I can tell, is to make their "application" a shell script that sets
LD_LIBRARY_PATH
and then runs the actual executable. Something along these lines:Then you just dump a copy of all the relevant .so files under
lib/
, put your executable underbin/
, put the script in.
, and ship the whole tree.(To be production-worthy, properly prepend
"$here"/lib
toLD_LIBRARY_PATH
if it is non-empty, etc.)[edit, to go with your update]
I think you may be confused about what is hard-coded and what is not.
ld-linux-x86-64.so.2
is the dynamic linker itself; and you are correct that its path is hard-coded into the ELF header. But the other libraries are not hard-coded; they are searched for by the dynamic linker, which will honorLD_LIBRARY_PATH
.If you really need a different ld-linux.so, instead of patching the ELF header, simply run the dynamic linker itself:
This will use your linker instead of the one listed in the ELF header.
Patching the executable itself is evil. Please consider the poor person who has to maintain your stuff after you move on... Nobody is going to expect you to have hacked the ELF header by hand. Anybody can read what a shell script is doing.
Just my $0.02.
There's CDE a bit of software designed to do exactly what you want. Here's a google tech talk about it http://www.youtube.com/watch?v=6XdwHo1BWwY