Cette question est ancienne, les autres réponses sont anciennes. La réponse "Employed Russian" est très bonne et informative, mais cela ne fonctionne que si vous avez le code source. Si vous ne le faites pas, les alternatives à l'époque étaient très délicates. Heureusement, de nos jours, nous avons une solution simple à ce problème (comme commenté dans l'une de ses réponses), en utilisant patchelf. Tout ce que vous avez à faire est :
$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp
Et après cela, vous pouvez simplement exécuter votre fichier :
$ ./myapp
Pas besoin de chroot
ou modifier manuellement les fichiers binaires, heureusement. Mais n'oubliez pas de sauvegarder votre binaire avant de le patcher, si vous n'êtes pas sûr de ce que vous faites, car cela modifie votre fichier binaire. Après l'avoir corrigé, vous ne pouvez pas restaurer l'ancien chemin vers interpreter/rpath. Si cela ne fonctionne pas, vous devrez continuer à le corriger jusqu'à ce que vous trouviez le chemin qui fonctionnera réellement... Eh bien, cela ne doit pas être un processus d'essais et d'erreurs. Par exemple, dans l'exemple d'OP, il avait besoin de GLIBC_2.3
, afin que vous puissiez facilement trouver quelle bibliothèque fournit cette version en utilisant strings
:
$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3
En théorie, le premier grep serait vide car la libc système n'a pas la version qu'il veut, et le 2ème devrait sortir GLIBC_2.3 car il a la version myapp
utilise, donc nous savons que nous pouvons patchelf
notre binaire en utilisant ce chemin. Si vous obtenez un défaut de segmentation, lisez la note à la fin.
Lorsque vous essayez d'exécuter un binaire sous Linux, le binaire essaie de charger l'éditeur de liens, puis les bibliothèques, et ils doivent tous être dans le chemin et/ou au bon endroit. Si votre problème concerne l'éditeur de liens et que vous souhaitez savoir quel chemin votre binaire recherche, vous pouvez le découvrir avec cette commande :
$ readelf -l myapp | grep interpreter
[Requesting program interpreter: /lib/ld-linux.so.2]
Si votre problème concerne les bibliothèques, les commandes qui vous indiqueront les bibliothèques utilisées sont :
$ readelf -d myapp | grep Shared
$ ldd myapp
Cela listera les bibliothèques dont votre binaire a besoin, mais vous connaissez probablement déjà celles qui posent problème, car elles génèrent déjà des erreurs comme dans le cas d'OP.
"patchelf" fonctionne pour de nombreux problèmes différents que vous pouvez rencontrer en essayant d'exécuter un programme, liés à ces 2 problèmes. Par exemple, si vous obtenez :ELF file OS ABI invalid
, il peut être corrigé en définissant un nouveau chargeur (le --set-interpreter
partie de la commande) comme je l'explique ici. Un autre exemple concerne le problème d'obtention de No such file or directory
lorsque vous exécutez un fichier qui est là et exécutable, comme illustré ici. Dans ce cas particulier, il manquait à OP un lien vers le chargeur, mais peut-être que dans votre cas, vous n'avez pas d'accès root et ne pouvez pas créer le lien. Définir un nouvel interprète résoudrait votre problème.
Merci Employed Russian et Michael Pankov pour la perspicacité et la solution !
Remarque pour erreur de segmentation :vous pourriez être dans le cas où myapp
utilise plusieurs bibliothèques, et la plupart d'entre elles sont correctes mais certaines ne le sont pas ; alors vous patchelf
dans un nouveau répertoire, et vous obtenez une erreur de segmentation. Lorsque vous patchelf
votre binaire, vous changez le chemin de plusieurs bibliothèques, même si certaines étaient à l'origine dans un chemin différent. Jetez un oeil à mon exemple ci-dessous :
$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
linux-vdso.so.1 => (0x00007fffb167c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)
Notez que la plupart des bibliothèques sont en /lib/x86_64-linux-gnu/
mais celui qui pose problème (libstdc++.so.6
) est sur /usr/lib/x86_64-linux-gnu
. Après avoir corrigé myapp
pointer vers /path/to/mylibs
, j'ai eu un défaut de segmentation. Pour une raison quelconque, les bibliothèques ne sont pas totalement compatibles avec le binaire. Depuis myapp
je ne me suis pas plaint des bibliothèques d'origine, je les ai copiées de /lib/x86_64-linux-gnu/
à /path/to/mylibs2
, et j'ai aussi copié libstdc++.so.6
de /path/to/mylibs
là. Ensuite, je l'ai corrigé en /path/to/mylibs2
, et myapp
fonctionne maintenant. Si votre binaire utilise différentes bibliothèques et que vous avez différentes versions, il se peut que vous ne puissiez pas résoudre votre problème. :( Mais si c'est possible, mélanger les bibliothèques pourrait être la solution. Ce n'est pas idéal, mais peut-être ça va marcher. Bonne chance !
Utilisez LD_PRELOAD :placez votre bibliothèque quelque part hors des répertoires man lib et exécutez :
LD_PRELOAD='mylibc.so anotherlib.so' program
Voir :l'article de Wikipédia
Tout d'abord, la dépendance la plus importante de chaque programme lié dynamiquement est l'éditeur de liens. Toutes les bibliothèques doivent donc correspondre à la version de l'éditeur de liens.
Prenons un exemple simple :j'ai le système newset ubuntu dans lequel j'exécute un programme (dans mon cas, il s'agit du compilateur D - ldc2). J'aimerais l'exécuter sur l'ancien CentOS, mais à cause de l'ancienne bibliothèque glibc, c'est impossible. j'ai
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
Je dois copier toutes les dépendances d'ubuntu vers centos. La méthode appropriée est la suivante :
Commençons par vérifier toutes les dépendances :
ldd ldc2-1.5.0-linux-x86_64/bin/ldc2
linux-vdso.so.1 => (0x00007ffebad3f000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)
linux-vdso.so.1 n'est pas une vraie bibliothèque et nous n'avons pas à nous en soucier.
/lib64/ld-linux-x86-64.so.2 est l'éditeur de liens, qui est utilisé par Linux pour lier l'exécutable avec toutes les bibliothèques dynamiques.
Le reste des fichiers sont de véritables bibliothèques et tous, avec l'éditeur de liens, doivent être copiés quelque part dans les centos.
Supposons que toutes les bibliothèques et l'éditeur de liens se trouvent dans le répertoire "/mylibs".
ld-linux-x86-64.so.2 - comme je l'ai déjà dit - est l'éditeur de liens. Ce n'est pas une bibliothèque dynamique mais un exécutable statique. Vous pouvez l'exécuter et voir qu'il a même certains paramètres, par exemple --library-path (j'y reviendrai).
Sur Linux, le programme lié dynamiquement peut être lancé simplement par son nom, par exemple
/bin/ldc2
Linux charge ce programme dans la RAM et vérifie quel éditeur de liens est défini pour lui. Habituellement, sur un système 64 bits, il s'agit de /lib64/ld-linux-x86-64.so.2 (dans votre système de fichiers, il s'agit d'un lien symbolique vers le véritable exécutable). Ensuite, Linux exécute l'éditeur de liens et charge les bibliothèques dynamiques.
Vous pouvez également changer cela un peu et faire une telle astuce :
/mylibs/ld-linux-x86-64.so.2 /bin/ldc2
C'est la méthode pour forcer Linux à utiliser un éditeur de liens spécifique.
Et maintenant, nous pouvons revenir au paramètre mentionné précédemment --library-path
/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2
Il exécutera ldc2 et chargera les bibliothèques dynamiques à partir de /mylibs.
C'est la méthode pour appeler l'exécutable avec les bibliothèques choisies (pas celles par défaut du système).
Il est très possible d'avoir plusieurs versions de glibc sur le même système (nous le faisons tous les jours).
Cependant, vous devez savoir que glibc se compose de plusieurs éléments (plus de 200 bibliothèques partagées) qui doivent tous correspondre. L'un des éléments est ld-linux.so.2, et il doit match libc.so.6, ou vous verrez les erreurs que vous voyez.
Le chemin absolu vers ld-linux.so.2 est codé en dur dans l'exécutable au moment de la liaison et ne peut pas être facilement modifié une fois la liaison établie (mise à jour :peut être effectuée avec patchelf ; voir cette réponse ci-dessous).
Pour créer un exécutable qui fonctionnera avec la nouvelle glibc, procédez comme suit :
g++ main.o -o myapp ... \
-Wl,--rpath=/path/to/newglibc \
-Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2
Le -rpath
l'option de l'éditeur de liens fera que le chargeur d'exécution recherchera les bibliothèques dans /path/to/newglibc
(pour que vous n'ayez pas à définir LD_LIBRARY_PATH
avant de l'exécuter), et le -dynamic-linker
l'option "cuire" le chemin pour corriger ld-linux.so.2
dans l'application.
Si vous ne pouvez pas réassocier le myapp
application (par exemple parce qu'il s'agit d'un binaire tiers), tout n'est pas perdu, mais cela devient plus délicat. Une solution consiste à définir un chroot
approprié environnement pour cela. Une autre possibilité consiste à utiliser rtldi et un éditeur binaire. Mise à jour :ou vous pouvez utiliser patchelf.