GCC HOWTO pour Linux par Daniel Barlow v1.17, 28 fevrier 1996 (Adaptation francaise par Eric Dumas , 8 Avril 1996). Ce document presente la maniere de configurer le compilateur GNU C et les bibliotheques de developpement sous Linux. Il donne un apercu de la compilation, de l'edition de liens, de l'execution et du debogage de programmes sous Linux. Bon nombre de passages de ce docu- ment sont empruntes a la FAQ GCC redigee par Mitch D'Souza's et au HowTo ELF. Ceci est la premiere version publique (en depit du numero de version : en fait, ca vient de RCS). N'hesitez pas a me joindre pour toute remarque. 11.. PPrreelliimmiinnaaiirreess 11..11.. EELLFF eett aa..oouutt Le developpement de Linux est actuellement dans une phase de transition. En resume, il existe deux formats de binaires que Linux reconnait et execute, et cela depend de la maniere dont votre systeme est configure : vous pouvez avoir les deux, l'un ou l'autre. En lisant ce document, vous pourrez savoir quels binaires votre systeme est capable de gerer. Comment le savoir ? Utilisez la commande file (par exemple, file /bin/bash). Pour un programme ELF, cette commande va vous repondre quelque chose dans lequel se trouve le mot ELF. Dans le cas d'un programme en a.out, il vous indiquera quelque chose comme Linux/i386. Les differences entre ELF et a.out sont detaillees plus tard dans ce document. ELF est le nouveau format et il est considere comme etant meilleur. 11..22.. DDuu ccoottee dduu ccooppyyrriigghhtt Le copyright et autres informations legales peuvent etre trouves a la _f_i_n de ce document, avec les avertissements conventionnels concernant la maniere de poser des questions sur Usenet pour eviter d'avoir a reveler votre ignorance du langage C en annoncant des bogues qui n'en sont pas, etc. 11..33.. TTyyppooggrraapphhiiee Si vous lisez ce document au format Postscript, dvi, ou HTML, vous pouvez voir quelques difference entre les styles d'ecriture alors que les gens qui consultent ce document au format texte pur ne verront aucune difference. En particulier, les noms de fichiers, le nom des commandes, les messages donnes par les programmes et les codes sources seront ecrits avec le style suivant : style d'ecriture, alors que les noms de variables entre autres choses seront en _i_t_a_l_i_q_u_e. Vous aurez egalement un index. Avec les formats dvi ou postscript, les chiffres dans l'index correspondent au numeros de paragraphes. Au format HTML, il s'agit d'une numerotation sequentielle pour que vous puissiez cliquer dessus. Avec le format texte, ce ne sont que des nombres. Il vous est donc conseille de prendre un autre format que le format texte ! L'interpreteur de commande (_s_h_e_l_l) utilise dans les exemples sera la Bourne shell (plutot que le C-Shell). Les utilisateurs du C-Shell utiliseront plutot : % setenv soif JD la ou j'ai ecrit $ soif=JD; export soif Si l'invite (_p_r_o_m_p_t dans la langue de Shakespeare) est # plutot que $, la commande ne fonctionnera que si elle est executee au nom de Root. Bien sur, je decline toute responsabilite de ce qui peut se produire sur votre systeme lors de l'execution de ces exemples. Bonne chance :-) 22.. OOuu rreeccuuppeerreerr ddee llaa ddooccuummeennttaattiioonn eett lleess pprrooggrraammmmeess ?? 22..11.. CCee ddooccuummeenntt Ce document fait partie de la serie des HOWTO pour Linux, et il est donc disponible ainsi que ces collegues dans les repertoires HowTo pour Linux, comme sur . La version HTML peut egalement etre consultee sur . Note du traducteur : vous pouvez obtenir tous les HowTos en langue anglaise et francaise sur ftp.ibp.fr:/pub/linux. Les versions francaises se trouvent dans le repertoire /pub/linux/french/HOWTO. 22..22.. AAuuttrreess ddooccuummeennttaattiioonn La documentation officielle pour gcc se trouve dans les sources de la distribution (voir plus bas) sous la forme de fichiers texinfo et de fichiers .info. Si vous possedez une connexion rapide, un CD-ROM ou une certaine patience, vous pouvez desarchiver la documentation et l'installer dans le repertoire /usr/info. Sinon, vous pouvez toujours les trouver sur tsx-11 , mais ce n'est pas necessairement toujours la derniere version. Il existe deux sources de documentation pour la libc. La libc GNU est fournie avec des fichiers info qui decrivent assez precisement la libc Linux sauf pour la partie des entrees-sorties. Vous pouvez egalement trouver sur sunsite des documents ecrits pour Linux ainsi que la description de certaines appels systemes (section 2) et certaines fonctions de la libc (section 3). Note du traducteur : un bemol concernant cette partie... La libc Linux n'est pas GNU et tend a etre relativement differente sur certains points. 22..33.. GGCCCC Il existe deux types de reponses (a) La distribution officielle de GCC pour Linux peut toujours etre recuperee sous la forme de binaires (deja compilee) sur . Vous pouvez la trouver sur le miroir francais . A l'heure ou j'ecris ces lignes, la derniere version est gcc 2.7.2 (gcc-2.7.2.bin.tar.gz). (b) La derniere distribution des sources de GCC de la _F_r_e_e _S_o_f_t_w_a_r_e _F_o_u_n_d_a_t_i_o_n peut-etre recuperee sur prep.ai.mit.edu ou ftp.ibp.fr . Ce n'est pas toujours la meme version que celle presentee ci-dessus. Les mainteneurs de GCC pour Linux ont rendu la compilation de GCC plus facile grace a l'utilisation du script configure qui effectue la configuration d'une maniere automatique. Regardez dans tsx-11 ou ftp.ibp.fr pour recuperer d'eventuels patches. Quelle que soit la complexite de votre programme, vous aurez egalement besoin de la _l_i_b_c. 22..44.. LLeess ffiicchhiieerrss dd''eenn--tteettee eett llaa bbiibblliiootthheeqquuee CC Ce que vous allez trouver dans ce paragraphe depend +o de votre systeme (ELF ou a.out) ; +o du type de binaire que vous desirez generer. Si vous etes en train de mettre a jour votre libc 4 en libc 5, vous devriez consulter le ELF HowTo qui se trouve au meme endroit que ce document. Les libc sont disponibles sur tsx-11 ou ftp.ibp.fr . Voici une description des fichiers situes dans ce repertoire : lliibbcc--55..22..1188..bbiinn..ttaarr..ggzz --- bibliotheques dynamiques et statiques ELF plus les fichiers d'en-tete pour la bibliotheque C et la bibliotheque mathematique. lliibbcc--55..22..1188..ttaarr..ggzz --- Code source pour la bibliotheque ci-dessus. Vous aurez egalement besoin du paquetage .bin. pour avoir les fichiers d'en-tete. Si vous hesitez entre compiler la bibliotheque C vous-meme et utiliser les binaires, la bonne reponse est dans la majorite des cas est d'utiliser les binaires. Toutefois, si vous desirer utiliser NYS (NdT : NYS != NIS) ou bien les mots de passe _s_h_a_d_o_w, vous devrez recompiler la libc par vous-meme. lliibbcc--44..77..55..bbiinn..ttaarr..ggzz --- bibliotheques dynamiques et statiques a.out pour la version 4.7.5 de la libc. Cette bibliotheque a ete concue pour pouvoir coexister avec le paquetage de la libc 5 decrit ci-dessus, mais c'est uniquement necessaire si vous desirez utiliser ou developper des programmes au format a.out. 22..55.. OOuuttiillss aassssoocciieess ((aass,, lldd,, aarr,, ssttrriinnggss,, eettcc..)) Ces outils se trouvent comme les bibliotheques dans le repertoire tsx-11 , et ftp.ibp.fr . La version actuelle est binutils-2.6.0.2.bin.tar.gz. Il est utile de remarquer que ces outils ne sont disponibles qu'au format ELF, que la libc actuelle est ELF et que la libc a.out ne pose pas de probleme lorsqu'elle est utilisee avec la libc ELF. Le developpement de la libc est relativement rapide et a moins que n'ayez de bonnes raisons pour utiliser le format a.out, vous etes encourages a suivre le mouvement. 33.. IInnssttaallllaattiioonn eett ccoonnffiigguurraattiioonn ddee GGCCCC 33..11.. LLeess vveerrssiioonnss ddee GGCCCC Vous pouvez savoir quelle est la version de GCC que vous possedez en tapant gcc -v lors de l'invite. C'est egalement une bonne technique pour savoir si votre configuration est ELF ou a.out. Sur mon systeme, cela donne ceci : $ gcc -v Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.7.2/specs gcc version 2.7.2 Les mots-clefs a remarquer +o i486. Cela vous indique que la version de gcc que vous utilisez a ete compilee pour etre utilisee sur un processeur 486 --- mais vous pouvez avoir un autre processeur comme un 386 ou un Pentium (586). Tous ces processeurs peuvent executer le code compile avec n'importe quel processeur. La seule difference reside dans le fait que le code 486 rajoute un peu de code a certains endroits pour aller plus vite sur un 486. Cela n'a pas d'effet nefaste cote performance sur un 386 mais cela rend les executables un peu plus importants. +o zorglub. Ce n'est pas reellement important, et il s'agit generalement d'un commentaire (comme slackware or debian) ou meme, cela peut-etre vide (lorsque vous avez comme nom de repertoire i486-linux). Si vous construisez votre propre gcc, vous pouvez fixer ce parametre selon vos desirs, comme je l'ai fait. :-) +o linux. Cela peut etre a la place linuxelf ou linuxaout et en fait, la signification varie en fonction de la version que vous possedez. +o linux signifie ELF si la version est 2.7.0 ou superieure, sinon, c'est du a.out. +o linuxaout signifie a.out. Cela a ete introduit comme cible lorsque le format des binaires a change de a.out vers ELF dans LLiinnuuxx. Normalement, vous ne verrez plus de linuxaout avec une version de gcc superieure a 2.7.0. +o linuxelf est depasse. Il s'agit generalement de gcc version 2.6.3 configure pour generer des executables ELF. Notez que gcc 2.6.3 est connu pour generer de nombreuses erreurs lorsqu'il produit du code ELF --- une mise a jour est tres fortement recommandee. +o 2.7.2 est le numero de la version de GCC. Donc, en resume, nous possedons gcc 2.7.2 qui genere du code ELF. _Q_u_e_l_l_e _s_u_r_p_r_i_s_e (NdT: En francais dans le texte) ! 33..22.. AA qquueell eennddrrooiitt ss''iinnssttaallllee GGCCCC ?? Si vous avez installe gcc sans regarder, ou bien si vous l'avez eu a partir d'une distribution, vous pouvez avoir envie de savoir ou il se trouve dans votre arborescence. Les mots clefs permettant cela sont +o /usr/lib/gcc-lib/_m_a_c_h_i_n_e_-_c_i_b_l_e/_v_e_r_s_i_o_n/ (et ses sous-repertoires) est generalement l'endroit ou se trouve le plus souvent le compilateur. Ceci inclut les executables qui realisent la compilation ainsi que certaines bibliotheques et quelques fichiers d'en-tete. +o /usr/bin/gcc est le lanceur du compilateur --- c'est en fait le programme que vous lancez. Il peut etre utilise avec plusieurs versions de gcc lorsque vous possedez plusieurs repertoires installes (voir plus bas). Pour trouver la version par defaut utilisee, lancez gcc -v. Pour forcer l'utilisation d'une autre version, lancez gcc -V _v_e_r_s_i_o_n. Par exemple, # gcc -v Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.7.2/specs gcc version 2.7.2 # gcc -V 2.6.3 -v Reading specs from /usr/lib/gcc-lib/i486-zorglub-linux/2.6.3/specs gcc driver version 2.7.2 executing gcc version 2.6.3 +o /usr/_m_a_c_h_i_n_e_-_c_i_b_l_e/(bin|lib|include)/. Si vous avez installe plusieurs cibles possibles (par exemple a.out et elf, ou bien un compilateur croise, les bibliotheques, les binutils (as, ld, etc.) et les fichiers d'en-tete pour les cibles differente de celle par defaut peuvent etre trouves a cet endroit. Meme si vous n'avez qu'une seule version de gcc installee, vous devriez toutefois trouver a cet endroit un certain nombre de fichiers. Si ce n'est pas la cas, regardez dans /usr/(bin|lib|include). +o /lib/, /usr/lib et autres sont les repertoires pour les bibliotheques pour le systeme initial. Vous aurez egalement besoin du programme /lib/cpp pour un grand nombre d'applications (X l'utilise beaucoup) --- soit vous le copiez a partir de /usr/lib/gcc-lib/_m_a_c_h_i_n_e_-_c_i_b_l_e/_v_e_r_s_i_o_n/, soit vous faites pointer un lien symbolique dessus. 33..33.. OOuu ssee ttrroouuvveenntt lleess ffiicchhiieerrss dd''eenn--tteettee ?? Si l'on excepte les fichier fichiers d'en-tete que vous installez dans le repertoire /usr/local/include, il y a en fait trois types de fichiers d'en-tete : +o La grande majorite des fichiers situes dans le repertoire /usr/include/ et dans ses sous-repertoires proviennent du paquetage de la libc dont s'occupe H.J. Lu. Je dis bien la "grande majorite" car vous pouvez avoir egalement certains fichiers provenant d'autres sources (par exemple des bibliotheques curses et dbm), ceci est d'autant plus vrai si vous possedez une distribution de la libc recente (ou les bibliotheques curses et dbm ne sont pas integrees). +o Les repertoires /usr/include/linux et /usr/include/asm (pour les fichiers et ) doivent etre des liens symboliques vers les repertoires linux/include/linux et linux/include/asm situes dans les sources du noyau. Vous devrez installer ces sources si vous desirez pouvoir developper : ces sources ne sont pas utilises uniquement pour compiler le noyau. Il est probable que vous ayez besoin de lancer la commande suivante make config dans le repertoire des sources du noyau apres les avoir installes. Beaucoup de fichiers ont besoin du fichier d'en-tete qui n'existe pas sans cette commande. Il est a noter que dans certaines versions du noyau, le repertoire asm est en fait un lien symbolique qui n'est cree qu'avec l'execution de make config. Donc, si vous installez les sources du noyau dans le repertoire /usr/src/linux, il suffit de faire : $ cd /usr/src/linux $ su # make config [repondez aux questions. A moins que vous ne recompiliez votre noyau, les reponses importent peu] # cd /usr/include # ln -s ../src/linux/include/linux . # ln -s ../src/linux/include/asm . +o Les fichiers tels que , , , et changent en fonction de la version du compilateur, et peuvent etre trouves dans le repertoire /usr/lib/gcc-lib/i486-box-linux/2.7.2/include/ pour la version 2.7.2. 33..44.. CCoonnssttrruuiirree uunn ccoommppiillaatteeuurr ccrrooiissee 33..44..11.. LLiinnuuxx ccoommmmee ppllaattee--ffoorrmmee ddee ddeessttiinnaattiioonn Nous supposons que vous avez recupere les sources de gcc, et normalement, il vous suffit de suivre les instructions donnees dans le fichier INSTALL situe dans les sources de gcc. Ensuite, il suffit de lancer configure --target=i486-linux --host=XXX sur une plateforme XXX, puit un make devrait compiler gcc correctement. Il est a noter que vous aurez besoin des fichiers d'en-tete de Linux, ainsi que les sources de l'assembleur et du l'editeur de liens croises que vous pouvez trouver sur ou . 33..44..22.. LLiinnuuxx ccoommmmee ppllaattee--ffoorrmmee oorriiggiinnee eett MMSSDDOOSS ccoommmmee ddeessttiinnaattiioonn Arggg. Apparemment, cela est possible en utilisant le paquetage " emx " ou l'extension " go ". Regardez pour plus d'informations. Je n'ai pas teste cela et je ne pense pas le faire ! 44.. PPoorrttaaggee eett ccoommppiillaattiioonn 44..11.. SSyymmbboolleess ddeeffiinniiss aauuttoommaattiiqquueemmeenntt Vous pouvez trouver quels symboles votre version de gcc definit automatiquement en le lancant avec l'option -v. Par exemple cela donne ca chez moi : $ echo 'main(){printf("Bonjour !\n");}' | gcc -E -v - Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs gcc version 2.7.2 /usr/lib/gcc-lib/i486-box-linux/2.7.2/cpp -lang-c -v -undef -D__GNUC__=2 -D__GNUC_MINOR__=7 -D__ELF__ -Dunix -Di386 -Dlinux -D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__i386 -D__linux -Asystem(unix) -Asystem(posix) -Acpu(i386) -Amachine(i386) -D__i486__ - Si vous ecrivez du code qui utilise des specificites Linux, il est souhaitable d'implementer le code non portable de la maniere suivante #ifdef __linux__ /* ... code linux ... */ #endif /* linux */ Utilisez __linux__ pour cela, et _p_a_s linux. Bien que cette macro soit definie, ce n'est pas une specification POSIX. 44..22.. OOppttiioonnss ddee ccoommppiillaattiioonn La documentation des options de compilation se trouve dans les pages _i_n_f_o de gcc (sous Emacs, utilisez C-h i puis selectionnez l'option `gcc'). Votre distribution peut ne pas avoir installe la documentation ou bien vous pouvez en avoir une ancienne. Dans ce cas, la meilleure chose a faire est de recuperer les sources de gcc depuis ou l'un des ses nombreux miroirs dont . La page de manuel gcc (gcc.1) est en principe, completement depassee. Cela vous met en garde si vous desirez la consulter. 44..22..11.. OOppttiioonnss ddee ccoommppiillaattiioonn gcc peut realiser un certain nombre d'optimisations sur le code genere en ajoutant l'option -O_n a la ligne de commandes, ou _n est un chiffre. La valeur de _n, et son effet exact, depend de la version de gcc, mais s'echelonne normalement entre 0 (aucune optimisation) et 2 (un certain nombre) ou 3 (toutes les optimisations possibles). En interne, gcc interprete les options telles que -f et -m. Vous pouvez voir exactement ce qu'effectue le niveau specifie dans l'option -O en lancant gcc avec l'option -v et l'option (non documentee) -Q. Par exemple, l'option -O2, effectue les operations suivantes sur ma machine : enabled: -fdefer-pop -fcse-follow-jumps -fcse-skip-blocks -fexpensive-optimizations -fthread-jumps -fpeephole -fforce-mem -ffunction-cse -finline -fcaller-saves -fpcc-struct-return -frerun-cse-after-loop -fcommon -fgnu-linker -m80387 -mhard-float -mno-soft-float -mno-386 -m486 -mieee-fp -mfp-ret-in-387 Utiliser un niveau d'optimisation superieur a celui que le compilateur supporte (par exemple -O6) aura le meme effet qu'utiliser le plus haut niveau gere. Distribuer du code ou la compilation est configuree de cette maniere est une tres mauvaise idee -- si d'autres optimisations sont incorporees dans de versions futures, vous (ou d'autres utilisateurs) pouvez vous apercevoir que cela ne compile plus, ou bien que le code genere ne fait pas les actions desirees. Les utilisateurs de gcc 2.7.0 a 2.7.2 devraient noter qu'il y a un bogue dans l'option -O2. Plus precisement, la _s_t_r_e_n_g_t_h _r_e_d_u_c_t_i_o_n ne fonctionne pas. Un patch a ete implemente pour resoudre ce probleme, mais vous devez alors recompiler gcc. Sinon, vous devrez toujours compiler avec l'option -fno-strength-reduce. 44..22..11..11.. SSppeecciiffiiccaattiioonn dduu pprroocceesssseeuurr Il existe d'autres options -m qui ne sont pas positionnees lors de l'utilisation de -O mais qui sont neanmoins utiles dans certains cas. C'est le cas pour les options -m386 et -m486, qui indiquent a gcc de generer un code plus ou moins optimise pour l'un ou l'autre type de processeur. Le code continuera a fonctionner sur les deux processeurs. Bien que le code pour 486 soit plus important, il ne ralentit pas l'execution du programme sur 386. Il n'existe pas actuellement de -mpentium ou -m586. Linus a suggere l'utilisation des options -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2, pour exploiter les optimisations du 486 tout en perdant de la place due aux problemes d'alignements (dont le Pentium n'a que faire). Michael Meissner (de Cygnus) nous dit : " Mon avis est que l'option -mno-strength-reduce permet d'obtenir un code plus rapide sur un x86 (nota : je ne parle pas du bogue _s_t_r_e_n_g_t_h _r_e_d_u_c_t_i_o_n, qui est un autre probleme). Cela s'explique en raison du peu de registres dont disposent ces processeurs (et la methode de GCC qui consiste a grouper les registres dans l'ordre inverse au lieu d'utiliser d'autres registres n'arrange rien). La _s_t_r_e_n_g_t_h _r_e_d_u_c_t_i_o_n consiste en fait a rajouter des registres pour remplacer les multiplications par des additions. Je suspecte egalement -fcaller-saves de ne pas arranger la situation. " Une autre idee est que -fomit-frame-pointer n'est pas obli- gatoirement une bonne idee. D'un cote, cela peut signifier qu'un autre registre est disponible pour une allocation. D'un autre cote, vue la maniere dont les processeurs x86 codent leur jeu d'instruction, cela peut signifier que la pile des adresses relatives prend plus de place que les adresses de fenetres relatives, ce qui signifie en clair que moins de cache est disponible pour l'execution du processus. Il faut preciser que l'option -fomit-frame-pointer, signifie que le compilateur doit constamment ajuster le pointeur de pile apres les appels, alors qu'avec une fenetre, il peut laisser plusieurs appels dans la pile. Le mot final sur le sujet provient de Linus : Remarquez que si vous voulez des performances maximales, ne me croyez pas : testez ! Il existe tellement d'options de gcc, et il est possible que cela ne soit une reelle optimi- sation que pour vous. 44..22..22.. IInntteerrnnaall ccoommppiilleerr eerrrroorr:: cccc11 ggoott ffaattaall ssiiggnnaall 1111 Signal 11 correspond au signal SIGSEGV, ou bien _s_e_g_m_e_n_t_a_t_i_o_n _v_i_o_l_a_t_i_o_n. Normalement, cela signifie que le programme s'est melange les pointeurs et a essaye d'ecrire la ou il n'en a pas le droit. Donc, cela pourrait etre un bug de gcc. Toutefois, gcc est un logiciel assez teste et assez remarquable de ce cote. Il utilise un grand nombre de structures de donnees complexes, et un nombre impressionnant de pointeurs. En resume, c'est le plus pointilleux des testeurs de memoire existants. Si vous _n_'_a_r_r_i_v_e_z _p_a_s _a _r_e_p_r_o_d_u_i_r_e _l_e _b_o_g_u_e --- si cela ne s'arrete pas au meme endroit lorsque vous retentez la compilation --- c'est plutot un probleme avec votre machine (processeur, memoire, carte mere ou bien cache). NN''aannnnoonncceezz ppaass la decouverte d'un nouveau bogue si votre ordinateur traverse tous les tests du BIOS, ou s'il fonctionne correctement sous Windows ou autre : ces tests ne valent rien. Il en va de meme si le noyau s'arrete lors du `make zImage' ! `make zImage' doit compiler plus de 200 fichiers, et il en faut bien moins pour arriver a faire echouer une compilation. Si vous arrivez a reproduire le bogue et (mieux encore) a ecrire un petit programme qui permet de mettre en evidence cette erreur, alors vous pouvez envoyer le code soit a la FSF, soit dans la liste linux- gcc. Consultez la documentation de gcc pour plus de details concernant les informations necessaires. 44..33.. PPoorrttaabbiilliittee Cette phrase a ete dite un jour : si quelque chose n'a pas ete porte vers Linux alors ce n'est pas important de l'avoir :-). Plus serieusement, en general seules quelques modifications mineures sont necessaires car Linux repond a 100% aux specifications POSIX. Il est generalement sympathique d'envoyer a l'auteur du programme les modifications effectuees pour que le programme fonctionne sur Linux, pour que lors d'une future version, un `make' suffise pour generer l'executable. 44..33..11.. <>) Specificites BSD (notamment bsd_ioctl, daemon et Vous pouvez compiler votre programme avec l'option -I/usr/include/bsd et faire l'edition de liens avec -lbsd (en ajoutant -I/usr/include/bsd a la ligne CFLAGS et -lbsd a la ligne LDFLAGS dans votre fichier Makefile). Il est egalement necessaire de ne ppaass ajouter -D__USE_BSD_SIGNAL si vous voulez que les signaux BSD fonctionnent car vous les avez inclus automatiquement avec la ligne -I/usr/include/bsd et en incluant le fichier d'en-tete . 44..33..22.. SSiiggnnaauuxx _m_a_n_q_u_a_n_t_s ((SSIIGGBBUUSS, SIGEMT, SIGIOT, SIGTRAP, SIGSYS, etc.) Linux respecte les specifications POSIX. Ces signaux n'en font pas partie (cf. ISO/IEC 9945-1:1990 - IEEE Std 1003.1-1990, paragraphe B.3.3.1.1) : " Les signaux SIGBUS, SIGEMT, SIGIOT, SIGTRAP, et SIGSYS ont ete omis de la norme POSIX.1 car leur comportement est dependant de l'implementation et donc ne peut etre reperto- rie d'une maniere satisfaisante. Certaines implementations peuvent fournir ces signaux mais doivent documenter leur effet " La maniere la plus elegante de regler ce probleme est de redefinir ces signaux a SIGUNUSED. La maniere _n_o_r_m_a_l_e de proceder est d'entourer le code avec les #ifdef appropries : #ifdef SIGSYS /* ... code utilisant les signaux non posix .... */ #endif 44..33..33.. CCooddee KK && RR GCC est un compilateur ANSI, or il existe beaucoup de code qui ne soit pas ANSI. Il n'y a pas grand chose a faire, sauf rajouter l'option -traditional lors de la compilation. Il effectue certaines verifications supplementaires. Consultez les pages info gcc. Notez que l'option -traditional a pour unique effet de changer la forme du langage accepte par gcc. Par exemple, elle active l'option -fwritable-strings, qui deplace toutes les chaines de caracteres vers l'espace de donnees (depuis l'espace de texte, ou elle ne peuvent pas etre modifiees). Ceci augmente la taille de la memoire occupee par le programme. 44..33..44.. lleess pprroottoottyyppeess dduu ccooddee LLeess ssyymmbboolleess dduu pprreepprroocceesssseeuurr pprroodduuiisseenntt uunn ccoonnfflliitt aavveecc Un des problemes frequents se produit lorsque certaines fonctions standards sont definies comme macros dans les fichiers d'en-tete de Linux et le preprocesseur refusera de traiter des prototypes identiques. Par exemple, cela peut arriver avec atoi() et atol(). 44..33..55.. sspprriinnttff(()) Parfois, soyez prudent lorsque vous effectuez un portage a partir des sources de programmes fonctionnant sous SunOs, surtout avec la fonction sprintf(string, fmt, ...) car elle renvoie un pointeur sur la chaine de caracteres alors que Linux (suivant la norme ANSI) retourne le nombre de caracteres recopies dans la chaine de caracteres. 44..33..66.. ffccnnttll et ses copains. Ou se trouve la definition de FD_* et compagnie ? Dans . Si vous utilisez fcntl vous voudrez probablement inclure egalement, pour avoir le prototype de la fonction. D'une maniere generale, la page de manuel pour une fonction donne la liste des fichiers d'en-tete a inclure. 44..33..77.. ccoommmmeenncceenntt ddaannss uunn eettaatt dd''aatttteennttee aaccttiivvee LLee ttiimmeeoouutt ddee sseelleecctt(()). Les programmes A une certaine epoque, le parametre timeout de la fonction select() etait utilise en lecture seule. C'est pourquoi la page de manuel comporte une mise en garde : select() devrait retourner normalement le temps ecoule depuis le timeout initial, s'il s'est declenche, en modifi- ant la valeur pointee par le parametre time. Cela sera peut- etre implemente dans les versions ulterieures du systeme. Donc, il n'est pas vraiment prudent de supposer que les don- nees pointees ne seront pas modifiees lors de l'appel a select(). Mais tout arrive avec le temps ! Lors d'un retour de select(), l'argument timeout recevra le temps ecoule depuis la derniere reception de donnees. Si aucune donnee n'est arrivee, la valeur sera nulle, et les futurs appels a cette fonction utilisant le meme timeout auront pour resultat un retour immediat. Pour resoudre le probleme, il suffit de mettre la valeur timeout dans la structure a chaque appel de select(). Le code initial etait struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; while (some_condition) select(n,readfds,writefds,exceptfds,&timeout); et doit devenir : struct timeval timeout; while (some_condition) { timeout.tv_sec = 1; timeout.tv_usec = 0; select(n,readfds,writefds,exceptfds,&timeout); } Certaines versions de Mosaic etaient connues a une certaine epoque pour avoir ce probleme. La vitesse de rotation du globe terrestre etait inversement proportionnelle a la vitesse de transfert des donnees ! 44..33..88.. AAppppeellss ssyysstteemmeess iinntteerrrroommppuuss 44..33..88..11.. SSyymmppttoommeess :: Lorsqu'un processus est arrete avec un Ctrl-Z et relance - ou bien lorsqu'un autre signal est declenche dans une situation differente : par exemple avec un Ctrl-C, la terminaison d'un processus, etc, on dit qu'il y a " interruption d'un appel systeme " , ou bien " write : erreur inconnue " ou des trucs de ce genre. 44..33..88..22.. PPrroobblleemmeess :: Les systemes POSIX verifient les signaux plus souvent que d'autres Unix plus anciens. Linux peux lancer les gestionnaires de signaux : +o d'une maniere asynchrone (sur un top d'horloge) +o lors d'un retour de n'importe quel appel systeme +o pendant l'execution des appels systemes suivants : select(), pause(), connect(), accept(), read() sur des terminaux, des sockets, des pipes ou des fichiers situes dans /proc, write() sur des terminaux, des sockets, des pipes ou des imprimantes, open() sur des FIFOs, des lignes PTYs ou series, ioctl() sur des terminaux, fcntl() avec la commande F_SETLKW, wait4(), syslog(), et toute operation d'ordre TCP ou NFS. Sur d'autres systemes d'exploitation, il est possible que vous ayez a inclure dans cette categorie les appels systemes suivants : creat(), close(), getmsg(), putmsg(), msgrcv(), msgsnd(), recv(), send(), wait(), waitpid(), wait3(), tcdrain(), sigpause(), semop(). Si un signal (que le programme desire traiter) est lance pendant l'execution d'un appel systeme, le gestionnaire est lance. Lorsque le gestionnaire du signal se termine, l'appel systeme detecte qu'il a ete interrompu et se termine avec la valeur -1 et errno = EINTR. Le programme n'est pas forcement au courant de ce qui s'est passe et donc s'arrete. Vous pouvez choisir deux solutions pour resoudre ce probleme. (1)Dans tout gestionnaire de signaux que vous mettez en place, ajoutez l'option SA_RESTART au niveau de _s_i_g_a_c_t_i_o_n. Par exemple, modifiez signal (signal_id, mon_gestionnaire_de_signaux); en signal (signal_id, mon_gestionnaire_de_signaux); { struct sigaction sa; sigaction (signal_id, (struct sigaction *)0, &sa); #ifdef SA_RESTART sa.sa_flags |= SA_RESTART; #endif #ifdef SA_INTERRUPT sa.sa_flags &= ~ SA_INTERRUPT; #endif sigaction (signal_id, &sa, (struct sigaction *)0); } Notez que lors de certains appels systemes vous devrez souvent regarder si errno n'a pas ete positionnee a EINTR par vous meme comme avec read(), write(), ioctl(), select(), pause() et connect(). (2) A la recherche de EINTR : Voici deux exemples avec read() et ioctl(), Voici le code original utilisant read() int result; while (len > 0) { result = read(fd,buffer,len); if (result < 0) break; buffer += result; len -= result; } et le nouveau code int result; while (len > 0) { result = read(fd,buffer,len); if (result < 0) { if (errno != EINTR) break; } else { buffer += result; len -= result; } } Voici un code utilisant ioctl() int result; result = ioctl(fd,cmd,addr); et cela devient int result; do { result = ioctl(fd,cmd,addr); } while ((result == -1) && (errno == EINTR)); Il faut remarquer que dans certaines versions d'Unix de type BSD on a l'habitude de relancer l'appel systeme. Pour recuperer les interruptions d'appels systemes, vous devez utiliser les options SV_INTERRUPT ou SA_INTERRUPT. 44..33..99.. "" sseeggmmeennttaattiioonn ffaauulltt "" dd''uunnee mmaanniieerree aalleeaattooiirree)) LLeess cchhaaiinneess eett lleeuurrss aacccceess eenn eeccrriittuurreess ((oouu lleess pprrooggrraammmmeess qquuii pprroovvoo-- qquueenntt ddeess GCC a une vue optimiste en ce qui concerne ses utilisateurs, en croyant qu'ils respectent le fait qu'une chaine dite constante l'est reellement. Donc, il les range dans la zone _t_e_x_t_e_(_c_o_d_e_) du programme, ou elles peuvent etre chargees puis dechargees a partir de l'image binaire de l'executable situee sur disque (ce qui evite d'occuper de l'espace disque). Donc, toute tentative d'ecriture dans cette chaine provoque un " segmentation fault ". Cela peut poser certains problemes avec d'anciens codes, par exemple ceux qui utilisent la fonction mktemp() avec une chaine constante comme argument. mktemp() essaye d'ecrire dans la chaine passee en argument. Pour resoudre ce probleme, 1. compilez avec l'option -fwritable-strings pour indiquer a gcc de mettre les chaines constantes dans l'espace de donnees 2. reecrire les differentes parties du code pour allouer une chaine non constante puis effectuer un strcpy des donnees dedans avant d'effectuer l'appel. 44..33..1100.. PPoouurrqquuooii ll''aappppeell aa eexxeeccll(()) echoue ? Tout simplement parce que vous l'utilisez mal. Le premier argument d'execl est le programme que vous desirez executer. Le second et ainsi de suite sont en fait le elements du tableau argv que vous appelez. Souvenez-vous que argv[0] est traditionnellement fixe meme si un programme est lance sans argument. Vous devriez donc ecrire : execl("/bin/ls","ls",NULL); et pas execl("/bin/ls", NULL); Lancer le programme sans argument est considere comme etant une demande d'affichage des bibliotheques dynamiques associees au programme, si vous utilisez le format a.out. ELF fonctionne d'une maniere differente. (Si vous desirez ces informations, il existe des outils plus simples; consultez la section sur le chargement dynamique, ou la page de manuel de ldd). 55.. DDeebboogguueerr eett ooppttiimmiisseerr 55..11.. EEttuuddee pprreevveennttiivvee dduu ccooddee ((lliinntt)) Il n'existe pas de lint qui soit reellement utilisable, tout simplement parce que la grande majorite des developpeurs sont satisfaits des messages d'avertissement de gcc. Il est probable que l'option la plus utile est l'option -Wall --- qui a pour effet d'afficher tous les avertissements possibles. Il existe une version du domaine public du programme lint que vous pouvez trouver a l'adresse suivante : . Je ne sais pas ce qu'elle vaut. 55..22.. DDeebboogguueerr 55..22..11.. CCoommmmeenntt rreennddrree ddeebbooggaabbllee uunn pprrooggrraammmmee ?? Vous devez compiler et effectuer l'edition de liens avec l'option -g, et sans l'option -fomit-frame-pointer. En fait, vous ne devez compiler que les modules que vous avez besoin de deboguer. Si vous possedez un systeme a.out, les bibliotheques dynamiques sont compilees avec l'option -fomit-frame-pointer, que gcc ne peut pas gerer. Lorsque vous compilez avec l'option -g, alors par defaut vous effectuez une edition de liens statique, ce qui permet de resoudre le probleme. Si l'editeur de liens echoue avec un message disant qu'il n'arrive pas a trouver la bibliotheque libg.a, c'est que vous ne possedez pas la bibliotheque /usr/lib/libg.a, qui est la bibliotheque C standard permettant le debogage. Cette bibliotheque est fournie dans le paquetage des binaires de la libc., ou (dans les nouvelles versions) vous aurez besoin de recuperer le source et de le compiler vous-meme. Vous n'avez pas reellement besoin de cela en fait, vous pouvez faire un lien logique vers /usr/lib/libc.a 55..22..11..11.. CCoommmmeenntt rreedduuiirree llaa ttaaiillllee ddeess eexxeeccuuttaabblleess ?? Bon nombre de produits GNU sont fournis pour compiler avec l'option -g, ce qui genere des executables d'une taille tres importante (et souvent l'edition de liens s'effectue d'une maniere statique). Ce n'est pas une idee lumineuse... Si le programme possede le script configure genere par autoconf, vous pouvez modifier les options de debogage en effectuant un vous pouvez aller modifier le Makefile. Bien sur, si vous utilisez le format ELF, l'edition de liens sera effectuee de maniere dynamique meme avec l'option -g. Dans ce cas, vous pouvez effectuer un strip sur l'executable. 55..22..22.. PPrrooggrraammmmeess ddiissppoonniibblleess Beaucoup de gens utilisent ggddbb, que vous pouvez recuperer sur le site prep.ai.mit.edu , sous une forme binaire sur tsx-11 ou sur sunsite. xxxxggddbb est une surcouche X de gdb (c.a.d. que vous avez besoin de gdb pour utiliser xxgdb). Les sources peuvent etre recuperes sur Il existe egalement le debogueur UUPPSS qui a ete porte par Rick Sladkey. Il fonctionne sous X egalement, mais a la difference d'xxgdb, ce n'est qu'une surcouche X pour un debogueur en mode en texte. Il possede certaines caracteristiques tres interessantes et si vous utilisez beaucoup ce genre d'outils, vous l'essayerez surement. Les patches ainsi que des versions precompilees pour Linux peuvent etre trouvees sur , et les sources peuvent etre recuperes sur . Un autre outil que vous pouvez trouver utile pour deboguer est " ssttrraaccee " , qui affiche les appels systemes que le processus lance. Il possede d'autres caracteristiques telles que donner les chemins d'acces ou ont ete compiles les binaires, donner les temps passes dans chacun des appels systemes, et il vous permet egalement de connaitre les resultats des appels. La derniere version de strace (actuellement la version 3.0.8) peut etre trouvee sur . 55..22..33.. PPrrooggrraammmmeess eenn ttaacchhee ddee ffoonndd ((ddeemmoonn)) Les demons lancent typiquement un fork() des leur lancement et terminent donc le pere. Cela fait une session de deboguage tres courte. La maniere la plus simple de resoudre ce probleme est de poser un point d'arret sur fork, et lorsque le programme s'arrete, forcer le retour a 0. (gdb) list 1 #include 2 3 main() 4 { 5 if(fork()==0) printf("child\n"); 6 else printf("parent\n"); 7 } (gdb) break fork Breakpoint 1 at 0x80003b8 (gdb) run Starting program: /home/dan/src/hello/./fork Breakpoint 1 at 0x400177c4 Breakpoint 1, 0x400177c4 in fork () (gdb) return 0 Make selected stack frame return now? (y or n) y #0 0x80004a8 in main () at fork.c:5 5 if(fork()==0) printf("child\n"); (gdb) next Single stepping until exit from function fork, which has no line number information. child 7 } 55..22..44.. FFiicchhiieerrss ccoorree Lorsque Linux se lance, il n'est generalement pas configure pour produire des fichiers core. Si vous les voulez vous devez utiliser votre shell pour ca en faisant sous csh (ou tcsh) : % limit core unlimited avec sh, bash, zsh, pdksh, utilisez $ ulimit -c unlimited Si vous voulez pousser le vice a nommer votre fichier core (par exemple si vous utilisez un debogueur bogue... ce qui est un comble) vous pouvez simplement modifier le noyau. Editez les fichiers fs/binfmt_aout.c et fs/binfmt_elf.c (dans les nouveaux noyaux, vous devrez chercher ailleurs) : memcpy(corefile,"core.",5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = '\0'; #endif et changez les 0 par des 1. 55..33.. CCaarraacctteerriissttiiqquueess dduu pprrooggrraammmmee Il est possible d'examiner un peu le programme pour savoir quels sont les appels de fonctions qui sont effectues le plus souvent ou bien qui prennent du temps. C'est une bonne maniere d'optimiser le code en determinant la ou l'on passe le plus de temps. Vous devez compiler tous les objets avec l'option -p, et pour mettre en forme la sortie ecran, vous aurez besoin du programme gprof (situe dans les binutils). Consultez les pages de manuel gprof pour plus de details. 66.. EEddiittiioonn ddee lliieennss Entre les deux formats de binaires incompatibles, bibliotheques statiques et dynamiques, on peut comparer l'operation d'edition de lien en fait a un jeu ou l'on se demanderait qu'est-ce qui se passe lorsque je lance le programme ? Cette section n'est pas vraiment simple... Pour dissiper la confusion qui regne, nous allons nous baser sur ce qui se passe lors d'execution d'un programme, avec le chargement dynamique. Vous verrez egalement la description de l'edition de liens dynamiques, mais plus tard. Cette section est dediee a l'edition de liens qui intervient a la fin de la compilation. 66..11.. BBiibblliiootthheeqquueess ppaarrttaaggeeeess ccoonnttrree bbiibblliiootthheeqquueess ssttaattiiqquueess La derniere phase de construction d'un programme est de realiser l'edition de liens, ce qui consiste a assembler tous les morceaux du programme et de chercher ceux qui sont manquants. Bien evidement, beaucoup de programmes realisent les memes operations comme ouvrir des fichiers par exemple, et ces pieces qui realisent ce genre d'operations sont fournies sous la forme de bibliotheques. Sous Linux, ces bibliotheques peuvent etre trouvees dans les repertoires /lib et/usr/lib/ entre autres. Lorsque vous utilisez une bibliotheque statique, l'editeur de liens cherche le code dont votre programme a besoin et en effectue une copie dans le programme physique genere. Pour les bibliotheques partagees, c'est le contraire : l'editeur de liens laisse du code qui lors du lancement du programme chargera automatiquement la bibliotheque. Il est evident que ces bibliotheques permettent d'obtenir un executable plus petit; elles permettent egalement d'utiliser moins de memoire et moins de place disque. Linux effectue par defaut une edition de liens dynamique s'il peut trouver les bibliotheques de ce type sinon, il effectue une edition de liens statique. Si vous obtenez des binaires statiques alors que vous les voulez dynamiques verifiez que les bibliotheques existent (*.sa pour le format a.out, et *.so pour le format ELF) et que vous possedez les droits suffisants pour y acceder (lecture). Sous Linux, les bibliotheques statiques ont pour nom libnom.a, alors que les bibliotheques dynamiques sont appelees libnnom.so.x.y.z ou x.y.z represente le numero de version. Les bibliotheques dynamiques ont souvent des liens logiques qui pointent dessus, et qui sont tres importants. Normalement, les bibliotheques standards sont livrees sous la double forme dynamique et statique. Vous pouvez savoir de quelles bibliotheques dynamiques un programme a besoin en utilisant la commande ldd (_L_i_s_t _D_y_n_a_m_i_c _D_e_p_e_n_d_e_n_c_i_e_s) $ ldd /usr/bin/lynx libncurses.so.1 => /usr/lib/libncurses.so.1.9.6 libc.so.5 => /lib/libc.so.5.2.18 Cela indique sur mon systeme que l'outil lynx (outil WWW) a besoin des bibliotheques dynamiques libc.so.5 (la bibliotheque C) et de libncurses.so.1 (necessaire pour le controle du terminal). Si un programme ne possede pas de dependances, ldd indiquera `_s_t_a_t_i_c_a_l_l_y _l_i_n_k_e_d' (edition de liens statique). 66..22.. AA llaa rreecchheerrcchhee ddeess ffoonnccttiioonnss...... oouu ddaannss qquueellllee bbiibblliiootthheeqquuee ssee ttrroouuvvee llaa ffoonnccttiioonn ssiinn(()) ?') nm _n_o_m_d_e_b_i_b_l_i_o_t_h_e_q_u_e vous donne tous les symboles references dans la bibliotheque. Cela fonctionne que cela soit du code statique ou dynamique. Supposez que vous vouliez savoir ou se trouve definie la fonction tcgetattr() : $ nm libncurses.so.1 |grep tcget U tcgetattr La lettre U vous indique que c'est indefini (_U_n_d_e_f_i_n_e_d) --- cela indique que la bibliotheque ncurses l'utilise mais ne la definit pas. Vous pouvez egalement faire : $ nm libc.so.5 | grep tcget 00010fe8 T __tcgetattr 00010fe8 W tcgetattr 00068718 T tcgetpgrp La lettre `W' indique que le symbole est defini mais de telle maniere qu'il peut etre surcharge par une autre definition de la fonction dans une autre bibliotheque (W pour _w_e_a_k : faible). Une definition normale est marquee par la lettre `T' (comme pour tcgetpgrp). La reponse a la question situee dans le titre est libm.(so|a). Toutes les fonctions definies dans le fichier d'en-tete sont implementees dans la bibliotheque mathematique donc vous devrez effectuer l'edition de liens grace a -lm. 66..33.. TTrroouuvveerr lleess ffiicchhiieerrss Supposons que vous ayez le message d'erreur suivant de la part de l'editeur de liens : ld: Output file requires shared library `libfoo.so.1` La strategie de recherche de fichiers de ld ou de ses copains differe de la version utilisee, mais vous pouvez etre sur que les fichiers situes dans le repertoire /usr/lib seront trouves. Si vous desirez que des fichiers situes a un endroit different soient trouves, il est preferable d'ajouter l'option -L a gcc ou ld. Si cela ne vous aide pas clairement, verifiez que vous avez le bon fichier a l'endroit specifie. Pour un systeme a.out, effectuer l'edition de liens avec -ltruc implique que ld recherche les bibliotheques libtruc.sa (bibliotheques partagees), et si elle n'existe pas, il recherche libtruc.a (statique). Pour le format ELF, il cherche libtruc.so puis libtruc.a. libtruc.so est generalement un lien symbolique vers libtruc.so.x. 66..44.. CCoommppiilleerr vvoottrree pprroopprree bbiibblliiootthheeqquuee 66..44..11.. NNuummeerroo ddee llaa vveerrssiioonn Comme tout programme, les bibliotheques ont tendance a avoir quelques bogues qui sont corriges au fur et a mesure. De nouvelles fonctionnalites sont ajoutees et qui peuvent changer l'effet de celles qui existent ou bien certaines anciennes peuvent etres supprimees. Cela peut etre un probleme pour les programmes qui les utilisent. Donc, nous introduisons la notion de numero de version. Nous repertorions les modifications effectuees dans la bibliotheques comme etant soit mineures soit majeures. Cela signifie qu'une modification mineure ne peut pas modifier le fonctionnement d'un programme (en bref, il continue a fonctionner comme avant). Vous pouvez identifier le numero de la version de la bibliotheque en regardant son nom (en fait c'est un mensonge pour les bibliotheques ELF... mais continuez a faire comme si !) : libtruc.so.1.2 a pour version majeure 1 et mineure 2. Le numero de version mineur peut etre plus ou moins eleve --- la bibliotheque C met un numero de patch, ce qui produit un nom tel que libc.so.5.2.18, et c'est egalement courant d'y trouver des lettres ou des blancs soulignes ou tout autre caractere ASCII affichable. Une des principales differences entre les formats ELF et a.out se trouve dans la maniere de construire la bibliotheque partagee. Nous traiterons les bibliotheques partagees en premier car c'est plus simple. 66..44..22.. EELLFF,, qquu''eesstt--ccee qquuee cc''eesstt ?? ELF (_E_x_e_c_u_t_a_b_l_e _a_n_d _L_i_n_k_i_n_g _F_o_r_m_a_t) est format de binaire initialement concu et developpe par USL (_U_N_I_X _S_y_s_t_e_m _L_a_b_o_r_a_t_o_r_i_e_s) et utilise dans les systemes Solaris et System R4. En raison de sa facilite d'utilisation par rapport a l'ancien format dit a.out qu'utilisait Linux, les developpeurs de GCC et de la bibliotheque C ont decide l'annee derniere de basculer tout le systeme sous le format ELF. ELF est desormais le format binaire standard sous Linux. 66..44..22..11.. EELLFF,, llee rreettoouurr !! Ce paragraphe provient du groupe '/news-archives/comp.sys.sun.misc'. ELF (_E_x_e_c_u_t_a_b_l_e _L_i_n_k_i_n_g _F_o_r_m_a_t) est le " nouveau et plus performant " format de fichier introduit dans SVR4. ELF est beaucoup plus puissant que le sacro-saint format COFF, dans le sens ou il est extensible. ELF voit un fichier objet comme une longue liste de sections (plutot qu'un tableau de taille fixe d'elements). Ces sections, a la difference de COFF ne se trouvent pas a un endroit constant et ne sont pas dans un ordre particulier, etc. Les utilisateurs peuvent ajouter une nouvelle section a ces fichiers objets s'il desirent y mettre de nouvelles donnees. ELS possede un for- mat de debogage plus puissant appele DWARF (_D_e_b_u_g_g_i_n_g _W_i_t_h _A_t_t_r_i_b_u_t_e _R_e_c_o_r_d _F_o_r_m_a_t) - par encore entierement gere par Linux (mais on y travaille !). Une liste chainee de " DWARF DIEs " (ou _D_e_b_u_g_g_i_n_g _I_n_f_o_r_m_a_t_i_o_n _E_n_t_r_i_e_s - NdT... le lecteur aura surement note le jeu de mot assez noir : dwarf = nain; dies = morts) forment la section _._d_e_b_u_g dans ELF. Au lieu d'avoir une liste de petits enregistrements d'information de taille fixes, les DWARF DIEs contiennent chacun une longue liste complexe d'attributs et sont ecrits sous la forme d'un arbre de donnees. Les DIEs peuvent contenir une plus grande quantite d'information que la section _._d_e_b_u_g du format COFF ne le pouvait (un peu comme les graphes d'her- itages du C++). Les fichiers ELF sont accessibles grace a la bibliotheque d'acces de SVR4 (Solaris 2.0 peut-etre ?), qui fournit une interface simple et rapide aux parties les plus complexes d'ELF. Une des aubaines que permet la bibliotheque d'acces ELF est que vous n'avez jamais besoin de connaitre les mean- dres du format ELF. Pour acceder a un fichier Unix, on utilise un Elf *, retourne par un appel a elf_open(). Ensuite, vous effectuez des appels a elf_foobar() pour obtenir les differents composants au lieu d'avoir a triturer le fichier physique sur le disque (chose que beaucoup d'utilisateurs de COFF ont fait...). Les arguments pour ou contre ELF, et les problemes lies a la mise a jour d'un systeme a.out vers un systeme ELF sont decrits dans le ELF- HOWTO et je ne veux pas effectuer de copier coller ici (NdT: ce HowTo est egalement traduit en francais). Ce HowTo se trouve au meme endroit que les autres. 66..44..22..22.. LLeess bbiibblliiootthheeqquuee ppaarrttaaggeeeess EELLFF Pour construire libtruc.so comme une bibliotheque dynamique, il suffit de suivre les etapes suivantes : $ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname,libtruc.so.1 -o libtruc.so.1.0 *.o $ ln -s libtruc.so.1.0 libtruc.so.1 $ ln -s libtruc.so.1 libtruc.so $ LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH Cela va generer une bibliotheque partagee appelee libtruc.so.1.0, les liens appropries pour ld (libtruc.so) et le chargeur dynamique (libtruc.so.1) pour le trouver. Pour tester, nous ajoutons le repertoire actuel a la variable d'environnement LD_LIBRARY_PATH. Lorsque vous etes satisfait et que la bibliotheque fonctionne, vous n'avez plus qu'a la deplacer dans le repertoire par exemple, /usr/local/lib, et de recreer les liens appropries. Le lien de libtruc.so.1 sur libtruc.so.1.0 est enregistre par ldconfig, qui sur bon nombre de systemes est lance lors du processus d'amorcage. Le lien libfoo.so doit etre mis a jour a la main. Si vous faites attention lors de la mise a jour de la bibliotheque la chose la plus simple a realiser est de creer le lien libfoo.so -> libfoo.so.1, pour que ldconfig conserve les liens actuels. Si vous ne faites pas cela, vous aurez des problemes plus tard. Ne me dites pas que l'on ne vous a pas prevenu ! $ /bin/su # cp libtruc.so.1.0 /usr/local/lib # /sbin/ldconfig # ( cd /usr/local/lib ; ln -s libtruc.so.1 libtruc.so ) 66..44..22..33.. LLeess nnuummeerrooss ddee vveerrssiioonn,, lleess nnoommss eett lleess lliieennss Chaque bibliotheque possede un nom propre (_s_o_n_a_m_e). Lorsque l'editeur de liens en trouve un qui correspond a un nom cherche, il enregistre le nom de la bibliotheque dans le code binaire au lieu d'y mettre le nom du fichier de la bibliotheque. Lors de l'execution, le chargeur dynamique va alors chercher un fichier ayant pour nom le nom propre de la bibliotheque, et pas le nom du fichier de la bibliotheque. Par exemple, une bibliotheque ayant pour nom libtruc.so peut avoir comme nom propre libbar.so, et tous les programmes lies avec vont alors chercher libbar.so lors de leur execution. Cela semble etre une nuance un peu pointilleuse mais c'est la clef de la comprehension de la coexistence de plusieurs versions differentes de la meme bibliotheque sur le meme systeme. On a pour habitude sous Linux d'appeler une bibliotheque libtruc.so.1.2 par exemple, et de lui donner comme nom propre libtruc.so.1. Si cette bibliotheque est rajoutee dans un repertoire standard (par exemple dans /usr/lib), le programme ldconfig va creer un lien symbolique entre libtruc.so.1 -> libtruc.so.1.2 pour que l'image appropriee soit trouvee lors de l'execution. Vous aurez egalement besoin d'un lien symbolique libtruc.so -> libtruc.so.1 pour que ld trouve le nom propre lors de l'edition de liens. Donc, lorsque vous corrigez des erreurs dans la bibliotheque ou bien lorsque vous ajoutez de nouvelles fonctions (en fait, pour toute modification qui n'affecte pas l'execution des programmes deja existants), vous reconstruisez la bibliotheque, conservez le nom propre tel qu'il etait et changez le nom du fichier. Lorsque vous effectuez des modifications que peuvent modifier le deroulement des programmes existants, vous pouvez tout simplement incrementer le nombre situe dans le nom propre --- dans ce cas, appelez la nouvelle version de la bibliotheque libtruc.so.2.0, et donnez-lui comme nom propre libtruc.so.2. Maintenant, faites pointer le lien de libfoo.so vers la nouvelle version et tout est bien dans le meilleur des mondes ! Il est utile de remarquer que vous n'etes pas oblige de nommer les bibliotheques de cette maniere, mais c'est une bonne convention. Elf vous donne une certaine liberte pour nommer des bibliotheques tant et si bien que cela peut perturber certains utilisateurs, mais cela ne veut pas dire que vous etes oblige de le faire. Resume : supposons que choisissiez d'adopter la methode traditionnelle avec les mises a jour majeures qui peuvent ne pas etre compatibles avec les versions precedentes et les mises a jour mineures qui ne posent pas ce probleme. Il suffit de creer la bibliotheque de cette maniere : gcc -shared -Wl,-soname,libtruc.so.majeur -o libtruc.so.majeur.mineur et tout devrait etre parfait ! 66..44..33.. aa..oouutt.. LLee bboonn vviieeuuxx ffoorrmmaatt La facilite de construire des bibliotheque partagees est la raison principale de passer a ELF. Ceci dit, il est toujours possible de creer des bibliotheques dynamiques au format a.out. Recuperez le fichier archive et lisez les 20 pages de documentation que vous trouverez dedans apres l'avoir desarchive. Je n'aime pas avoir l'air d'etre aussi partisan, mais il est clair que je n'ai jamais aime ce format :-). 66..44..33..11.. ZZMMAAGGIICC ccoonnttrree QQMMAAGGIICC QMAGIC est le format des executables qui ressemble un peu aux vieux binaires a.out (egalement connu comme ZMAGIC), mais qui laisse la premiere page libre. Cela permet plus facilement de recuperer les adresses non affectees (comme NULL) dans l'intervalle 0-4096 (NdT : Linux utilise des pages de 4Ko). Les editeurs de liens desuets ne gerent que le format ZMAGIC, ceux un peu moins rustiques gerent les deux, et les plus recents uniquement le QMAGIC. Cela importe peu car le noyau gere les deux types. La commande file est capable d'identifier si un programme est de type QMAGIC. 66..44..33..22.. GGeessttiioonn ddeess ffiicchhiieerrss Une bibliotheque dynamique a.out (DLL) est composee de deux fichiers et d'un lien symbolique. Supposons que l'on utilise la bibliotheque _t_r_u_c, les fichiers seraient les suivants : libtruc.sa et libtruc.so.1.2; et le lien symbolique aurait pour nom libtruc.so.1 et pointerait sur le dernier des fichiers. Mais a quoi servent-ils ? Lors de la compilation, ld cherche libtruc.sa. C'est le fichier de description de la bibliotheque : il contient toutes les donnees exportees et les pointeurs vers les fonctions necessaires pour l'edition de liens. Lors de l'execution, le chargeur dynamique cherche libtruc.so.1. C'est un lien symbolique plutot qu'un reel fichier pour que les bibliotheques puissent etre mise a jour sans avoir a casser les applications qui utilisent la bibliotheque. Apres la mise a jour, disons que l'on est passe a la version libfoo.so.1.3, le lancement de ldconfig va positionner le lien. Comme cette operation est atomique, aucune application fonctionnant n'aura de probleme. Les bibliotheques DLL (Je sais que c'est une tautologie... mais pardon !) semblent etre tres souvent plus importantes que leur equivalent statique. En fait, c'est qu'elles reservent de la place pour les extensions ulterieures sous la simple forme de trous qui sont fait de telle maniere qu'ils n'occupent pas de place disque (NdT : un peu comme les fichiers core). Toutefois, un simple appel a cp ou a makehole les remplira... Vous pouvez effectuer une operation de strip apres la construction de la bibliotheque, comme les adresses sont a des endroits fixes. NNee ffaaiitteess ppaass llaa mmeemmee ooppeerraattiioonn aavveecc lleess bbiibblliiootthheeqquueess EELLFF !! 66..44..33..33.. "" lliibbcc--lliittee "" ?? Une " libc-lite " (contraction de _l_i_b_c et _l_i_t_t_l_e) est une version epuree et reduite de la bibliotheque libc construite de telle maniere qu'elle puisse tenir sur une disquette avec un certain nombre d'outil Unix. Elle n'inclut pas curses, dbm, termcap, ... Si votre /lib/libc.so.4 est liee avec une bibliotheque de ce genre il est tres fortement conseille de la remplacer avec une version complete. 66..44..44.. EEddiittiioonn ddee lliieennss :: pprroobblleemmee ccoouurraannttss Envoyez-les moi ! DDeess pprrooggrraammmmeess ssttaattiiqquueess lloorrssqquuee vvoouuss lleess vvoouulleezz partages" Verifiez que vous avez les bons liens pour que ld puisse trouver les bibliotheques partagees. Pour ELF cela veut dire que libtruc.so est un lien symbolique sur son image, pour a.out un fichier libtruc.sa. Beaucoup de personnes ont eu ce probleme apres etre passes des outils ELF 2.5 a 2.6 (binutils) --- la derniere version effectue une recherche plus intelligente pour les bibliotheques dynamiques et donc ils n'avaient pas cree tous les liens symboliques necessaires. Cette caracteristique avait ete supprimee pour des raisons de compatibilite avec d'autres architectures et parce qu'assez souvent cela ne marchait pas bien. En bref, cela posait plus de problemes qu'autre chose. LLee pprrooggrraammmmee ``mmkkiimmaaggee'' nn''aarrrriivvee ppaass aa ttrroouuvveerr lliibbggcccc Comme libc.so.4.5.x et suivantes, libgcc n'est pas une bibliotheque partagee. Vous devez remplacer les `-lgcc' sur la ligne de commande par `gcc -print-libgcc-file-name` (entre quotes) Egalement, detruisez tous les fichiers situes dans /usr/lib/libgcc*. C'est important. LLee mmeessssaaggee ____NNEEEEDDSS__SSHHRRLLIIBB__lliibbcc__44 mmuullttiippllyy ddeeffiinneedd Sont une consequence du meme probleme. LLee mmeessssaaggee ````AAsssseerrttiioonn ffaaiilluurree'''' aappppaarraaiitt lloorrssqquuee vvoouuss rreeccoonnssttrruuiisseezz uunnee DLL" Ce message enigmatique signifie qu'un element de votre table _j_u_m_p a depasse la table car trop peu de place etait reservee dans le fichier jump.vars file. Vous pouvez trouver le(s) coupable(s) en lancant la commande getsize fournie dans le paquetage tools-2.17.tar.gz. La seule solution est de passer a une nouvelle version majeure, meme si elle sera incompatible avec les precedentes. lldd:: oouuttppuutt ffiillee nneeeeddss sshhaarreedd lliibbrraarryy lliibbcc..ssoo..44 Cela arrive lorsque vous effectuez l'edition de liens avec des bibliotheques differentes de la libc (comme les bibliotheques X) et que vous utilisez l'option -g sans utiliser l'option -static. Les fichiers .sa pour les bibliotheques dynamiques ont un symbole non resolu _NEEDS_SHRLIB_libc_4 qui est defini dans libc.sa. Or, lorsque vous utilisez -g vous faites l'edition de liens avec libg.a ou libc.a et donc ce symbole n'est jamais defini. Donc, pour resoudre le probleme, ajoutez l'option -static lorsque vous compilez avec l'option -g, ou n'utilisez pas -g lors de l'edition de liens ! 77.. CChhaarrggeemmeenntt ddyynnaammiiqquuee _C_e _p_a_r_a_g_r_a_p_h_e _e_s_t _e_n _f_a_i_t _u_n _p_e_u _c_o_u_r_t _: _i_l _s_e_r_a _e_t_e_n_d_u _d_a_n_s _u_n_e _v_e_r_s_i_o_n _u_l_t_e_r_i_e_u_r_e _d_e_s _q_u_e _j_'_a_u_r_a_i _r_e_c_u_p_e_r_e _l_e _H_o_w_T_o _E_L_F 77..11.. CCoonncceeppttss Linux possede des bibliotheques dynamiques, comme on vous le repete depuis le debut de ce document ! Or, il existe un systeme pour reporter le travail d'association des noms des symboles et de leur adresse dans la bibliotheque, qui est normalement effectue lors de l'edition de liens en l'effectuant lors du chargement du programme. 77..22.. MMeessssaaggeess dd''eerrrreeuurr Envoyez moi vos erreurs ! Je n'en fait pas grand chose sauf les inserer dans ce paragraphe... ccaann''tt llooaadd lliibbrraarryy:: //lliibb//lliibbxxxxxx..ssoo,, IInnccoommppaattiibbllee vveerrssiioonn (seulement a.out) Cela signifie que vous n'avez pas la version correcte de la bibliotheque (numero dit majeur). Non, il n'est pas possible d'effectuer un lien symbolique sur la bibliotheque que vous possedez : si vous avez de la chance, vous obtiendrez un _s_e_g_m_e_n_t_a_t_i_o_n _f_a_u_l_t. Recuperez la nouvelle version. Un message un peu equivalent existe egalement sur les systemes ELF : ftp: can't load library 'libreadline.so.2' wwaarrnniinngg uussiinngg iinnccoommppaattiibbllee lliibbrraarryy vveerrssiioonn xxxxxx (seulement a.out) Vous avez un numero de version de bibliotheque (mineur) inferieur a la version avec laquelle a ete compile le programme. Le programme fonctionnera surement. Une mise a jour est toutefois conseillee. 77..33.. CCoonnttrroolleerr ll''ooppeerraattiioonn ddee cchhaarrggeemmeenntt ddyynnaammiiqquuee Il existe certaines variables d'environnements que le chargeur dynamique utilise. Beaucoup sont exploitees par le programme ldd lorsqu'il s'agit de particularites de l'environnement de l'utilisateur, ce qui peuvent etre positionnees pour lancer ldd avec des options particulieres. Voici une description des differentes variables d'environnement que vous pouvez rencontrer : +o LD_BIND_NOW --- normalement, les fonctions ne sont pas cherchees dans les bibliotheques avant leur appel. En positionnant cette option, vous verifiez que toutes les fonctions employees dans votre programmes se trouvent bien dans la bibliotheque lors de son chargement, ce qui ralentit le lancement du programme. C'est utile lorsque vous voulez tester que l'edition de liens s'est parfaitement deroulee et que tous les symboles sont bien associes. +o LD_PRELOAD peut etre defini avec un nom de fichier qui contient des fonctions surchargeant des fonctions deja existantes. Par exemple, si vous testez une strategie d'allocation memoire, et que vous voulez remplacer le malloc de la bibliotheque C par le votre situe dans un module ayant pour nom malloc.o, il vous suffit de faire : $ export LD_PRELOAD=malloc.o $ test_mon_malloc LD_ELF_PRELOAD et LD_AOUT_PRELOAD sont similaires, mais leur utilisa- tion est specifique au type de binaire utilise. Si LD__T_y_p_e_B_i_- _n_a_i_r_e_PRELOAD et LD_PRELOAD sont positionnes, celui correspondant le mieux a la machine est utilise. +o LD_LIBRARY_PATH contient une liste de repertoires contenant les bibliotheques dynamiques. Cela n'affecte pas l'edition de liens : cela n'a qu'un effet lors de l'execution. Il faut noter qu'elle est desactivee pour des programmes qui s'executent avec un setuid ou un setgid. Enfin, LD_ELF_LIBRARY_PATH et LD_AOUT_LIBRARY_PATH peuvent etre utilises pour orienter le mode de compilation du binaire. LD_LIBRARY_PATH ne devrait pas etre necessaire en principe : ajoutez les repertoires dans le fichier /etc/ld.so.conf/ et relancez ldconfig. +o LD_NOWARN s'applique au format a.out uniquement. Lorsqu'elle est positionnee (c.a.d si elle existe par exemple avec LD_NOWARN=true; export LD_NOWARN) cela arrete le chargeur du programme meme sur des avertissements insignifiants (tels que des messages d'incompatibilites de numeros mineurs de version). +o LD_WARN s'applique a ELF uniquement. Lorsqu'elle est positionnee, on transforme le message habituellement fatal _C_a_n_'_t _f_i_n_d _l_i_b_r_a_r_y en un avertissement. Ce n'est pas positionne par defaut mais c'est important pour un programme comme ldd. +o LD_TRACE_LOADED_OBJECTS s'applique a ELF uniquement, et permet de simuler l'execution des programmes comme s'ils l'etaient par ldd : $ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx libncurses.so.1 => /usr/lib/libncurses.so.1.9.6 libc.so.5 => /lib/libc.so.5.2.18 77..44.. EEccrriirree ddeess pprrooggrraammmmeess eenn uuttiilliissaanntt llee cchhaarrggeemmeenntt ddyynnaammiiqquuee Cela ressemble enormement au systeme de chargement dynamique utilise sous Solaris 2.x. Ce systeme est decrit d'une maniere precise dans le document expliquant la programmation avec ELF ecrit par H J Lu et dans la page de manuel dlopen(3), qui se trouve dans le paquetage ld.so. Voici un exemple simple : pensez a faire l'edition de liens avec -ldl #include #include main() { void *libc; void (*printf_call)(); if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY)) { printf_call = dlsym(libc,"printf"); (*printf_call)("Bonjour ! Ha ben ca marche pil poil sous Linux !\n"); } } 88.. CCoonnttaacctteerr lleess ddeevveellooppppeeuurrss 88..11.. AAnnnnoonncceerr ddeess bboogguueess Commencez par mettre en doute le probleme. Est-ce specifique a Linux ou bien cela arrive avec gcc mais sur d'autres plates-formes ? Est-ce specifique a la version du noyau ? A la version de la bibliotheque C ? Est-ce que ce probleme disparait lorsque vous effectuez une edition de liens statique ? Pouvez-vous produire un code tres court mettant en evidence le probleme ? Apres avoir repondu apres ces quelques questions, vous saurez quel programme est a l'origine du probleme. Pour un probleme direct avec GCC, le mieux est de consulter le fichier d'information livre avec : la procedure pour rapporter un bogue y est detaille. Pour un probleme avec ld.so, la bibliotheque C ou mathematique, envoyez un courrier electronique a linux-gcc@vger.rutgers.edu. Si possible, donnez un court exemple mettant en evidence le probleme ainsi qu'une courte description indiquant ce que le programme aurait normalement du faire, et ce qu'il fait en realite. 88..22.. PPaarrttiicciippeerr aauu ddeevveellooppppeemmeenntt Si vous desirez participer au developpement de GCC ou de la bibliotheque C, la premiere chose a faire est de rejoindre la liste de diffusion linux-gcc@vger.rutgers.edu. Si vous desirez uniquement savoir de quoi ca parle, il existe des archives a l'adresse . Tout depend de ce que vous desirez faire ou apporter a ce projet ! 99.. DDiivveerrss 99..11.. CCee ddooccuummeenntt Ce HowTo est base sur la FAQ de Mitchum DSouza's. Bon nombre des informations en proviennent. D'une maniere generale, il est frequent de dire une phrase du genre " je n'ai pas tout teste et donc ne me blamez pas si vous cassez votre disque, votre systeme ou si vous rompez avec votre epouse ". Le nom des contributeurs a ce document sont donnes par ordre alphabetique : Andrew Tefft, Axel Boldt, Bill Metzenthen, Bruce Evans, Bruno Haible, Daniel Barlow, Daniel Quinlan, David Engel, Dirk Hohndel, Eric Youngdale, Fergus Henderson, H.J. Lu, Jens Schweikhardt, Kai Petzke, Michael Meissner, Mitchum DSouza, Olaf Flebbe, Paul Gortmaker, Rik Faith, Steven S. Dick, Tuomas J Lukka, et bien sur Linus Torvalds, sans qui ce genre d'exercice aurait ete difficile, voir impossible :-) Ne soyez pas offense si votre nom n'apparait pas dans la liste et que vous ayez contribue a ce document (sous la forme d'un HowTo ou d'une FAQ). Envoyez-moi un courrier electronique et j'effectuerai la correction. 99..22.. TTrraadduuccttiioonn A l'heure ou j'ecris ces lignes, je ne connais pas de traduction de ce document. Si vous en realisez une, s'il vous plait dites-le moi. Je suis disponible pour toute aide concernant l'explication du texte, je serai tres content d'y repondre. Note du traducteur : CCooccoorriiccoo !! La version francaise est la premiere traduction de ce document. 99..33.. CCoonnttaaccttss Tout contact est le bienvenu. Envoyez-moi un courrier electronique a l'adresse suivante : dan@detached.demon.co.uk. Ma clef publique PGP (ID 5F263625) est disponible sur mes pages WWW , Si vous souhaitez rendre confidentiel certains messages. 99..44.. CCooppyyrriigghhtt Toutes les remarques appartiennent a leurs auteurs respectifs. Ce document est copyrighte (C) 1996 Daniel Barlow . Il peut etre reproduit et distribue en partie ou entierement, sur tout support physique ou electronique, du moment ou ce copyright se trouve sur toute les copies. La redistribution commerciale est autorisee et encouragee. Toutefois l'auteur de ce document doit etre mis au courant de ce genre de distributions. Toute traduction, adaptation, ou bien tout travail incorporant tout document HowTo Linux doit posseder ce copyright. De cette maniere, vous ne pouvez pas imposer de restriction a la distribution de ce document. Des exceptions peuvent etre eventuellement accordees sous certaines conditions : contactez le coordinateur des HowTo's Linux a l'adresse donnee ci-dessous. En resume, nous souhaitons voir diffuser l'information de la maniere la plus large qui soit. Toutefois, nous souhaitons garder la maitrise de ces documents et nous aimerions etre consultes avant toute diffusion des HowTo's. Si vous avez des questions, vous pouvez contacter Greg Hankins, le coordinateur des HowTo Linux HOWTO a l'adresse electronique suivante : gregh@sunsite.unc.edu 1100.. IInnddeexx Les entrees de cet index sont triees dans l'ordre alphabetique. +o -fwritable-strings ``39'', ``56'' +o /lib/cpp ``16'' +o a.out ``1'' +o ar ``10'' +o as ``8'' +o ``19'' +o atoi() ``40'' +o atol() ``41'' +o executables trop gros ``63'', ``65'', ``77'' +o chewing gum ``3'' +o cos() ``68'' +o deboguer ``59'' +o divers ``72'' +o dlopen() ``82'' +o dlsym() ``83'' +o documentation ``4'' +o EINTR ``52'' +o elf ``0'', ``71'' +o execl() ``57'' +o fcntl ``47'' +o FD_CLR ``44'' +o FD_ISSET ``45'' +o FD_SET ``43'' +o FD_ZERO ``46'' +o fichier ``2'' +o ``20'' +o gcc ``6'' +o gcc -fomit-frame-pointer ``61'' +o gcc -g ``60'' +o gcc -v ``14'' +o gcc, bogues ``15'', ``28'', ``29'', ``84'' +o gcc, options de compilation ``13'', ``25'', ``26'' +o gdb ``64'' +o fichiers d'en-tete ``17'' +o appels systemes interrompus ``51'' +o ld ``9'' +o LD_* : variables d'environnement ``80'' +o ldd ``81'' +o libc ``7'' +o libg.a ``62'' +o libgcc ``79'' +o ``21'' +o lint ``58'' +o ``18'' +o ``70'' +o maths ``69'' +o mktemp() ``55'' +o numero de version ``12'', ``74'' +o optimisation ``27'' +o pages de manuel ``5'' +o QMAGIC ``76'' +o segmentation fault ``30'', ``54'' +o segmentation fault, in GCC ``33'' +o select() ``50'' +o SIGBUS ``34'' +o SIGEMT ``35'' +o SIGIOT ``36'' +o SIGSEGV ``31'', ``53'' +o SIGSEGV, in gcc ``32'' +o SIGSYS ``38'' +o SIGTRAP ``37'' +o sin() ``67'' +o soname ``73'' +o sprintf() ``42'' +o binaires linkes statiquement ``66'', ``78'' +o ``23'' +o ``24'' +o strings ``11'' +o ``48'' +o ``49'' +o ``22'' +o ZMAGIC ``75'' .