2011-07-15 27 views
10

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?¿Cómo hacer que Unix sea binario autónomo?

En mi caso, las dos máquinas tienen la misma arquitectura, mismo kernel de Ubuntu, pero la máquina de destino no tiene make y tiene una versión incorrecta de los archivos bajo /lib y /usr

Una idea que tenía era de usar y chroot recree un subconjunto del sistema de archivos que utiliza el binario, posiblemente usando strace para descubrir lo que necesita. ¿Hay alguna herramienta que ya lo haga?

Para la posteridad, así es como puedo averiguar qué archivos de un proceso abre

#!/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 LD_LIBRARY_PATH soluciones es que /lib está codificada en intérprete y tiene prioridad sobre LD_LIBRARY_PATH, por lo que las versiones nativas ser cargado primero El intérprete está codificado en el binario. Un enfoque podría ser parchar el intérprete y ejecutar el código binario como patched_interpreter mycommandline El problema es que cuando mycommandline se inicia con java, esto no funciona porque Java configura 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 la misma longitud del intérprete parcheado

+4

Parece que quieres un binario estático. Construye en todas las bibliotecas que usa. –

+0

Lo que dijo @VLC, tienes que marcarlo para enlaces estáticos, lo que puede ser un poco molesto. –

+0

¿Construiste el binario en cuestión? Si lo hizo, es muy posible que pueda reconstruirlo estáticamente. – Cascabel

Respuesta

2

Es casi seguro que hay mejores respuestas, pero puede encontrar lo que las necesidades bibliotecas binarias con el comando ldd (ejemplo para el ls binario):

$ 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, se podía hacer copias y ponerlas en los lugares adecuados en el equipo de destino.

+0

En realidad, he hecho algo así (usando 'strace' para encontrar bibliotecas requeridas adicionales no informadas por' ldd'), pero no me gusta la idea de mi programa potencialmente rompiendo debido a cosas fuera de '~' sobre las cuales no tengo control. 'chroot' se ve bien, pero tomaría trabajo descubrir cómo reconstruir el sistema de archivos –

4

Como han mencionado otros, 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).

Su idea de chroot es probablemente exagerada.

La solución que la mayoría de los productos comerciales usan, 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 a lo largo de estas líneas:

#!/bin/sh 
here=`dirname "$0"` 
export LD_LIBRARY_PATH="$here"/lib 
exec "$here"/bin/my_app "[email protected]" 

A continuación, sólo volcar una copia de todos los archivos relevantes .so bajo lib/, ponga su ejecutable bajo bin/, poner el script en ., y el barco todo el árbol.

(Ser producción digna, adecuada a anteponer "$here"/libLD_LIBRARY_PATH si no está vacío, etc.)

[editar, para ir con su actualización]

Creo que puede ser confundido acerca qué está codificado y qué 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 cumplirá con LD_LIBRARY_PATH.

Si realmente necesita un ld-linux.so diferente, en lugar de parchear la cabecera ELF, simplemente ejecute el enlazador dinámico en sí:

/path/to/my-ld-linux.so my_program <args> 

Esto utilizará su enlazador en lugar de la que aparece en el ELF encabezamiento.

Aplicar parches al ejecutable en sí es malo. Considere a la persona pobre que tiene que mantener sus cosas después de mudarse ... Nadie va a esperar que haya pirateado el encabezado ELF a mano. Cualquiera puede leer lo que está haciendo un script de shell.

Sólo mi $ 0.02.

+0

El problema aquí es que las cosas en'/lib' se cargarán antes que las cosas en 'LD_LIBRARY_PATH'. Lo solucioné sin usar 'chroot', cuerpo de pregunta actualizado –

+0

@Yaroslav: estado allí, hecho eso ... Tenga en cuenta que también puede ejecutar el código binario como" /lib/my-ld-linux.so ". Cuando hagas esto, 'my-ld-linux.so' ignorará la versión en el encabezado ELF. Podría decirse que es más limpio ejecutar su ejecutable de una secuencia de comandos (para que cualquiera pueda ver lo que está haciendo) que aplicar un parche al encabezado ELF en el archivo ejecutable (que nadie podrá imaginar). – Nemo

+0

Sí, realmente no se puede hacer una vinculación completamente estática con glibc en absoluto debido al mecanismo de Cambio de Servicio de Nombre para permitir que las cosas incluyan tipos alternativos de resolución de nombre de host. – Spudd86

Cuestiones relacionadas