linux - mac - musicbrainz picard español
¿Cómo hacer que Unix sea binario autónomo? (3)
Tengo un binario de Linux, sin fuentes, que funciona en una máquina, y me gustaría crear un paquete independiente que se ejecute en una máquina diferente de la misma arquitectura. ¿Cuál es una forma de lograr esto?
En mi caso, ambas máquinas tienen la misma arquitectura, el mismo kernel de Ubuntu, pero la máquina de destino no tiene make
y tiene una versión incorrecta de los archivos en /lib
y /usr
Una idea que tuve fue utilizar chroot
y recrear un subconjunto del sistema de archivos que usa el binario, posiblemente usando strace
para descubrir qué es lo que necesita. ¿Hay alguna herramienta que ya lo haga?
Para la posteridad, así es como averiguo qué archivos abre un proceso
#!/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
Actualización El problema con las soluciones LD_LIBRARY_PATH
es que /lib
está codificado en el intérprete y tiene prioridad sobre LD_LIBRARY_PATH
, por lo que las versiones nativas se cargarán primero. El intérprete está codificado en el binario. Un enfoque podría ser parchear el intérprete y ejecutar el binario como patched_interpreter mycommandline
problema es que cuando mycommandline
se inicia con java
, esto no funciona porque Java establece LD_LIBRARY_PATH
y se reinicia a sí mismo, que recurre al antiguo intérprete. Una solución que funcionó para mí fue abrir el binario en el editor de texto, encontrar el intérprete ( /lib/ld-linux-x86-64.so.2
) y reemplazarlo con una ruta de igual longitud para el intérprete de parches
Es casi seguro que hay mejores respuestas, pero puede averiguar qué bibliotecas necesita el binario con el comando ldd
(ejemplo para el binario 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)
Una vez que tenga esto, puede hacer copias y colocarlas en las ubicaciones correctas en la máquina de destino.
Como otros han mencionado, la vinculación estática es una opción. Excepto la vinculación estática con glibc se rompe un poco más con cada lanzamiento (lo siento, sin referencia, solo mi experiencia).
Tu idea de chroot
es probablemente excesiva.
La solución que utilizan la mayoría de los productos comerciales, hasta donde puedo decir, es convertir su "aplicación" en un script de shell que establece LD_LIBRARY_PATH
y luego ejecuta el ejecutable real. Algo en esta línea:
#!/bin/sh
here=`dirname "$0"`
export LD_LIBRARY_PATH="$here"/lib
exec "$here"/bin/my_app "$@"
Luego, simplemente coloca una copia de todos los archivos .so relevantes bajo lib/
, coloca el ejecutable bajo bin/
, coloca el script .
y envía todo el árbol
(Para ser productivo, anteponga "$here"/lib
a LD_LIBRARY_PATH
si no está vacío, etc.)
[Editar, para ir con tu actualización]
Creo que puede estar confundido acerca de lo que está codificado y lo que no. ld-linux-x86-64.so.2
es el enlazador dinámico en sí mismo; y tiene razón en que su ruta está codificada en el encabezado ELF. Pero las otras bibliotecas no están codificadas; los busca el enlazador dinámico, que respetará LD_LIBRARY_PATH
.
Si realmente necesita un ld-linux.so diferente, en lugar de parchear el encabezado ELF, simplemente ejecute el enlazador dinámico en sí:
/path/to/my-ld-linux.so my_program <args>
Esto usará su enlazador en lugar del que figura en el encabezado ELF.
Parchear el ejecutable en sí mismo es malo. Por favor, considere a la persona pobre que tiene que mantener sus cosas después de que se mude ... Nadie va a esperar que haya pirateado el encabezado ELF a mano. Cualquiera puede leer lo que está haciendo un script de shell.
Solo mi $ 0.02.
Hay CDE un poco de software diseñado para hacer exactamente lo que quieres. Aquí hay una charla de tecnología de google sobre ella http://www.youtube.com/watch?v=6XdwHo1BWwY