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.