GNU/Linux >> Tutoriels Linux >  >> Linux

Un exécutable Linux compilé sur une version de Linux fonctionnera-t-il sur une autre ?

En bref :si vous transférez un binaire compilé d'un hôte à un autre en utilisant la même architecture (ou une compatible) , vous pouvez très bien le transférer vers une autre distribution . Cependant, à mesure que la complexité du code augmente, la probabilité d'être lié à une bibliothèque qui n'est pas installée ; installé dans un autre endroit ; ou installé à une version différente, augmente. Prenons par exemple votre code, pour lequel ldd signale les dépendances suivantes lorsqu'il est compilé avec gcc -o exit-test exit-test.c sur un hôte Ubuntu Linux (dérivé 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)

Évidemment, ce binaire ne fonctionnera pas si je le lance sur, disons, un Mac (./exit-test: cannot execute binary file: Exec format error ). Essayons de le déplacer vers une boîte RHEL :

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

Oh cher. Pourquoi cela pourrait-il être ?

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

Même pour ce cas d'utilisation, le chariot élévateur a échoué en raison de bibliothèques partagées manquantes.

Cependant, si je le compile avec gcc -static exit-test-static exit-test.c , le portage sur le système sans les bibliothèques fonctionne très bien. Au détriment bien sûr de l'espace disque :

$ 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

Une autre solution viable consisterait à installer les bibliothèques requises sur le nouvel hôte.

Comme pour beaucoup de choses dans l'univers U&L, c'est un chat avec de nombreuses peaux, dont deux sont décrites ci-dessus.


Ça dépend. Quelque chose compilé pour IA-32 (Intel 32 bits) peut fonctionner sur amd64 car Linux sur Intel conserve la rétrocompatibilité avec les applications 32 bits (avec le logiciel approprié installé). Voici votre code compilé sur le système RedHat 7.3 32 bits (vers 2002, gcc version 2.96), puis le binaire copié et exécuté sur un système Centos 7.4 64 bits (vers 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

L'ancien RedHat 7.3 à Centos 7.4 (essentiellement RedHat Enterprise Linux 7.4) reste dans la même famille de "distribution", il aura donc probablement une meilleure portabilité que de passer d'une installation aléatoire "Linux à partir de zéro" de 2002 à une autre distribution Linux aléatoire en 2018 .

Quelque chose compilé pour amd64 ne fonctionnerait pas sur les versions 32 bits de Linux uniquement (l'ancien matériel ne connaît pas le nouveau matériel). Cela est également vrai pour les nouveaux logiciels compilés sur des systèmes modernes destinés à être exécutés sur d'anciennes choses, car les bibliothèques et même les appels système peuvent ne pas être rétro-portables, ce qui peut nécessiter des astuces de compilation, ou l'obtention d'un ancien compilateur, etc., ou peut-être à la place compilation sur l'ancien système. (C'est une bonne raison de conserver des machines virtuelles d'anciennes choses.)

L'architecture compte; amd64 (ou IA-32) est très différent d'ARM ou de MIPS, de sorte que le binaire de l'un d'entre eux ne devrait pas fonctionner sur un autre. Au niveau de l'assemblage le main section de votre code sur IA-32 compile via gcc -S code.c à

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

qu'un système amd64 peut gérer (sur un système Linux - OpenBSD en revanche sur amd64 ne le fait pas prend en charge les binaires 32 bits ; la rétrocompatibilité avec les anciennes arches donne aux attaquants une marge de manœuvre, par ex. CVE-2014-8866 et amis). Pendant ce temps sur un système MIPS big-endian main compile à la place :

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

dont un processeur Intel n'aura aucune idée de quoi faire, et de même pour l'assemblage Intel sur MIPS.

Vous pouvez éventuellement utiliser QEMU ou un autre émulateur pour exécuter du code étranger (peut-être très, très lentement).

Cependant! Votre code est un code très simple, il aura donc moins de problèmes de portabilité qu'autre chose ; les programmes utilisent généralement des bibliothèques qui ont changé au fil du temps (glibc, openssl, ...); pour ceux-ci, il peut également être nécessaire d'installer des versions plus anciennes de diverses bibliothèques (RedHat, par exemple, met généralement "compat" quelque part dans le nom du package pour cela)

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

ou peut-être s'inquiéter des changements ABI (Application Binary Interface) pour des choses très anciennes qui utilisent glibc, ou plus récemment des changements dus à C++11 ou à d'autres versions C++. On pourrait également compiler statique (augmentant considérablement la taille du binaire sur le disque) pour essayer d'éviter les problèmes de bibliothèque, bien que le fait que certains anciens binaires le fassent dépend du fait que l'ancienne distribution Linux compilait presque tout dynamique (RedHat :oui) ou non. D'un autre côté, des choses comme patchelf peut rejigger dynamique (ELF, mais probablement pas a.out format) binaires pour utiliser d'autres bibliothèques.

Cependant! Être capable d'exécuter un programme est une chose, et en faire quelque chose d'utile en est une autre. Les anciens binaires Intel 32 bits peuvent avoir des problèmes de sécurité s'ils dépendent d'une version d'OpenSSL qui présente un problème de sécurité horrible et non rétroporté, ou le programme peut ne pas être en mesure de négocier du tout avec les serveurs Web modernes (comme le les serveurs rejettent les anciens protocoles et chiffrements de l'ancien programme), ou le protocole SSH version 1 n'est plus supporté, ou ...


En plus des excellentes réponses de @thrig et @DopeGhoti :les systèmes d'exploitation Unix ou de type Unix, y compris Linux, ont toujours été conçus et alignés davantage pour la portabilité du code source que pour les binaires.

Si vous n'avez rien de matériel spécifique ou si vous êtes une source simple comme dans votre exemple, vous pouvez le déplacer sans aucun problème entre à peu près tout version de Linux ou architecture comme code source tant que les serveurs de destination ont les packages de développement C installés , les bibliothèques nécessaires et les bibliothèques de développement correspondantes installées.

En ce qui concerne le portage de code plus avancé d'anciennes versions de Linux éloignées dans le temps, ou de programmes plus spécifiques comme les modules du noyau pour différentes versions du noyau, vous devrez peut-être adapter et modifier le code source pour tenir compte des bibliothèques/API/ABI obsolètes.


Linux
  1. Linux - Un exécutable Linux compilé sur une «saveur» de Linux fonctionnera-t-il sur un autre?

  2. Linux – Les différents noyaux Linux/unix sont-ils interchangeables ?

  3. Comment exécuter un programme avec un répertoire de travail différent de l'actuel, à partir du shell Linux ?

  4. Existe-t-il une différence entre les fichiers binaires exécutables entre les distributions ?

  5. Intégrer une icône dans un exécutable Linux

Comment exécuter Windows 95 sous Linux

Comment exécuter plusieurs commandes Linux en une seule commande

Linux - Comment tester si un binaire Linux a été compilé en tant que code indépendant de la position ?

Commande qui forcera Linux à vider le cache d'un fichier sur un partage NFS ?

Meilleure pratique pour exécuter le service Linux en tant qu'utilisateur différent

Exécutez le code C # sur le terminal Linux