Obtenir ld pour choisir la bonne bibliothèque

J'essaie de comstackr un programme prog et de le lier à la bêta 1.0.2 d'OpenSSL, construit à partir de la source et installé dans /usr/local/ssl-1.0.2 . Sur un ancien système utilisant 0.9.8, cela fonctionne sans trop de problèmes. Sur un système plus récent avec 1.0.1 installé, cela nécessite un peu plus de travail. Je me request pourquoi.

1) Sur Ubuntu 10.04, avec OpenSSL 0.9.8:

Voici les étapes que je suis pour comstackr et lier à 1.0.2.

 $ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install $ ldconfig $ ldconfig -p | grep libcrypto 

=> Seuls les files 0.9.8 apparaissent, donc j'ajoute le path vers les files 1.0.2 …

 $ ldconfig /usr/local/ssl-1.0.2/lib $ ldconfig -p | grep libcrypto 

=>

  libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8 libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8 libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8 libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8 libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so 

Et donc je peux comstackr prog

 $ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto $ ldd prog 

=>

  libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000) 

… et il est correctement lié à 1.0.2.

2) Sur Debian Wheezy, avec OpenSSL 1.0.1:

Même étapes, résultat différent.

 $ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install $ ldconfig $ ldconfig -p | grep libcrypto 

=>

  libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0 

De même, j'ajoute le path à 1.0.2 …

 $ ldconfig /usr/local/ssl-1.0.2/lib $ ldconfig -p | grep libcrypto 

=>

  libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so 

Ensuite, j'essaie de comstackr …

 $ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto $ ldd prog 

=>

  libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000) 

Mais ici, il n'est pas lié à 1.0.2. Le path de la bibliothèque à la compilation est correct (spécifié avec -L , gcc échouerait sinon car certaines fonctions utilisées dans prog sont spécifiques à 1.0.2), mais pas au moment de l'exécution.

3) Comment le faire fonctionner sur Wheezy

Avec ou sans exécuter ldconfig /usr/local/ssl-1.0.2/lib :

 $ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto $ ldd prog 

=>

  libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000) 

Sinon, exécutez l' export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib avant d'exécuter gcc .

Ce que j'aimerais savoir

En utilisant LD_DEBUG=libs ./prog comme suggéré par mr.spuratic, j'ai trouvé que les paths étaient recherchés dans /etc/ld.so.cache . J'ai ouvert ce file et trouvé que l'ordre dans lequel .so sont recherchés correspond à la sortie de ldconfig -p .

Donc, la vraie question est:

  • Pourquoi le file 1.0.2 se trouve-t-il au dessus de la list de ldconfig dans 1) mais pas dans 2)? Pure random? Confusion due aux files 1.0.1 et 1.0.2 ayant le même suffixe? ("1.0.0")

Ou, dit différemment,

  • Pourquoi les drapeaux ajoutés dans 3) ne sont-ils pas nécessaires dans 1)?

Il y a trois choses dont vous devez vous occuper lors de la compilation / binding avec un packageage non par défaut:

  • en-têtes (habituellement CFLAGS )
  • path de la bibliothèque à la compilation (généralement LDFLAGS )
  • path de la bibliothèque d' exécution ( rpath via LDFLAGS , LD_RUN_PATH , LD_LIBRARY_PATH ou LD_LIBRARY_PATH )

Vous n'avez pas dit ce qu'est le prog , donc je ne peux pas à quel point sa configuration est correcte (ou si elle utilise autoconf?), J'en ai vu beaucoup qui n'effectuent que les deux premières étapes de manière fiable.

En supposant que vous utilisez la string d'outils GNU (gcc & binutils), vous pouvez probablement voir ce qui se passe en définissant CFLAGS avant la configure (ou possible dans le Makefile directement):

 export CFLAGS="-Wl,-t" 

Cela transmet l'option -t trace à l'éditeur de liens. Vous devrez peut-être append V=1 ou VERBOSE=1 à la command make si les lignes "CC" et "LD" ne sont pas VERBOSE=1 .)

Au moment de l'exécution, vous pouvez voir ce que ld.so essaye en définissant avec soin LD_DEBUG , par exemple

 LD_DEBUG=libs ./myprog 

(ou essayez les valeurs des files ou des symbols pour plus de détails)

Pour spécifier tous les trois parameters correctement au moment de la construction, vous devriez être en mesure de faire:

  • export CFLAGS="-I/usr/local/ssl-1.0.2/include"
  • export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"

puis reconfigurez / recomstackz.

Vous utilisez --openssldir plutôt que le --openssldir plus conventionnel (je recommand ce dernier et aussi en utilisant make install_sw si vous n'avez pas besoin des 1000 pages man et des liens symboliques qu'une installation par défaut vous donne). Cela peut faire partie du problème. Pour une raison ou une autre, les bibliothèques .so que vous montrez sont connues de ld.so et ne possèdent pas de suffixe de version (par exemple, .so.1.0.2 ), une "make install" correcte devrait l'avoir configurée (via le link-shared cible link-shared dans le Makefile principal).

L'option -R request à l'éditeur de liens d'incorporer un message RPATH dans la sortie exécutable de la bibliothèque OpenSSL spécifique, afin qu'il n'ait pas besoin de s'appuyer sur la valeur par défaut fournie par l'éditeur de liens d'exécution ( ld.so ). Vous pouvez modifier les binarys existants avec chrpath place.

Ceci est plus ou less équivalent à l'export de LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib . Vous pouvez en savoir plus sur RPATH et le RUNPATH connexe ici: http://blog.tremily.us/posts/rpath/

En dernier recours, vous pouvez éventuellement build OpenSSL sans "partagé" ou avec "voshared", cela vous donnera des bibliothèques statiques qui n'auront pas ce problème (mais qui peuvent avoir d'autres problèmes, par exemple pour ELF .so, / Problèmes PIE)


Basé sur les détails mis à jour, je crois que le problème est que 1.0.1 et 1.0.2beta à la fois définir le suffixe de version .so (SONAME) à 1.0.0. Sur le premier système avec seulement 0.9.8 cela ne pose aucun problème; sur le second avec 1.0.1 et 1.0.2 tous les deux versionnés en 1.0.0, c'est "first match wins" basé sur la command ld.so.{conf,d} . Souvenez-vous, ld le linker de la compilation est un programme différent de ld.so , et peut avoir un comportement différent (ce qui entraîne généralement des erreurs de symboles ou pire, comme vous l'avez vu).

 $ cd /usr/local/src/openssl/openssl/1.0.2beta1 $ readelf -a libssl.so | grep SONAME 0x0000000e (SONAME) Library soname: [libssl.so.1.0.0] $ cat verchk.c int main(int argc, char *argv[]) { printf("build: %s\n",OPENSSL_VERSION_TEXT); printf("run : %s\n",SSLeay_version(SSLEAY_VERSION)); return 0; } $ gcc -Wall -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \ -Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \ -o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c $ ./verchk build: OpenSSL 1.0.2-beta1 24 Feb 2014 run : OpenSSL 1.0.2-beta1 24 Feb 2014 $ grep SHLIB_M...R= Makefile SHLIB_MAJOR=1 SHLIB_MINOR=0.0 

Le path de la nouvelle lib est-il dans l'un des files de /etc/ld.so.conf.d ? Prochaine course: –

 #ldconfig -v 

pour rebuild le cache. Si vous êtes rapide, vous devriez voir la nouvelle lib dans la longue list qu'elle imprime (ou le diriger vers grep ou less )

Peut-être que le path était déjà dans le premier server, mais pas sur le second?