desarrollo-web-br-bd.com

¿Se ejecutará un ejecutable de Linux compilado en un "sabor" de Linux en uno diferente?

¿El ejecutable de un programa pequeño y extremadamente simple, como el que se muestra a continuación, que se compila en una versión de Linux, se ejecutará en una versión diferente? ¿O necesitaría ser recompilado?

¿Importa la arquitectura de la máquina en un caso como este?

int main()
{
  return (99);
}
60
JCDeen

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á su code compilado en el sistema RedHat 7.3 de 32 bits (circa 2002, gcc versión 2.96) y luego el binario copiado y ejecutado en un sistema Centos 7.4 de 64 bits (circa 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) se mantiene en la misma familia de "distribución", por lo que probablemente tendrá una mejor portabilidad que pasar de una instalación aleatoria "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 nuevo hardware). Esto también es cierto para el nuevo software compilado en sistemas modernos destinados a ejecutarse en cosas antiguas y antiguas, ya que las bibliotecas y 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 y así sucesivamente, o posiblemente compilando en el sistema anterior. (Esta es una buena razón para mantener las máquinas virtuales de las cosas antiguas antiguas).

La arquitectura sí importa; AMD64 (o IA-32) es muy diferente de ARM o MIPS), por lo que no se esperaría que el binario de uno de ellos se ejecute en otro. En el nivel de la Asamblea main sección de su código en compilaciones IA-32 a través de gcc -S code.c a

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

que un sistema AMD64 puede manejar (en un sistema Linux - OpenBSD en contraste con AMD64 no no admite binarios de 32 bits; compatibilidad con versiones anteriores de archs antiguos les da a los atacantes margen de maniobra, por ejemplo CVE-2014-8866 y amigos). Mientras tanto, en un sistema MIPS big-endianmain en su lugar se compila para:

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 del mismo modo para la Asamblea 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 muy simple, por lo que tendrá menos problemas de portabilidad que cualquier otra cosa; los programas suelen utilizar bibliotecas que han cambiado con el tiempo (glibc, openssl, ...); para aquellos que también pueden necesitar instalar versiones anteriores de varias bibliotecas (RedHat, por ejemplo, generalmente coloca "compat" en algún lugar del nombre del paquete)

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

o posiblemente preocuparse por los cambios de ABI (Application Binary Interface) por cosas viejas que usan glibc, o cambios más recientes debido a C++ 11 u otras versiones de C++. También se podría compilar estática (aumentando enormemente 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 distribución anterior de Linux estaba compilando casi todo lo dinámico (RedHat: sí) o no. Por otro lado, cosas como patchelf pueden reiniciar dinámico (ELF, pero probablemente no a.out formato) binarios para usar otras bibliotecas.

¡Sin embargo! Poder ejecutar un programa es una cosa, y hacer algo útil con él es otra. Los viejos 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 el programa puede no ser capaz de negociar con servidores web modernos (como los modernos los servidores rechazan los protocolos y cifrados antiguos del programa antiguo), o el protocolo SSH versión 1 ya no es compatible, o ...

50
thrig

En resumen: si está llevando un binario compilado de un Host a otro usando el mismo (o un compatible) arquitectura, puede estar perfectamente bien llevarlo a otro distribución . Sin embargo, a medida que aumenta la complejidad del código, la probabilidad de estar vinculado a 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 pateo a, por ejemplo, una Mac (./exit-test: cannot execute binary file: Exec format error). Intentemos moverlo a una caja 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, el montacargas falló 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 requeridas en el nuevo Host.

Al igual que con muchas cosas en el universo U&L, este es un gato con muchas máscaras, dos de las cuales se describen anteriormente.

69
DopeGhoti

Además de las excelentes respuestas @thrig y @DopeGhoti: los sistemas operativos Unix o similares a Unix, incluido Linux, siempre se diseñaron y alinearon más tradicionalmente para la portabilidad del código fuente que 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 la versión any de Linux o la arquitectura como código fuente siempre y cuando como los servidores de destino tienen instalados los paquetes de desarrollo C, las bibliotecas necesarias y las bibliotecas de desarrollo correspondientes instaladas.

En la medida en que transfiera código más avanzado de versiones anteriores de Linux distantes 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 bibliotecas/API/ABI en desuso.

25
Rui F Ribeiro

Por por defecto , casi seguro que tendrás problemas con las bibliotecas externas. Algunas de las otras respuestas entran en más detalles sobre esos problemas, por lo que no duplicaré su trabajo.

Sin embargo, usted puede compilar muchos programas, incluso los no triviales, para que sean portátiles entre sistemas Linux. La clave es el juego de herramientas llamado Linux Standard Base . LSB está diseñado para crear solo este tipo de aplicaciones portátiles. Compile una aplicación para LSB v5.0 y se ejecutará en cualquier otro entorno Linux (de la misma arquitectura) que implemente LSB v5.0. Algunas distribuciones de Linux son compatibles con LSB, y otras incluyen kits de herramientas/bibliotecas LSB como un paquete instalable. Si construye su aplicación usando las herramientas LSB (como el lsbcc wrapper para gcc) y vincula a la versión LSB de las bibliotecas, creará una aplicación portátil.

20
bta

Tal vez.

Las cosas que tienden a romperlo incluyen.

  1. Diferentes arquitecturas. Obviamente, arquitecturas totalmente diferentes no funcionarán (a menos que tenga algo como el modo de usuario qemu con binfmt_misc, pero esa no es una configuración normal). Los binarios x86 pueden funcionar en AMD64 pero solo si las bibliotecas de 32 bits requeridas están disponibles.
  2. Versiones de la biblioteca. Si la versión es incorrecta, no encontrará la biblioteca en absoluto. Si la versión es la misma pero el binario se construye con una versión más nueva de la biblioteca de la que se está ejecutando, es posible que no se cargue debido a nuevos símbolos o nuevas versiones de símbolos. En particular, glibc es un gran usuario de versiones de símbolos, por lo que es muy probable que los binarios construidos contra un glibc más nuevo fallen con un glibc más antiguo.

Si evita usar bibliotecas que cambian rápidamente, evite los cambios de arquitectura y construya sobre la distribución más antigua a la que desea apuntar, tiene una buena oportunidad de hacer que un binario funcione en muchas distribuciones.

11
plugwash

Además de algunas de las cosas mencionadas anteriormente, ha habido algunos cambios en el formato de archivo ejecutable. En su mayor parte, Linux usa ELF, pero las versiones anteriores usaban a.out o COFF.

El comienzo de un wikihole:

https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats

Puede haber una forma de obtener versiones anteriores para ejecutar formatos más nuevos, pero personalmente nunca lo he investigado.

4
Ben