cher journal,
je me pose quelques questions sur le fonctionnement du linker dynamique sous linux.
Déja je voudrais etre sur de bien comprendre le principe. Alors je repete un peu ce que j'ai deja dit :
De ce que j'ai compris/experimenté :
Cas 1:
Soit un .so contenant une fonction toto() qui appelle tata()
Un executable charge ce .so. A ce moment la le systeme fait sa tambouille au niveau des liens et s'apercoit qu'il ne connait pas tata => relocation error
Question 1 : je vois en gros l'interet du link dynamique (vraiment, de loin et en gros), mais les defauts me semble tellement nombreux qu'en fait, non, je vois pas. Les defauts sont notamment qu'on a aucune verif au moment de la compilation/link de la presence/absence des symboles, et que donc faut faire des tests intensif pour etre sur que sur tous les "codepath" de l'apli qu'il n'y'ait pas de relocation error
Cas 2:
Soit un so avec une fonction toto, tata, toto appelant tata
Soit un exe avec AUSSI une fonction tata, exe chargeant le .so precedent
au chargement du .so, le systeme va voir qu'il connait deja un tata (cui de l'exe) et va donc utiliser ce symbole plutot que cui du so. Donc, notre so, au lieu d'appeler le tata qu'il contient va appeler celui de l'exe.
Question 2: bon la je pense que faire la liste des defauts est trop longue (et aussi evidente), donc meme question : pourquoi pareil tambouille ? Y'a un truc que j'ai pas pigé ?
# plugins
Posté par Rémi . Évalué à 4.
Ensuite forcément ce plugin doit implémenter certaines fonctions, sinon xmms arrivera pas à le charger...
enfin xmms fonctionne peut être pas comme ça hein, c'était juste un exemple.
# Alors
Posté par Ph Husson (site web personnel) . Évalué à 3.
Quand tu dis qu'un executable charge un .so c'est qu'il dépend de lui, ou le charge avec dlopen?
Si c'est la 1° alors y a une vérification au niveau de la compil
Si c'est la 2° ce que tu peux faire c'est déclarer tout les symboles dans un .h mais pas de symbole en trop, et gcc dit que le prototype n'est pas déclaré
Cas2: Pareil:
Un .so qui dépend de lui ou dlopen?
1° effectivement y a un bordel sur quel symbole est utilisé, en meme temps une librairie qui a des noms qui vont pas bien est une mauvaise librairie
si c'est le 2° alors c'est l'appli qui dit quel nom donne pour chaque symbole
moi par exemple j'ai un symbole dans des plugins du doux nom SetProgressBar, que je défini dans mon programme en SetProgressBar_external et ce en plus dans une structure (euh maintenant je suis plus sur que ce soit dans une structure tien...)
# Euh ... moi je ne vois que des avantages :-)
Posté par Victor STINNER (site web personnel) . Évalué à 5.
Après, niveau technique, gcc et son pôte ld font du bon boulot. Déjà, lors de la compilation, gcc vérifie que le symbolique existe dans le .so (ou alors je me trompe). Après, lorsqu'on exécute un programme qui utilise les librairies dynamiques (99% des applications hors de /bin je pense), il suffit de demander au programme ELF quels sont les symboles dont il a besoin. On peut faire ça à la main avec la commande nm.
Les noms (toto, tata) sont juste un artifice de programmeur. Un binaire ne contient plus aucun nom lorsqu'il est exécuté. Et lors du chargement de la librairie dynamique, seuls les symboles demandés sont importés. Là encore je peux me tromper. Mais ça fait juste une correspondance "tel pointeur en mémoire est assigné à telle valeur". Donc tu peux avoir plusieurs toto sans que ça pose de problème (je vais pas entrer dans les détails).
@+ Haypo
[^] # Re: Euh ... moi je ne vois que des avantages :-)
Posté par Ph Husson (site web personnel) . Évalué à 5.
Non c'est bien ca
Les noms (toto, tata) sont juste un artifice de programmeur.
Vive l'époque ou les noms étaient forcés à 7 caractères ou un truc du genre
Un binaire ne contient plus aucun nom lorsqu'il est exécuté.
Je sais pas trop:
Quand tu change de version de librairies les adresses changent
La seule chose à laquelle tu peux te référencer c'est alors le nom
Et lors du chargement de la librairie dynamique, seuls les symboles demandés sont importés
Ouép et tu leur donne le nom que tu veux
Donc tu peux avoir plusieurs toto sans que ça pose de problème (je vais pas entrer dans les détails).
Ca dépend des cas...
En fait y a des librairies qui font exprès de prendre la place d'autres symboles (en vrac: libfaketime, chkinstall, euh bon le reste me vient plus enfin bref l'idée est la)
[^] # Re: Euh ... moi je ne vois que des avantages :-)
Posté par Victor STINNER (site web personnel) . Évalué à 3.
>> Un binaire ne contient plus aucun nom lorsqu'il est exécuté.
> Je sais pas trop:
> Quand tu change de version de librairies les adresses changent
> La seule chose à laquelle tu peux te référencer c'est alors le nom
Oui, je suis allé un peu vite. J'étais dans le rush cette après-midi, mais mon rapport sur les brevets logiciels est imprimé. Ouf.
Je voulais dire, un binaire ("strippé") après avoir été chargé par /lib/ld-linux.so.2 ne contient que des adresses mémoire, pas de symbole. Par contre, une fichier ELF contient la liste des symboles (chaînes de caractères donc) dont il a besoin pour chaque librairie :
Bon, apparement il n'y a de lien entre le nom du symbole et le nom de la librairie.
>> Donc tu peux avoir plusieurs toto sans que ça pose de problème (je vais pas entrer dans les détails).
> Ca dépend des cas...
> En fait y a des librairies qui font exprès de prendre la place d'autres symboles (en vrac: libfaketime, chkinstall, euh bon le reste me vient plus enfin bref l'idée est la)
Ok, autant pour moi. C'est vrai que j'avais déjà vu passer un librairie qui remplaçait les fonctions d'accès aux fichiers/répertoires pour mettre les fichiers ~/.* dans le répertoire ~/etc/*. Elle s'utilisait en préchargeant cette librairie à l'aide de LD_LIBRARY_PATH.
--
Les librairies dynamiques, y'a plein de chose à dire dessus :)
@+ Haypo
[^] # Re: Euh ... moi je ne vois que des avantages :-)
Posté par Ph Husson (site web personnel) . Évalué à 2.
loupé :p
c'est LD_PRELOAD :)=
Bon, apparement il n'y a de lien entre le nom du symbole et le nom de la librairie.
En francais faut deux négations
la on prend dans quel sens?
Y a un lien ou y a pas de lien?
Sinon
quid de prelink dans tout ce beans?
Et pis aussi quelqu'un aurait un ldconfig "lite" (mais avec une api propre pour ajouter lib par lib au cache)
Ca serait pour coder un ldconfig dynamique qui relit pas tout /lib à chaque fois par inotify
[^] # Re: Euh ... moi je ne vois que des avantages :-)
Posté par doublehp (site web personnel) . Évalué à 0.
oui : a la compilation, GCC ne verifie que le prototype des dites fonctions dans les headers divers ... tandis que le linker ira lui verifier la definition de la fonction dans le LD_LIBRARY_PATH ou les -Lmypath
note qu il est possible de linker contre ./tata.so, tandis que l execution prendra tata.so ailleurs ... c est ce qui permet d avoir dans un gros projet le linkage des applicatifs des que les librairies sont compilees, et de faire les installs des applis+libs PLUS TARD.
Dans mon cas, cela engendre parfois des problemes de versioning, quand la version ./ et la version /usr different, mais ordinairement, ce probleme ne devrait pas arriver.
Ceci parce que ld cherche dans les '-L', tandis que le linker de Linux cherche les chemins dans /etc/ld.so.conf (de memoire).
Bref, je trouve ca assez drole de dev une appli qui a a la fois des applicatifs et des libs.
# Inutile
Posté par ckyl . Évalué à 9.
On va faire un petit test:
$ cd /usr/bin
$ objdump -T * 2> /dev/null | grep " printf" | wc
donc avec ce simple test nous voyons que nous avons 930 binaires qui utilisent printf. Maintenant si tu n'as pas de lib dynamique ca veut dire 930 fois le code de printf !
Prend un autre exemple une machine d'université. Chaque étudiant à 20 binaires utilisant printf il y a 500 comptes.... 10 000 copies du même code.
Le gain de place est monstrueux. Un hello world compilé en -static fait 377Ko contre 3Ko pour celui utilisant une bibliothèque partagée. Sur une distrib classique il y a dans les 3000 binaires installés : 1Go rien que pour la libc.
La maintenance est aussi très facile. Si jamais tu as un bug dans la lib png. Tu mets à jour la libpng. Maintenant si tu as pas de lib dynamique
$ ldd * 2> /dev/null | grep png | wc
60 225 3031
Un peu plus lourd non ? À chaque modification de la libpng il faut recompiler et redeployer 60 logiciels.
Et pour finir ca permet de faire des trucs magnifiques. Par exemple je bosse actuellement sur un projet qui à besoin de surcharger quelques fonctions de la libc. Là où ca pourrait être la folie pour que tout le système utilise ma version des fonctions. La bibliothèques dynamiques rendent ca très facile. Suffit de créer un /etc/ld.so.preload et de mettre ta lib dedans et hop tu prends la main sur la libc et voila tout ton système vient de migrer d'un coup. Rien à recompiler....
Tu vois toujours pas d'avantages ? :-)
[^] # Re: Inutile
Posté par grollum . Évalué à 3.
# Confusion link dynamique / appel dynamique
Posté par BiBite . Évalué à 10.
1 - un programme linké statiquement avec une lib
2- un programme linké dynamiquement avec une lib
3 - un programme qui n'a pas linké mais appel une (des) librairies dynamiquement au runtime.
Cas N° 1
Dans le premier cas, le programmeur inclut les headers de la lib qu'il veut utiliser (nom des fonctions + signature donc). Au moment de la compilation, le linker cherche les fonctions qui ne sont pas déjà dans le code link les bouts de codes externes dans un unique exécutable: au final, l'exécutable contient tous les bouts de codes externes auxquelles il fait appel (plus le code de l'éxécutable proprement, bien entendu ^^).
Il peut donc tourner sans que les librairies qui ont servit au moment du link soient présentes sur le système. L'inconvénient est que l'exécutable est plus gros et qu'il ne profite pas des mises à jour des librairies.
Cas N°2
Dans le deuxième cas, tout se passe comme dans le premier cas, sauf qu'on dit au linker de linker dynamiquement. Le linker ne va pas donc pas inclure les bouts de codes externes comme un gros sale, mais va indiquer dans l'exécutable que certaines fonctions ne sont pas présentes et que l'OS devra les chercher parmis les librairies dynamiques à sa disposition avant de lancer l'exécutable. Je précise que cette recherche se fait avant que l'exécutable se lance, donc pas besoin de faire des "tests intensifs" pour savoir si toutes les libs dont le soft a besoin sont là.
Dans ce cas, si le développeur utilise en interne une fonction qui a la même signature, le même nom et le même espace de nommage que le nom d'une fonction externe qu'il utilise également, ça ne passera pas. Mais l'erreur se produira au moment du link, et non pas lorsque l'utilisateur lancera l'exé.
Idem, si le système ne trouve pas la lib, en question, ou que la signature attendue dans la lib diffère, alors le système refusera de lancer l'exécutable nous dira qu'il n'est pas content parcequ'il n'arrive pas à trouver telle ou telle fonction dans la lib machin-truc.
Cas N°3
Enfin, il y a le 3ème cas. Le développeur utilise un appel système pour dire qu'il veut utiliser les fonction "toto" de la librairie "libmachin.so". Une fois compilé, il est impossible de savoir si l'exécutable fait appel à des librairies externes et encore mois de connaître le nom des ces fonctions (Bon, si le mec veut vraiment, il pourra, ne serait-ce qu'en décompilant le soft. Et je pense que c'est plus simple que de faire exécuter tous les chemins possibles du code ^^). C'est ce qui permet notamment de charger des plug'in à la volée, sans fermer/réouvrir le soft.
Si le système trouve la lib et la fonction au moment de l'exécution, alors tout se passe bien. Le programme a alors un pointeur de fonction (que le dév a pu appeler "toto_ext"), et s'il a déjà une fonction "toto", tout se passe bien puisque les deux n'ont pas le même nom dans le programme en question (sinon, ça n'aurait pas compilé).
Sinon, soit le dév. a prévu le coup et tout se passe bien (on peut imaginer que le soft exprime sont mécontentement et continue avec une solution de secours ou alors se ferme). Soit le dév. a fait ça de manière un peu sale et il va manipuler un pointeur NULL, ce qui devrait aboutir tôt ou tard à un seg fault mérité :)
PS: j'avoue que ce que je viens de raconter est basé sur mon expérience avec Windows et ses DLL, mais je suppose que c'est la même chose ou presque sous Linux.
[^] # Re: Confusion link dynamique / appel dynamique
Posté par imalip . Évalué à 3.
J'ajoute que ce comportement a justement ca d'utile, on ne va pas se prendre un mechant coup de "unresolved symbol" parce que la lib machinchose n'est pas present. Au premier abord ca peut parraitre bizarre, mais ca permet de faire de la gestion conditionelle.
Par exemple, on peut vouloir proposer d'utiliser au choix MySQL, PostgreSQL, SQLite, Oracle, ...
Plutot que de linker dynamiquement (methode 2), on essaie de trouver la lib depuis le code, et si elle n'est pas la, tant pis, on passe, on n'essaie pas d'appeler. Ca permet de ne pas avoir besoin que toutes les libs, y compris celles inutiles, soient presentes a l'execution. Tres agreable avec un systeme de packages avec gestion des dependances pour eviter de se retrouver avec une demi-douzaine de libs installees dont on se fout completement.
Par contre derriere il faut bien gerer sont truc proprement, sinon ca explose de partout.
# blah
Posté par Troy McClure (site web personnel) . Évalué à 5.
[^] # Re: blah
Posté par grollum . Évalué à 1.
(on sens vachement que le linker dynamique marche bien là ...)
# En voila une drôle de question !
Posté par Obsidian . Évalué à 2.
Comme dit plus haut, l'idée générale est de ne pas à avoir à intégrer n fois le même code dans toutes les applications. Non seulement il y a des milliers de binaires en service sur un système, mais ils dépendent tous de routines de plus bas niveau. Si dix applications s'appuient sur dix bibliothèques qui elles-mêmes font appel à dix appels systèmes, tu te retrouves avec 1000 fois le même code. Les bibliothèques dynamiques ne sont pas seulement nécessaires du fait de la multiplication des binaires, mais surtout à cause du caractère exponentiel que présente une édition de liens purement statique, celui-ci étant dù aux dépendances en cascade.
Non. Avec gcc en tout cas (et donc ld, par conséquent), il faut que tu spécifies à la compilation les bibliothèques impliquées avec l'option "-l", et éventuellement les répertoires dans lesquels elles se trouvent avec "-L". Toutefois, pour rendre la compilation facile, le compilateur peut faire ce travail pour toi envers les bibliothèques standard (stdio et compagnie). Tu peux inhiber ce comportement à l'aide des options « -nostdlib » et « -nodefaultlibs ».
$ man gcc
Non plus, car une fois résolus, les symboles disparaissent (donc en interne) car ils deviennent inutiles, mais surtout ton problème n'a absolument rien à voir avec le caractère dynamique de la gestion des bibliothèques :Si tu compiles un programmes avec une suite de « *.o » purement statiques, tu devras faire face au même problème si deux bibliothèques indépendantes ont décidé d'utiliser le même nom de fonction.
La plupart du temps, le problème ne se pose pas car les noms de symboles ne sont pas limités en longueur (ou en tout cas en tolère un très grand nombre), et les développeurs choisissent en général des noms suffisament explicites pour écarter toute ambigüité. Cependant, dans certains langages tel que le C++, on peut avoir des doubles-emplois. Pour éviter cela, soit les méthodes sont encapsulées dans une classe, dans le cas d'un langage orienté objet, soit les différentes entités sont déclarées au sein d'un namespace ou espace de nommage, que l'on peut décider d'utiliser implicitement au début d'un listing, soit explicitement en utilisant le nom du namespace comme préfixe au symbole que l'on souhaite invoquer.
Mais là encore, c'est totalement indépendant des systèmes de liaison dynamique.
[^] # Re: En voila une drôle de question !
Posté par Dugland Bob . Évalué à 4.
Pour avoir bossé en intégration/déploiement (donc côté pas dev), j'ai compris que les utilisateurs (ceux qui compte donc) ont exactement l'avis inverse.
Marre de devoir télécharger 30 libs pour installer un truc marre de ne pas savoir précisément quel périmètre va régresser lors d'une montée de version, marre de devoir tester sans cesse plus de truc après un déploiement, parce que monter de version la commande ls oblige à changer de noyeau, marre des incompatibilités entre versions etc.
J'ai comme l'impression que la toute puissance du développeur est de plus en plus néfaste pour l'utilisateur. Je me suis bien trouvé con le jour où j'ai dû expliquer l'intérêt de corba à un utilisateur : il n'en a rien à foutre des avantages de l'intégration multi-langages, de la visionunifiée des objets, et comme la configuration des ORB n'est pas unifiée, ben lui il a que des inconvénients.
[^] # Re: En voila une drôle de question !
Posté par Obsidian . Évalué à 3.
Ca, en revanche, c'est vrai. D'ailleurs le seul programme que j'ai écrit pour Windows se passait complètement de bibliothèques. Cela ne veut pas dire pour autant qu'il était entièrement statique, mais qu'il faisait appel à des bibliothèques réputées être toutes fournies par le système. Moralité, un petit exécutable de 164Ko qui pouvait s'exécuter partout sans installation. Il a fait fureur pendant facilement deux ans sur logithèque point fr.
Ceci dit, c'est à ça que servent les installeurs style InstallShield sur Windows ou *.rpm/*.deb sous Gnu/Linux, parce que non seulement ils gèrent les bibliothèques associées, mais aussi tous les fichiers connexes (conf principalement), les dépendances, les mises à jour, et la redoutable base de registre sous Windows.
Faire le procès des bibliothèques partagées, c'est déplacer le problème. Aucun utilisateur ne devrait se trouver avec un *.exe seul sans ses dépendances, à moins de l'avoir piraté (dans ce cas, aucune vergogne), soit parce que le système n'est pas assez souple pour permettre un déploiement facile.
Ca c'est vrai aussi, mais je trouve que là encore le problème est ailleurs. La multiplication des langages de haut niveau et des couches d'abstractions sont autant de causes potentielles de panne et d'incompatibilité, et ce qui ne profite qu'au programmeur au moment du développement se paye au quotidien par une consommation de ressources excessives (le processeur doit traverser toutes les couches au moindre appel).
Ceci dit, là encore, les bibliothèques partagées sont les amies des utilisateurs comme des développeurs. On faisait déjà le procès des grands éditeurs dans les années 90 lorsque l'on a vu les systèmes d'expoitation et les logiciels les plus populaires occuper de plus en plus de place sur le disque (un ami m'a envoyé Windows 1.0 par mail :-) ). Maintenant imagine un peu que tous les logiciels soient statiques : L'équivalent d'un système d'exploitation entier dans chacune de tes applications. Un disque dur de 15To ne suffirait pas, et accessoirement ton OS ne servirait plus à rien. Avec des libs partagées, le code de ladite bibliothèque n'occupe qu'une seule fois sa place non seulement sur le disque, mais également en mémoire (mapping).
En plus, le code partagé se trouve même là où tu ne l'attends pas : Quand une application ouvre une fenêtre, c'est toujours la même et cela te paraît normal : C'est Windows (ou GTK/Qt sous Linux) qui s'occupe de la construire, pas l'application.
[^] # Re: En voila une drôle de question !
Posté par Mildred (site web personnel) . Évalué à 1.
Je ne comprends toujours pas pourquoi on ne peut pas faire un système de paquets générique pour toutes les distributions qui gèrerait les dépendances.
[^] # Re: En voila une drôle de question !
Posté par Obsidian . Évalué à 2.
Concurrence (ou compétition, à la limite).
C'est pour les mêmes raisons qu'il existe Gnome et KDE en parallèle. On peut s'estimer heureux qu'il n'en existe que deux, mais en un sens, cela respecte quand même le droit à l'alternative.
# Library or not bibliothèque ?
Posté par kd . Évalué à 4.
Le mot anglais library sont par exemple les fichiers .so dont on parle ici. Il se traduit donc en français par bibliothèque. Donc par pitié, dites soit library, soit bibliothèque, mais pas librairie !
[^] # Re: Library or not bibliothèque ?
Posté par Ph Husson (site web personnel) . Évalué à 0.
Or informatique, librairie ou bibliothèque c'est quoi la différence?
Après pourquoi ne pas dire librairie dans ce cas la?
[^] # Re: Library or not bibliothèque ?
Posté par Obsidian . Évalué à 3.
?
s/Or/Hors/ ?
Une librairie c'est une boutique qui vend notament des livres, des revues, des ouvrages en tout genres et qui peut accessoirement faire office de débit de tabac.
Une bibliothèque c'est avant tout une collection d'ouvrages. Il se trouve qu'en français, le terme intègre le préfixe biblio qui signifie « livre », et que l'on décline en ludothèque, vidéothèque, logithèque ou autre. C'est plus rare en anglais.
Ici, une bibliothèque est une collection de fonctions, et éventuellement de ressources en tous genres (icônes, objets divers, etc.) réunies dans le même fichier, et ce soit sous forme d'objets partagés (*.so), soit sous forme d'objets statiques (*.o) embarqués dans un fichier d'archive (*.a).
Parce que c'est un contresens ! C'est un piège facile mais que l'on rencontre de plus en plus souvent, simplement parce que la plupart des gens ne maîtrisent pas leur propre langue, et qui n'a par conséquent aucune raison d'être « légalisé ».
Le pire exemple est encore le verbe « supporter » : C'est un terme violent en français qui se traduit par to stand en anglais, et comme ces notions existent dans les deux langues, cela induit des ambigüités. Et en plus, c'est vraiment très laid et désagréable à lire. Donc, s'il y a des gens qui se demandent comment traduire ce terme en français :
S'il s'agit d'apporter son appui à une cause ou une personne, on dit « soutenir ».
S'il s'agit de matériel informatique ou d'une configuration particulière, on peut utiliser « prendre en charge » ou (mieux) « reconnaître ».
S'il s'agit d'aide aux utilisateurs, on parlera d'« assistance » plutôt que de support technique ou autre.
[^] # Re: Library or not bibliothèque ?
Posté par Sylvain Sauvage . Évalué à 3.
-thèque veut donc dire, soit, pour un objet, étagère, soit, dans un sens plus global, collection (tout est posé au même endroit).
Voilà. La semaine prochaine, nous parlerons de l'apothicaire et de ses étagères en hauteur...
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.