GNU/Linux >> Tutoriels Linux >  >> Linux

Plusieurs bibliothèques glibc sur un seul hôte

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.


Linux
  1. Héberger plusieurs sites Web sur des conteneurs Docker

  2. Comment diviser un seul fichier en plusieurs fichiers en fonction des lignes

  3. Linux - Un seul utilisateur peut-il avoir plusieurs fichiers Crontab ?

  4. Configurer plusieurs sites WordPress sur un seul VPS

  5. scp un seul fichier vers plusieurs emplacements

Comment héberger plusieurs sites dans une seule installation Wordpress sur Ubuntu 14.04

Comment héberger plusieurs sites dans une seule installation Wordpress sur CentOS 7

Comment exécuter une commande unique sur plusieurs systèmes distants à la fois

Comment exécuter plusieurs commandes Linux en une seule commande

Héberger plusieurs sites Web sur un seul serveur avec Apache sur Ubuntu 18.04

Comment joindre plusieurs pages PDF à une seule page