GNU/Linux >> Tutoriales Linux >  >> Linux

¿Se ejecutará un ejecutable de Linux compilado en un tipo de Linux en otro diferente?

En resumen:si está llevando un binario compilado de un host a otro usando la misma (o una compatible) arquitectura , puede estar perfectamente bien llevándolo a otra distribución . Sin embargo, a medida que aumenta la complejidad del código, aumenta la probabilidad de que se vincule con una biblioteca que no está instalada; instalado en otra ubicación; o instalado en una versión diferente, aumenta. Tomando por ejemplo su código, para el cual ldd informa las siguientes dependencias cuando se compila con gcc -o exit-test exit-test.c en un host Ubuntu Linux (derivado de Debian):

$ ldd exit-test
    linux-gate.so.1 =>  (0xb7748000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757b000)
    /lib/ld-linux.so.2 (0x8005a000)

Obviamente, este binario no se ejecutará si lo paso a, digamos, una Mac (./exit-test: cannot execute binary file: Exec format error ). Intentemos moverlo a un cuadro RHEL:

$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

Oh querido. ¿Por qué podría ser esto?

$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory

Incluso para este caso de uso, la manipulación fracasó debido a la falta de bibliotecas compartidas.

Sin embargo, si lo compilo con gcc -static exit-test-static exit-test.c , portarlo al sistema sin las bibliotecas funciona bien. A expensas, por supuesto, del espacio en disco:

$ ls -l ./exit-test{,-static}
-rwxr-xr-x  1 username  groupname    7312 Jan 29 14:18 ./exit-test
-rwxr-xr-x  1 username  groupname  728228 Jan 29 14:27 ./exit-test-static

Otra solución viable sería instalar las bibliotecas necesarias en el nuevo host.

Como muchas cosas en el universo de U&L, este es un gato con muchas pieles, dos de las cuales se describen arriba.


Eso depende. Algo compilado para IA-32 (Intel de 32 bits) puede ejecutarse en amd64, ya que Linux en Intel conserva la compatibilidad con aplicaciones de 32 bits (con el software adecuado instalado). Aquí está tu code compilado en el sistema RedHat 7.3 de 32 bits (alrededor de 2002, gcc versión 2.96) y luego el binario copiado y ejecutado en un sistema Centos 7.4 de 64 bits (alrededor de 2017):

-bash-4.2$ file code
code: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
-bash-4.2$ ./code
-bash: ./code: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
-bash-4.2$ sudo yum -y install glibc.i686
...
-bash-4.2$ ./code ; echo $?
99

Ancient RedHat 7.3 a Centos 7.4 (esencialmente RedHat Enterprise Linux 7.4) permanece en la misma familia de "distribución", por lo que probablemente tendrá una mejor portabilidad que pasar de una instalación aleatoria de "Linux desde cero" de 2002 a alguna otra distribución aleatoria de Linux en 2018 .

Algo compilado para amd64 no se ejecutaría en versiones de Linux de solo 32 bits (el hardware antiguo no conoce el hardware nuevo). Esto también es cierto para el nuevo software compilado en sistemas modernos destinados a ejecutarse en cosas antiguas antiguas, ya que las bibliotecas e incluso las llamadas al sistema pueden no ser portátiles hacia atrás, por lo que pueden requerir trucos de compilación, u obtener un compilador antiguo, etc., o posiblemente en su lugar. compilando en el sistema anterior. (Esta es una buena razón para mantener las máquinas virtuales de cosas antiguas).

La arquitectura importa; amd64 (o IA-32) es muy diferente de ARM o MIPS, por lo que no se espera que el binario de uno de ellos se ejecute en otro. A nivel de ensamblaje, el main sección de su código en IA-32 se compila a través de gcc -S code.c a

main:
    pushl %ebp
    movl %esp,%ebp
    movl $99,%eax
    popl %ebp
    ret

