<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <HTML> <HEAD> <TITLE>The Linux GCC HOWTO : Linking</TITLE> <LINK HREF="GCC-HOWTO-7.html" REL=next> <LINK HREF="GCC-HOWTO-5.html" REL=previous> <LINK HREF="GCC-HOWTO.html#toc6" REL=contents> </HEAD> <BODY> <A HREF="GCC-HOWTO-7.html">Avanti</A> <A HREF="GCC-HOWTO-5.html">Indietro</A> <A HREF="GCC-HOWTO.html#toc6">Indice</A> <HR> <H2><A NAME="s6">6. Linking</A></H2> <P>Questo paragrafo è piuttosto complicato a causa dei due formati binari incompatibili, la distinzione tra libreria statica e condivisa, e del sovraccarico del verbo 'link' che significa sia 'cosa accade dopo la compilazione', sia 'cosa accade quando viene richiamato un programma compilato' (e, di fatto, il sovraccarico del verbo 'load' in un senso simile ma opposto). <P>Per ridurre in qualche modo la confusione, si userà il termine `caricamento dinamico' (dynamic loading) per quello che accade durante l'esecuzione, argomento descritto nel prossimo paragrafo. Potrebbe anche accadere di trovare il termine 'collegamento dinamico' (dynamic linking) con lo stesso significato, ma non in questo documento. Questo paragrafo, quindi, tratta esclusivamente il tipo di link che avviene alla fine di una compilazione. <P> <H2><A NAME="ss6.1">6.1 Librerie condivise e statiche</A> </H2> <P>L'ultima fase della compilazione di un programma consiste nel 'collegamento' (link), ossia nell'unire tutte le parti e vedere se manca qualcosa. Ovviamente esistono alcune cose che molti programmi hanno in comune - ad esempio, aprire file, ed il codice in grado di fare queste cose sono fornite sotto forma di librerie. Nella maggior parte dei sistemi Linux si trovano in <CODE>/lib</CODE> e <CODE>/usr/lib/</CODE>. <P> <A NAME="index.65"></A> <A NAME="index.66"></A> <P> <P>Quando si utilizza una libreria statica, il linker trova le parti necessarie ai moduli di programma e le copia fisicamente nel file di output eseguibile che viene generato. Al contrario, questo non avviene per le librerie condivise - in questo caso nell'output viene inserita una nota del tipo 'quando viene eseguito questo programma, è necessario caricare questa libreria'. Ovviamente, le librerie condivise tendono a creare eseguibili di dimensioni minori; inoltre utilizzano una quantità inferiore di memoria e viene utilizzato meno spazio su disco. Il comportamento predefinito di Linux consiste nell'eseguire il collegamento di librerie condivise se esistono, altrimenti vengono utilizzate quelle statiche. Se si ottengono dei binari statici quando, al contrario, si vogliono quelli condivisi, controllare che i file di libreria condivisa (<CODE>*.sa</CODE> per a.out, <CODE>*.so</CODE> per ELF) si trovino dove dovrebbero essere e siano leggibili. <P>Su Linux, le librerie statiche hanno nomi come <CODE>libname.a</CODE>, mentre le librerie condivise sono denominate <CODE>libname.so.x.y.z</CODE> dove <CODE>x.y.z</CODE> rappresenta il numero di versione. Le librerie condivise, inoltre, contengono spesso dei collegamenti che puntano ad esse, che risultano essere molto importanti, e (in configurazioni a.out) contengono dei file <CODE>.sa</CODE> associati. Le librerie standard sono disponibili sia in formato condiviso, sia in formato statico. <P>È possibile sapere quali librerie condivise sono richieste da un programma utilizzando <CODE>ldd</CODE> (List Dynamic Dependencies) <P> <BLOCKQUOTE><CODE> <PRE> $ ldd /usr/bin/lynx libncurses.so.1 => /usr/lib/libncurses.so.1.9.6 libc.so.5 => /lib/libc.so.5.2.18 </PRE> </CODE></BLOCKQUOTE> <P>Questo esempio mostra che il browser WWW 'lynx' dipende dalla presenza di <CODE>libc.so.5</CODE> (la libreria C) e <CODE>libncurses.so.1</CODE> (utilizzata per il controllo del terminale). Se un programma non ha dipendenze, <CODE>ldd</CODE> risponderà 'statically linked' o 'statically linked (ELF)'. <P> <H2><A NAME="index.69"></A> <A NAME="index.68"></A> <A NAME="index.67"></A> <A NAME="ss6.2">6.2 Interrogazione delle librerie ('In quale libreria si trova sin()?')</A> </H2> <P><CODE>nm</CODE> <B>nome_libreria</B> dovrebbe listare tutti i simboli per i quali esistono dei riferimenti in <B>nome_libreria</B>. Il comando funziona sia per librerie statiche che dinamiche. Si supponga di voler saper dov'è definita <CODE>tcgetattr()</CODE>: si potrebbe utilizzare <P> <BLOCKQUOTE><CODE> <PRE> $ nm libncurses.so.1 |grep tcget U tcgetattr </PRE> </CODE></BLOCKQUOTE> <P>`<CODE>U</CODE>' significa 'undefined' - mostra che la libreria <CODE>ncurses</CODE> la utilizza ma non la definisce. In alternativa, si potrebbe usare <P> <BLOCKQUOTE><CODE> <PRE> $ nm libc.so.5 | grep tcget 00010fe8 T __tcgetattr 00010fe8 W tcgetattr 00068718 T tcgetpgrp </PRE> </CODE></BLOCKQUOTE> <P>`<CODE>W</CODE>' significa 'weak', ossia che il simbolo è definito, ma in modo tale da poter essere sostituito da un'altra definizione in una libreria diversa. Una definizione 'normale' (come quella per <CODE>tcgetpgrp</CODE>) è indicata con una '<CODE>T</CODE>'. <P> <A NAME="index.70"></A> <P> <P>Comunque la risposta breve alla domanda del titolo, consiste in <CODE>libm.(so|a)</CODE>. Tutte le funzioni definite in <CODE><math.h></CODE> sono tenute nella libreria <CODE>math</CODE>; ne consegue che sarà necessario eseguire il collegamento con l'opzione <CODE>-lm</CODE> quando si utilizza una di esse. <P> <H2><A NAME="ss6.3">6.3 Ricerca dei file</A> </H2> <P><CODE>ld: Output file requires shared library `libfoo.so.1`</CODE><BR> (Ovvero: "ld: Il file di output richiede la libreria condivisa 'libfoo.so.1'") <P>La strategia di ricerca di un file per ld e simili varia a seconda della versione, ma l'unico punto che si può ritenere predefinito è <CODE>/usr/lib</CODE>. Se si vuole che le librerie vengano cercate in altre locazioni, è necessario specificare le loro directory tramite l'opzione <CODE>-L</CODE> in gcc o ld. <P>Se non dovesse funzionare, controllare che i file necessari si trovino effettivamente in quelle directory. Per a.out, il collegamento con <CODE>-lfoo</CODE> fa in modo che ld cerchi <CODE>libfoo.sa</CODE> (condivisa) e, in caso di insuccesso, <CODE>libfoo.a</CODE> (statica). Per ELF, verrà eseguita la ricerca di <CODE>libfoo.so</CODE>, quindi di <CODE>libfoo.a</CODE>. <CODE>libfoo.so</CODE> è generalmente un collegamento simbolico a <CODE>libfoo.so.x</CODE>. <P> <H2><A NAME="ss6.4">6.4 Compilazione delle proprie librerie</A> </H2> <H3>Controllo della versione</H3> <P>Come qualunque altro programma, le librerie possono contenere errori che vengono riscontrati e risolti nel tempo. Inoltre, le librerie possono introdurre nuove caratteristiche, modificare l'effetto di altre esistenti, o rimuovere quelle vecchie. Questo potrebbe costituire un problema per i programmi che le utilizzano. <P>Pertanto si è introdutto il concetto di versione della libreria. Tutte le modifiche che possono essere fatte a una libreria sono catalogate in 'minori' o 'maggiori', dove una modifica 'minore' non interrompe il funzionamento dei vecchi programmi che la utilizzano. La versione di una libreria può essere dedotta dal suo nome di file (di fatto, questo non è vero per quanto riguarda ELF; nel seguito viene spiegato il motivo): <CODE>libfoo.so.1.2</CODE> ha '1' come versione maggiore, e '2' come minore. Il numero di versione minore può essere svariato - libc inserisce in esso il 'livello di patch', assegnando alle librerie nomi del tipo <CODE>libc.so.5.2.18</CODE>, e spesso sono utilizzate lettere, underscore, o quasi ogni altro carattere ASCII. <P>Una delle differenze principali tra il formato ELF e a.out consiste nel modo in cui viene eseguita la compilazione delle librerie condivise. Per prima cosa viene descritto ELF, dal momento che è più semplice. <P> <H3><A NAME="index.71"></A> ELF. Di cosa si tratta? </H3> <P>ELF (Executable and Linking Format) è un formato binario originariamente sviluppato da USL (UNIX System Laboratories) e attualmente utilizzato in Solaris e System V Release 4. A seguito della sua aumentata flessibilità rispetto al più vecchio formato a.out utilizzato da Linux, gli sviluppatori di librerie GCC e C hanno deciso lo scorso anno di utilizzare ELF come formato binario standard per Linux. <P> <H3>Uteriori dettagli</H3> <P>Questo paragrafo è tratto dal documento '<CODE>/news-archives/comp.sys.sun.misc</CODE>'. <P> <BLOCKQUOTE> ELF (Executable Linking Format) è il nuovo e migliorato formato di file oggetto introdotto in SVR4. ELF è molto più potente di COFF, nel fatto di essere estendibile dall'utente. ELF vede un file oggetto come una lista di sezioni arbitrariamente lunga (piuttosto che come un array di entità a lunghezza fissa), tali sezioni, a differenza di quanto accade in COFF, non si devono trovare in un luogo specifico e non devono essere in un ordine specifico ecc. Gli utenti possono aggiungere nuove sezioni ai file oggetto, se desiderano avere a disposizione nuovi dati. ELF, inoltre, possiede un formato di debugging molto più potente denominato DWARF (Debugging With Attribute Record Format) - attualmente non supportato completamente su Linux (ma ci si sta lavorando). Una lista linkata di DIE (o Debugging Information Entries) di DWARF costituisce la sezione <CODE>.debug</CODE> di ELF. Invece di essere un insieme di piccoli record a dimensione fissa, ogni DIE di DWARF contiene una lista di lunghezza arbitraria di attributi complessi ed è scritto come un albero di dati di programma. I DIE sono in grado di includere una quantità di informazioni di molto maggiore rispetto alla sezione <CODE>.debug</CODE> di COFF (come grafi di eredità del C++ ecc). </BLOCKQUOTE> <BLOCKQUOTE> L'accesso ai file ELF avviene tramite la libreria di accesso ELF SVR4 (Solaris 2.0 ?), che fornisce un'interfaccia semplice e rapida alle parti più complicate di ELF. Uno dei vantaggi principali derivanti dall'utilizzo della libreria di accesso ELF consiste nel fatto che non sarà mai necessario vedere un file ELF come file Unix, è possibile eseguire l'accesso come file Elf *, dopo una chiamata <CODE>elf_open()</CODE> si eseguono chiamate <CODE>elf_foobar()</CODE> sulle sue componenti invece di occuparsi della sua immagine effettiva su disco (cosa che con COFF si faceva impunemente). </BLOCKQUOTE> <P>I vantaggi e gli svantaggi di ELF, e le evoluzioni necessarie per eseguire l'upgrade di un sistema a.out per supportarlo, sono descritti nell'ELF-HOWTO e non ho intenzione di ripeterli qui. L'HOWTO dovrebbe essere disponibile nello stesso luogo in cui è stato trovato questo documento. <P> <H3>Librerie condivise di ELF</H3> <P>Per eseguire la compilazione di <CODE>libfoo.so</CODE> come libreria condivisa, i passi di base hanno la seguente forma: <P> <BLOCKQUOTE><CODE> <PRE> $ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 *.o $ ln -s libfoo.so.1.0 libfoo.so.1 $ ln -s libfoo.so.1 libfoo.so $ LD_LIBRARY_PATH='pwd':$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH </PRE> </CODE></BLOCKQUOTE> <P>Questi comandi genererano una libreria condivisa denominata <CODE>libfoo.so.1.0</CODE>, i collegamenti appropriati per ld (<CODE>libfoo.so</CODE>) e il caricamento dinamico (<CODE>libfoo.so.1</CODE>) per trovarla. Per eseguire un collaudo, si aggiunge la directory corrente a <CODE>LD_LIBRARY_PATH</CODE>. <P> <A NAME="index.72"></A> <P>Quando si è sicuri che la libreria funziona, deve essere spostata, ad esempio, in <CODE>/usr/local/lib</CODE>, e devono essere creati appropriati collegamenti. Il collegamento da <CODE>libfoo.so.1</CODE> a <CODE>libfoo.so.1.0</CODE> è mantenuto aggiornato da <CODE>ldconfig</CODE>, che nella maggior parte dei sistemi viene eseguito come parte del processo di avviamento. Il collegamento <CODE>libfoo.so</CODE> deve essere aggiornato manualmente. Se si è scrupolosi nell'eseguire l'aggiornamento di tutte le parti di una libreria (ossia degli header file) contemporaneamente, la cosa più semplice da fare consiste nel rendere <CODE>libfoo.so -> libfoo.so.1</CODE>, in modo che ldconfig mantenga correnti entrambi i collegamenti. In caso contrario, potrebbe in seguito verificarsi ogni genere di stranezza. <P> <BLOCKQUOTE><CODE> <PRE> $ su # cp libfoo.so.1.0 /usr/local/lib # /sbin/ldconfig # ( cd /usr/local/lib ; ln -s libfoo.so.1 libfoo.so ) </PRE> </CODE></BLOCKQUOTE> <P> <H3><A NAME="index.74"></A> <A NAME="index.73"></A> Numerazione delle versioni, soname e symlink </H3> <P>Ogni libreria ha un <B>soname</B>. Quando il linker trova uno di questi in una libreria in cui sta eseguendo una ricerca, nel binario viene incluso il soname in luogo del nome di file effettivo ricercato. Durante l'esecuzione, il loader dinamico cercherà un file tramite il nome di soname, non con il nome di file/libreria. Pertanto, una libreria denominata <CODE>libfoo.so</CODE> potrebbe avere il soname <CODE>libbar.so</CODE>, di conseguenza tutti i programmi collegati ad essa, all'avvio, cercherebbero <CODE>libbar.so</CODE>. <P>Sembra essere una caratteristica di poca importanza, invece è la chiave per capire come su un sistema possono coesistere diverse versioni della stessa libreria. Di fatto, la denominazione standard delle librerie in Linux consiste nel chiamare la libreria, ad esempio, <CODE>libfoo.so.1.2</CODE>, e assegnare ad essa il soname <CODE>libfoo.so.1</CODE>. Se aggiunta in una directory di libreria 'standard' (ossia, <CODE>/usr/lib</CODE>), ldconfig creerà un collegamento simbolico <CODE>libfoo.so.1 -> libfoo.so.1.2</CODE> in modo che sia possibile trovare l'immagine appropriata durante l'esecuzione. È necessario anche un collegamento <CODE>libfoo.so -> libfoo.so.1</CODE> affinché ld possa trovare il soname corretto da utilizzare durante il link. <P>Pertanto, quando si risolve un errore nella libreria, o si aggiungono nuove funzioni (ogni modifica che non influenzi in modo negativo i programmi esistenti), si eseguirà nuovamente la compilazione mantenendo lo stesso soname, e modificando il nome di file. Quando si inseriscono nella libreria delle modifiche che causerebbero l'interruzione dei programmi esistenti, incrementare semplicemente il numero nel soname - in questo caso, rinominare la nuova versione <CODE>libfoo.so.2.0</CODE>, e assegnarle il soname <CODE>libfoo.so.2</CODE>. Quindi, convertire il collegamento a <CODE>libfoo.so</CODE> in modo che punti alla nuova versione e tutto è a posto. <P>Si noti che non è <B>necessario</B> dare un nome alle librerie, ma si tratta di una buona convenzione. ELF fornisce una flessibilità nel nominare le librerie in modi che potrebbero confondere, ma questo non significa che debba farlo per forza. <P>Riassumendo: se si suppone di osservare la tradizione secondo cui gli aggiornamenti maggiori potrebbero distruggere la compatibilità e che quelli minori non lo fanno, eseguire il collegamento con <P> <BLOCKQUOTE><CODE> <PRE> gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor </PRE> </CODE></BLOCKQUOTE> <P>e tutto funzionerà alla perfezione. <P> <H3>a.out. Il formato tradizionale</H3> <P>La facilità con cui si esegue la compilazione di librerie condivise è uno dei motivi principali per passare a ELF. Detto questo, è ancora possibile utilizzare a.out. Si prenda <A HREF="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz">ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz</A> e si legga il documento di 20 pagine. <P> <H3><A NAME="index.76"></A> <A NAME="index.75"></A> ZMAGIC e QMAGIC </H3> <P>QMAGIC è un formato eseguibile proprio come i vecchi binari a.out (conosciuti anche come ZMAGIC), ma che lascia la prima pagina non mappata. Questo consente che accada più facilmente un riferimento NULL dal momento che non esiste alcun mapping nel range 0-4096. Come effetto collaterale, i binari saranno di dimensioni inferiori (di circa 1 K). <P>I linker obsoleti supportano solamente ZMAGIC, quelli semi-obsoleti supportano entrambi i formati, mentre le versioni attuali supportano solo QMAGIC. In realtà questo non ha importanza, dal momento che il kernel riesce ad eseguire entrambi i formati. <P>Il proprio comando 'file' dovrebbe essere in grado di identificare se un programma è QMAGIC. <P> <H3>Posizione dei file</H3> <P>Una libreria condivisa a.out (DLL) è formata da due file reali e da un collegamento simbolico. Per la libreria '<CODE>foo</CODE>' utilizzata come esempio, questi file sarebbero <CODE>libfoo.sa</CODE> e <CODE>libfoo.so.1.2</CODE>; il collegamento simbolico sarebbe <CODE>libfoo.so.1</CODE> e punterebbe all'ultimo di questi file. Ma a cosa servono? <P>Durante la compilazione, ld ricerca <CODE>libfoo.sa</CODE>. Si tratta del file 'matrice' della libreria, e contiene tutti i dati esportati e i puntatori alle funzioni richieste per il collegamento run time. <P>Durante l'esecuzione, il loader dinamico cerca <CODE>libfoo.so.1</CODE>. Si tratta di un collegamento simbolico anziché di un file reale in modo che le librerie possano essere aggiornate con versioni più recenti e corrette senza procurare danni a nessuna delle applicazioni utilizzanti la libreria in quel momento. Dopo che la nuova versione, ad esempio <CODE>libfoo.so.1.3</CODE> - è stata introdotta, l'esecuzione di ldconfig commuterà il collegamento affinché punti ad essa tramite un'operazione atomica, lasciando illeso ogni programma che stava utilizzando la vecchia versione. <P>Le librerie DLL appaiono spesso più grandi delle loro controparti statiche. Riservano spazio per future espansioni nella forma di 'buchi' che possono essere creati senza occupare spazio su disco. Una semplice chiamata <CODE>cp</CODE> o l'utilizzo del programma <CODE>makehole</CODE> raggiungerà questo scopo. Dopo la compilazione, è anche possibile rimuoverli, dal momento che gli indirizzi si trovano in locazioni fisse. Non tentare di rimuoverli dalle librerie ELF. <P> <H3>"libc-lite"?</H3> <P>Un libc-lite è una versione ridotta della libreria libc per la quale è stata eseguita la compilazione in modo tale da stare su un floppy disk ed essere sufficiente per tutti i task Unix essenziali. Non include codice <CODE>curse</CODE>, <CODE>dbm</CODE>, <CODE>termcap</CODE> ecc. Se il proprio <CODE>/lib/libc.so.4</CODE> ha un collegamento con un lite lib, il sistema avvisa di sostituirlo con una versione completa. <P> <H3>Linking: problemi comuni</H3> <P>Inviatemi i problemi derivanti dal linking! Anche se non potrò fare niente per risolverli, ne scriverò un resoconto dettagliato. <P> <DL> <DT><B>Programmi eseguono il link statico anziché dinamico</B><DD><P> <A NAME="index.77"></A> <A NAME="index.78"></A> <P>Controllare di avere i collegamenti corretti affinché ld possa trovare tutte le librerie condivise. Per ELF questo significa un collegamento simbolico <CODE>libfoo.so</CODE> per l'immagine, in a.out un file <CODE>libfoo.sa</CODE>. Molte persone hanno riscontrato questo problema dopo il passaggio dai binutils ELF 2.5 ai 2.6 - la versione precedente ricercava le librerie condivise in un modo 'più intelligente' pertanto non avevano bisogno di creare tutti i collegamenti. Il comportamento intelligente è stato eliminato per compatibilità con altre architetture, e perché molto spesso le sue supposizioni erano sbagliate e causando più guai di quanti fossero i problemi risolti. <P> <DT><B>Lo strumento DLL 'mkimage' non riesce a trovare libgcc</B><DD><P> <A NAME="index.79"></A> <P>Da <CODE>libc.so.4.5.x</CODE> e oltre, <CODE>libgcc</CODE> non è più condivisa. Pertanto, è necessario sostituire le occorrenze di '<CODE>-lgcc</CODE>' con '<CODE>gcc -print-libgcc-file-name</CODE>'. <P>Inoltre, bisogna cancellare tutti i file <CODE>/usr/lib/libgcc*</CODE>. Questo è molto importante. <P> <DT><B>Messaggi <CODE>__NEEDS_SHRLIB_libc_4 multiply defined</CODE></B><DD><P>Altra conseguenza del problema descritto al punto precedente. <P> <DT><B>Messaggio ``Assertion failure'' quando si ricompila una DLL?</B><DD><P>Questo messaggio criptico molto probabilmente significa che uno degli slot della propria jump table è andato in overflow poiché è stato riservato troppo poco spazio nel file jump.vars originale. È possibile localizzare i colpevoli eseguendo il comando '<CODE>getsize</CODE>' fornito nel pacchetto <CODE>tools-2.17.tar.gz</CODE>. Tuttavia, probabilmente l'unica soluzione consiste nel sostituire il numero di versione maggiore della libreria, forzandolo affinché sia impossibile tornare indietro. <P> <DT><B><CODE>ld: output file needs shared library libc.so.4</CODE></B><DD><P>Questo accade solitamente quando si sta eseguendo il collegamento con librerie diverse da libc (come le librerie X), e si utilizza l'opzione <CODE>-g</CODE> sulla riga di link utilizzando anche <CODE>-static</CODE>. <P>Gli stub <CODE>.sa</CODE> per le librerie condivise contengono solitamente un simbolo indefinito <CODE>_NEEDS_SHRLIB_libc_4</CODE> che viene risolto da <CODE>libc.sa</CODE>. Tuttavia, con <CODE>-g</CODE> si finisce di eseguire il collegamento con <CODE>libg.a</CODE> o <CODE>libc.a</CODE>, il simbolo non viene mai risolto, portando all'errore sopra descritto. <P>In conclusione, aggiungere <CODE>-static</CODE> quando si compila con l'opzione <CODE>-g</CODE>, oppure non eseguire il collegamento con <CODE>-g</CODE>. Molto spesso è possibile ottenere informazioni di debugging sufficienti compilando i file individuali con <CODE>-g</CODE>, ed eseguendo il collegamento senza questa opzione. <P> </DL> <P> <H2><A NAME="ss6.5">6.5 Loading dinamico</A> </H2> <P>Questo paragrafo è per il momento piuttosto breve, verrà esteso in futuro. <P> <H3>Concetti</H3> <P>Linux possiede delle librerie condivise, come si è visto diverse molte volte nell'ultimo paragrafo. Gran parte del lavoro di associazione dei nomi a locazioni, che tradizionalmente era svolto al momento del link, deve essere ritardato al momento del load (caricamento). <P> <H3>Messaggi di errore</H3> <P>I lettori sono pregati di inviare i proprii errori di link all'autore, che anche se non potrà risolverli, comunque scriverà un resoconto dettagliato. <P> <DL> <DT><B> <CODE>can't load library: /lib/libxxx.so, Incompatible version</CODE></B><DD><P>(solo in a.out) Questo significa che non si possiede la versione maggiore aggiornata della libreria xxx. Non è possibile semplicemente creare un collegamento simbolico ad un'altra versione che si possiede; nella migliore delle ipotesi questo causerà un segfault nel proprio programma. Si consiglia di ottenere una nuova versione. Una situazione simile in ELF produrrà un messaggio del tipo <P> <BLOCKQUOTE><CODE> <PRE> ftp: can't load library 'libreadline.so.2' </PRE> </CODE></BLOCKQUOTE> <P> <DT><B> <CODE>warning using incompatible library version xxx</CODE></B><DD><P>(solo in a.out) Si possiede una versione minore della libreria più vecchia di quella posseduta dalla persona che ha compilato il programma in questione. Il programma funzionerà comunque. Tuttavia, un aggiornamento non sarebbe una cattiva idea. <P> </DL> <P> <H3><A NAME="index.81"></A> <A NAME="index.80"></A> Controllo delle operazioni del loader dinamico </H3> <P>Esistono diverse variabili di ambiente a che influenzano il comportamento del loader dinamico. La maggior parte di esse sono più utili a <CODE>ldd</CODE> di quanto non lo siano per l'utente medio, e possono essere impostate eseguendo ldd con diverse opzioni. Includono <P> <UL> <LI> <CODE>LD_BIND_NOW</CODE> --- normalmente, le funzioni non sono ricercate nelle librerie finché non vengono chiamate. L'impostazione di questa opzione attiva la ricerca all'atto del caricamento della libreria, determinando un tempo di avviamento maggiore. Può essere utile quando si vuole collaudare un programma per accertarsi che sia eseguito il link di tutte le parti. </LI> <LI> <CODE>LD_PRELOAD</CODE> --- può essere impostato con un file contenente delle definizioni di funzioni da sovrapporre. Ad esempio, se si sta eseguendo un test delle strategie di allocazione della memoria, e si vuole sostituire 'malloc', è possibile scrivere la propria routine sostitutiva, compilarla come <CODE>malloc.o</CODE> e utilizzare i comandi <BLOCKQUOTE><CODE> <PRE> $ LD_PRELOAD=malloc.o; export LD_PRELOAD $ programma_di_test </PRE> </CODE></BLOCKQUOTE> <CODE>LD_ELF_PRELOAD</CODE> e <CODE>LD_AOUT_PRELOAD</CODE> sono simili, ma possono essere applicati solo al tipo binario appropriato. Se <CODE>LD_</CODE><B>qualcosa</B><CODE>_PRELOAD</CODE> e <CODE>LD_PRELOAD</CODE> sono entrambi impostati, verrà utilizzato quello più specifico. </LI> <LI> <CODE>LD_LIBRARY_PATH</CODE> --- elenco, separato da virgole, di directory in cui ricercare le librerie condivise. <B>Non</B> ha effetti su ld, ma solo durante l'esecuzione. Inoltre, è disabilitato per programmi che eseguono setuid o setgid. <CODE>LD_ELF_LIBRARY_PATH</CODE> e <CODE>LD_AOUT_LIBRARY_PATH</CODE> possono anche essere utilizzati per impostare la ricerca in modo differente per diversi tipi di binari. <CODE>LD_LIBRARY_PATH</CODE> non dovrebbe essere necessario nelle operazioni normali; piuttosto aggiungere le directory a <CODE>/etc/ld.so.conf/</CODE> ed eseguire ldconfig. </LI> <LI> <CODE>LD_NOWARN</CODE> --- si applica solo ad a.out. Quando impostato (ossia con <CODE>LD_NOWARN=true; export LD_NOWARN</CODE>) evita che il <I>loader</I> fornisca i warning non fatali (come i messaggi per incompatibilità di versione minore). </LI> <LI> <CODE>LD_WARN</CODE> --- si applica solamente a ELF. Quando impostato, rende i messaggi, solitamente fatali, "Can't find library" dei semplici warning. Non è molto utilizzato nelle operazioni normali, ma è importante per ldd. </LI> <LI> <CODE>LD_TRACE_LOADED_OBJECTS</CODE> --- si applica solamente a ELF, e fa in modo che i programmi credano di essere in esecuzione sotto ldd: <BLOCKQUOTE><CODE> <PRE> $ 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 </PRE> </CODE></BLOCKQUOTE> </LI> </UL> <P> <H3><A NAME="index.83"></A> <A NAME="index.82"></A> Scrivere programmi con il loading dinamico </H3> <P>Questo è molto simile al funzionamento del supporto di loading dinamico di Solaris 2.x. L'argomento è trattato ampiamente nel documento di programmazione ELF di H J Lu e nella pagina di manuale <CODE>dlopen(3) manual page</CODE>, che può essere trovata nel pacchetto ld.so. Segue un semplice esempio: è necessario effettuare il link con <CODE>-ldl</CODE> <P> <BLOCKQUOTE><CODE> <PRE> #include <dlfcn.h> #include <stdio.h> main() { void *libc; void (*printf_call)(); if(libc=dlopen("/lib/libc.so.5",RTLD_LAZY)) { printf_call=dlsym(libc,"printf"); (*printf_call)("hello, world\n"); } } </PRE> </CODE></BLOCKQUOTE> <P> <HR> <A HREF="GCC-HOWTO-7.html">Avanti</A> <A HREF="GCC-HOWTO-5.html">Indietro</A> <A HREF="GCC-HOWTO.html#toc6">Indice</A> </BODY> </HTML>