que puede manejar un sistema amd64 (en un sistema Linux, OpenBSD, por el contrario, en amd64 no admite binarios de 32 bits; la compatibilidad con versiones anteriores de los arcos antiguos les da a los atacantes margen de maniobra, p. CVE-2014-8866 y amigos). Mientras tanto, en un sistema MIPS big-endian main en su lugar compila a:

main:
        .frame  $fp,8,$31
        .mask   0x40000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp
        li      $2,99
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        j       $31
        nop

con el que un procesador Intel no tendrá idea de qué hacer, y lo mismo ocurre con el ensamblaje de Intel en MIPS.

Posiblemente podría usar QEMU o algún otro emulador para ejecutar código extranjero (quizás muy, muy lentamente).

¡Sin embargo! Su código es un código muy simple, por lo que tendrá menos problemas de portabilidad que cualquier otra cosa; los programas suelen hacer uso de bibliotecas que han cambiado con el tiempo (glibc, openssl, ...); para aquellos, también es posible que deba instalar versiones anteriores de varias bibliotecas (RedHat, por ejemplo, generalmente coloca "compat" en algún lugar del nombre del paquete para tales)

compat-glibc.x86_64                     1:2.12-4.el7.centos

o posiblemente preocuparse por los cambios de ABI (interfaz binaria de aplicaciones) para cosas muy antiguas que usan glibc, o cambios más recientes debido a C++ 11 u otras versiones de C++. También se podría compilar estático (aumentando en gran medida el tamaño binario en el disco) para tratar de evitar problemas con la biblioteca, aunque si algún binario antiguo hizo esto depende de si la antigua distribución de Linux compilaba casi todo lo dinámico (RedHat:sí) o no. Por otro lado, cosas como patchelf puede reajustar dinámica (ELF, pero probablemente no a.out formato) binarios para usar otras bibliotecas.

¡Sin embargo! Ser capaz de ejecutar un programa es una cosa y hacer algo útil con él es otra. Los antiguos binarios de Intel de 32 bits pueden tener problemas de seguridad si dependen de una versión de OpenSSL que tiene algún problema de seguridad horrible y no respaldado, o es posible que el programa no pueda negociar en absoluto con los servidores web modernos (como el moderno los servidores rechazan los protocolos antiguos y los cifrados del programa antiguo), o el protocolo SSH versión 1 ya no es compatible, o...


Agregando a las excelentes respuestas de @thrig y @DopeGhoti:Los sistemas operativos Unix o similares a Unix, incluido Linux, tradicionalmente siempre se diseñaron y alinearon más para la portabilidad del código fuente que para los binarios.

Si no tiene nada específico de hardware o es una fuente simple como en su ejemplo, puede moverlo sin ningún problema entre casi cualquier versión de Linux o arquitectura como código fuente siempre y cuando los servidores de destino tengan instalados los paquetes de desarrollo C , las bibliotecas necesarias y las correspondientes bibliotecas de desarrollo instaladas.

En cuanto a portar código más avanzado de versiones anteriores de Linux lejanas en el tiempo, o programas más específicos como módulos de kernel para diferentes versiones de kernel, es posible que deba adaptar y modificar el código fuente para tener en cuenta las bibliotecas/API/ABI obsoletas.


Linux
  1. ¿Comando simple de Linux que me dirá qué es el administrador de pantalla?

  2. Linux:¿ejecutar aplicaciones de Mac Os X en Linux?

  3. Linux:¿cómo probar si un binario de Linux se compiló como código independiente de la posición?

  4. ¿Comando que obligará a Linux a vaciar el caché de un archivo en un recurso compartido Nfs?

  5. Linux:¿los diferentes kernels de Linux/unix son intercambiables?

Cómo ejecutar Windows 95 en Linux

Cómo ejecutar múltiples comandos de Linux en un solo comando

Ejecute el código C# en la terminal de Linux

Use un ejecutable CLI de versión de PHP diferente para un comando

¿Cómo mantener el código ejecutable en la memoria incluso bajo presión de memoria? en Linux

¿Cómo puedo ejecutar un ejecutable que no es de confianza en Linux de forma segura?