<!doctype linuxdoc system>

<!-- Questo è il Linux GCC HOWTO. Autore: Daniel Barlow
 dan@detached.demon.co.uk per la traduzione italiana:
 Andrea Girotto andrea.girotto@usa.net

   ?      Prima traduzione italiana eseguita da?
 Apr. 98: Adattamento alla versione sgml di Andrea Girotto.
          Varie correzioni.
 -->

<article OPTS="italian">

<title>The Linux GCC HOWTO 
<author><htmlurl url="dan@detached.demon.co.uk" 
name="Daniel Barlow (dan@detached.demon.co.uk)"> 
<date>v1.17, 28 Febbraio 1996

<abstract>
Questo documento tratta la configurazione del compilatore C 
GNU e delle librerie di sviluppo sotto Linux, e fornisce 
una panoramica sulla compilazione, il link, l'esecuzione 
e la correzione (debug) dei programmi. La maggior 
parte del materiale contenuto nel documento è stato preso 
dal GCC-FAQ di Mitch D'Souza, che sostituisce, o 
dall'<htmlurl url="http://sunsite.unc.edu/LDP/HOWTO/ELF-HOWTO" 
name="ELF-HOWTO"> (per la traduzione in italiano vedi 
<htmlurl url="http://www.pluto.linux.it/ildp/HOWTO/ELF-HOWTO.html" 
name="[1]">). Quella che state leggendo è 
la prima versione rilasciata pubblicamente (nonostante il numero). 
Ogni feedback è benvenuto.
Revisione e manutenzione della traduzione italiana:
<htmlurl url="mailto:andrea.girotto@usa.net" 
name="Andrea Girotto (andrea.girotto@usa.net)">
</abstract>
 
<toc>

<sect><heading>Preliminari
<sect1><heading>Confronto tra ELF e a.out<label id="index.0"><label id="index.1"> 

<p>
Lo sviluppo di Linux si trova attualmente in uno stato di 
continua evoluzione. Brevemente, esistono due formati di 
file binari che Linux è in grado di eseguire, ed a 
seconda di come è stato costruito, un sistema potrebbe
usare uno o l'altro dei due. Leggendo questo HOWTO si  
scoprirà quale.

<label id="index.2">

<p>
Per riconoscere il tipo di un binario è possibile utilizzare l'utility 
<tt/file/ (ad esempio: <tt>file /bin/bash</tt>). Per un programma ELF, darà 
una risposta contenente <tt/ELF/; per un programma <tt/a.out/ la risposta 
sarà qualcosa del tipo <tt>Linux/i386</tt>.
<p>
Le differenze tra ELF e a.out sono descritte ampiamente
in questo documento. ELF è il formato più recente, generalmente
ritenuto il migliore. 

<sect1><heading>Questioni amministrative
<p>
Informazioni riguardo al copyright si trovano alla fine di questo documento, 
insieme a dovute avvertenze relative a certe stupide domande poste su 
Usenet, che, segnalando problemi inesistenti, rivelano un'ignoranza 
del linguaggio C. 

<sect1><heading>Tipografia
<p>
La versione in formato Postscipt, dvi, o html, di questo documento
ha una maggiore varietà tipografica rispetto a quella in solo testo. In 
particolare, i nomi di file, i comandi, l'output dei comandi e gli stralci 
di codice sorgente sono impostati con un carattere tipo 
<tt>macchina da scrivere</tt>, come pure sono state messe in evidenza le 
&quot;variabili&quot; ed altre parti che dovevano essere <bf/enfatizzate/. 
<p>
Inoltre, è presente un utile indice. In dvi o postscript, la numerazione
dell'indice corrisponde a quella dei paragrafi. In HTML si tratta di 
numeri assegnati sequenzialmente che rimandano ad altre parti del
testo. Nella versione a solo testo, si tratta solo di numeri. 
Si consiglia una versione avanzata piuttosto che quella in modalità
testo.
<p>
Negli esempi viene utilizzata la sintassi dell'interprete dei comandi
(shell) Bourne (al posto di quella C). Gli utenti di C-shell 
potranno utilizzare il comando: 

<tscreen><verb>
% setenv FOO bar
</verb></tscreen>

al posto di:

<tscreen><verb>
$ FOO=bar; export FOO
</verb></tscreen>

Se il prompt mostrato è <tt/#/ invece di <tt/$/, il comando indicato 
probabilmente funzionerà solo se digitato come <bf/root/. Naturalmente, 
non si assumere alcuna responsabilità per qualsiasi cosa accada 
al sistema nell'utilizzo di questi esempi. 

<sect><heading>Dove ottenere quello che serve.
<sect1><heading>Questo documento.
<p>
Questo documento fa parte della serie dei Linux HOWTO, pertanto si 
può ottenere da tutti gli archivi di Linux HOWTO, come 
<htmlurl url="http://sunsite.unc.edu/pub/linux/docs/HOWTO/"
name="http://sunsite.unc.edu/pub/linux/docs/HOWTO/"> (le traduzioni
italiane sono disponibili presso <htmlurl
url="http://www.pluto.linux.it/ildp/"  
name="[2]">). La versione HTML in inglese può 
anche essere trovata (probabilmente leggermente più aggiornata) su <htmlurl 
url="http://ftp.linux.org.uk/~barlow/howto/gcc-howto.html"
name="http://ftp.linux.org.uk/~barlow/howto/gcc-howto.html">
(traduzione italiana <htmlurl
url="http://www.pluto.linux.it/ildp/HOWTO/GCC-HOWTO.html" 
name="[3]">).

<sect1><heading>Ulteriore documentazione.<label id="index.4">

<p>
La documentazione ufficiale di gcc si trova nella distribuzione sorgente 
(si veda sotto) sotto forma di file texinfo, e come file <tt/.info/. Se si 
dispone di una connessione di rete veloce, un cd-rom o una buona dose di 
pazienza, è possibile eseguirne l'<tt/untar/ e copiare le parti rilevanti in 
<tt>/usr/info</tt>. In caso contrario, possono essere trovati presso
<htmlurl url="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/"
name="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/">, ma non 
necessariamente si tratterà della versione più recente.

<label id="index.5">

<p>
Esistono due sorgenti di documentazione per libc. La GNU libc contiene dei 
file info che descrivono piuttosto accuratamente la libc Linux, fatta 
eccezione per stdio. Inoltre, le pagine di manuale dell'archivio 
<htmlurl url="ftp://sunsite.unc.edu/pub/Linux/docs/"
name="ftp://sunsite.unc.edu/pub/Linux/docs/"> sono state scritte per Linux 
e descrivono numerose chiamate di sistema (sezione 2) e funzioni 
libc (sezione 3).

<sect1><heading>GCC<label id="index.6">

<p>
La distribuzione ufficiale del GCC Linux può sempre essere trovata in 
formato binario (già compilato) all'indirizzo 
<htmlurl url="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/"
name="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/">. Nel momento in cui 
viene scritto questo documento, la versione più recente è la <it/2.7.2/
(<tt>gcc-2.7.2.bin.tar.gz</tt>).
<p>
È possibile ottenere la distribuzione sorgente più recente di GCC fornita 
dalla Free Software Foundation dagli archivi 
<htmlurl url="ftp://prep.ai.mit.edu/pub/gnu/"
name="ftp://prep.ai.mit.edu/pub/gnu/">. I gestori del GCC Linux hanno reso 
molto semplice la compilazione dell'ultima versione - il programma di 
configurazione (<tt/configure/) dovrebbe impostare tutto da solo. Si 
verifichi anche l'eventuale presenza di patch da applicare presso:
<htmlurl url="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/"
name="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/">.
<p>
Per compilare qualcosa di non banale (ma anche alcune cose banali) sarà 
necessario possedere anche quanto descritto nel paragrafo che segue. 

<sect1><heading>Libreria C e header file
<label id="index.7">

<p>
Quello che si desidera a questo punto dipende da due fattori: 

<enum>
<item>se il proprio sistema è ELF oppure a.out

<item>quale dei due si desidera avere. 
</enum>

Se si sta passando da libc 4 a libc 5, si raccomanda di leggere 
l'<htmlurl url="http://www.sunsite.unc.edu/HOWTO/ELF-HOWTO.html"
name="ELF-HOWTO">, rintracciabile più o meno nello stesso luogo in cui è 
stato trovato questo documento (traduzione italiana <htmlurl
url="http://www.pluto.linux.it/ildp/ELF-HOWTO.html"
name="[1]">). 
<p>
Da <htmlurl url="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/" 
name="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/"> 
sono disponibili:

<descrip>
<tag>libc-5.2.18.bin.tar.gz</tag> Immagini di librerie condivise ELF, librerie 
statiche e file include per le librerie C e matematiche.

<tag>libc-5.2.18.tar.gz</tag> Sorgenti per quanto descritto sopra. Sarà 
necessario anche il pacchetto <tt>.bin.</tt> per gli header file. Se 
si è indecisi tra compilarsi in proprio la 
libreria C o utilizzare il formato binario, la scelta migliore consiste
nell'usare il codice già compilato. Nel caso in cui si desideri il supporto
NIS o per le shadow password di dovrà comunque gestirli in prima persona. 

<tag>libc-4.7.5.bin.tar.gz</tag> Immagini di libreria condivisa <tt/a.out/
e librerie statiche per la versione 4.7.5 della libreria C e simili. 
Questo è stato studiato per coesistere con il pacchetto libc 5 sopra 
menzionato, ma è necessario solo se si desidera continuare a 
utilizzare o sviluppare programmi in formato a.out.
</descrip>

<sect1><heading>Strumenti associati (as, ld, ar, strings, ecc.)
<label id="index.8">
<label id="index.9">
<label id="index.10">
<label id="index.11">

<p>
Si possono trovare su <htmlurl 
url="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/"
name="ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/">, come ogni altra 
cosa sinora descritta. La versione corrente è 
<tt/binutils-2.6.0.2.bin.tar.gz/.
<p>
Le binutils sono disponibili unicamente in ELF, la versione corrente di 
libc si trova in ELF ed inoltre è meglio utilizzare la versione a.out di
libc in congiunzione con una ELF. Lo sviluppo della libreria C 
si sta muovendo verso ELF: se non c'è un particolare motivo
per l'utilizzo di a.out, si consiglia di fare altrettanto.

<sect><heading>Installazione e impostazione di GCC
<sect1><heading>Versioni GCC
<label id="index.12">
<label id="index.13">
<label id="index.14">
<p>
È possibile scoprire quale versione GCC si sta eseguendo digitando 
<tt>gcc -v</tt> alla richiesta dell'interprete comandi. Si tratta di un 
metodo piuttosto affidabile anche per scoprire se la propria impostazione 
è ELF o a.out. Il risultato potrebbe essere:

<tscreen><verb>
$ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
</verb></tscreen>

Le cose da notare sono:

<descrip>
<tag/i486/ Indica che il gcc è stato compilato per un processore 486 
- altre possibilità sono 386 o 586. Tutti i processori possono 
eseguire il codice compilato per ciascuna delle altre versioni; la 
differenza consiste nell'ottimizzazione che non ha effetti 
sulle prestazioni in un 386, ma rende il codice eseguibile leggermente più 
grande.

<tag/box/ Non è affatto importante, potrebbe esserci qualcosa di 
diverso (come <tt/slackware/ o <tt/debian/) o anche nulla (in tal caso, il 
nome di directory completa sarà <tt/i486-linux/). Se si esegue 
personalmente la compilazione di gcc, è possibile impostare questa 
caratteristica al momento della compilazione, a fini puramente estetici. 

<tag/linux/ In alternativa, potrebbe essere <tt/linuxelf/
o <tt/linuxaout/, il significato varia a seconda della versione 
utilizzata, fatto che potrebbe confondere le idee. 

<descrip>
<tag/linux/ significa ELF se la versione è la 2.7.0 o seguente, 
altrimenti significa a.out.

<tag/linuxaout/ significa a.out. È stato introdotto quando la definizione 
di <tt/linux/ è stata modificata da a.out in ELF, in modo che non sia
possibile vedere un gcc <tt/linuxaout/ più vecchio della versione 
2.7.0.

<label id="index.15">
<tag/linuxelf/ è obsoleto. Si tratta generalmente di una versione 
di gcc 2.6.3 impostata per produrre eseguibili ELF. Si noti che 
il gcc 2.6.3 contiene degli errori nella produzione di codice per 
ELF - si consiglia un aggiornamento.
</descrip>

<tag/2.7.2/ numero della versione.
</descrip>

In conclusione, si tratta di gcc 2.7.2 che produce del codice ELF.

<sect1><heading>Dov'è finito?
<p>
Se gcc è stato installato senza prestare attenzione, oppure se è stato 
ottenuto come parte di una distribuzione, potrebbe essere necessario 
scoprire dove si trova all'interno del filesystem. Le parti chiave sono:

<itemize>
<item> <tt>/usr/lib/gcc-lib/</tt><bf>destinazione</bf><tt>/</tt><bf>versione</bf><tt>/</tt> 
(e sottodirectory) posto in cui si trova la maggior parte del 
compilatore, i programmi eseguibili che effettuano la 
compilazione, alcune librerie e file include specifici per la versione che 
si sta utilizzando. 

<item> <tt>/usr/bin/gcc</tt> driver del compilatore - la parte che si  
esegue dalla riga di comando. Può essere utilizzato con diverse versioni di 
gcc, a patto che siano state installate più directory di compilatore (come 
descritto sopra). Per scoprire la versione predefinita, digitare 
<tt>gcc -v</tt>. Per forzare un'altra versione, digitare <tt>gcc -V</tt>
<bf/versione/. Ad esempio:

<tscreen><verb>
# gcc -v
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
gcc version 2.7.2
# gcc -V 2.6.3 -v
Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.6.3/specs
gcc driver version 2.7.2 executing gcc version 2.6.3
</verb></tscreen>

<item> <tt>/usr/</tt><bf>destinazione</bf><tt>/(bin|lib|include)/</tt>. Se sono 
stati installati più destinazioni (target) (ad esempio, a.out ed elf, o un
cross compilatore di qualche tipo), le librerie, le binutils (come <tt/as/,
<tt/ld/ o altri) e gli header file per destinazioni non native possono
essere trovati in questa posizione. Se è stato installato un solo tipo di 
gcc, diverse parti di esso sono poste o in questa directory o, 
alternativamente, in <tt>/usr/(bin|lib|include)</tt>.

<item> <tt>/lib/</tt>, <tt>/usr/lib</tt> e altre sono directory di libreria per 
il sistema nativo. Sarà anche necessaria la directory <tt>/lib/cpp</tt>
per molte applicazioni (ad esempio X ne fa un grande utilizzo) - è 
possibile copiarla da <tt>/usr/lib/gcc-lib/destinazione/versione/</tt>
o creare un collegamento (link) simbolico.

<label id="index.16">
</itemize>

<sect1><heading>Dove si trovano gli header file?
<label id="index.17"> 

<p>
Indipendentemente dalla posizione in cui sono stati installati i propri,
sotto <tt>/usr/local/include</tt>, esistono tre sorgenti principali degli 
header file in Linux:

<itemize>
<item>la maggior parte di <tt>/usr/include/</tt> e relative subdirectory 
sono sostituiti con il pacchetto binario di libc da H. J. Lu.  
In tali posizioni si potrebbero anche trovare file da altri sorgenti 
(librerie <bf/curses/ e <bf/dbm/, ad esempio) specialmente se si sta 
utilizzando la distribuzione libc più recente (che non contiene curses o 
dbm, come invece accadeva nelle più vecchie). 

<label id="index.18"> 
<label id="index.19"> 

<item><tt>/usr/include/linux</tt> e <tt>/usr/include/asm</tt> (per i file 
<tt>&lt;linux/*.h&gt;</tt> e <tt>&lt;asm/*.h&gt;</tt>) dovrebbero essere 
link simbolici alle directory <tt>linux/include/linux</tt> e 
<tt>linux/include/asm</tt> nella distribuzione sorgente del kernel. È 
necessario installarli se si pensa di eseguire lo sviluppo di un qualsiasi
programma non banale; non servono solo per la compilazione del kernel.
<p>
Potrebbe essere anche necessario eseguire il <tt>make config</tt> nelle 
directory del kernel dopo aver scaricato i sorgenti. Molti 
file dipendono da <tt>&lt;linux/autoconf.h&gt;</tt> che potrebbe non 
esistere, e in alcune versioni di kernel, <tt/asm/ è un link 
simbolico che viene creato al momento del <tt/make config/.  Pertanto, se 
si scaricano i sorgenti del kernel sotto <tt>/usr/src/linux</tt>:

<tscreen><verb>
$ cd /usr/src/linux
$ su
# make config
[rispondere alle domande. A meno che non si abbia intenzione di
 proseguire con la compilazione del kernel, la risposta non ha
 molta importanza]
# cd /usr/include
# ln -s ../src/linux/include/linux .
# ln -s ../src/linux/include/asm .
</verb></tscreen>

<label id="index.20">
<label id="index.21">
<label id="index.22">
<label id="index.23">
<label id="index.24">

<item>File come <tt>&lt;float.h&gt;</tt>, <tt>&lt;limits.h&gt;</tt>, 
<tt>&lt;varargs.h&gt;</tt>, <tt>&lt;stdarg.h&gt;</tt> e
<tt>&lt;stddef.h&gt;</tt> variano a seconda della versione del compilatore, 
pertanto si trovano in 
<tt>/usr/lib/gcc-lib/i486-box-linux/2.7.2/include/</tt>
e posizioni simili. 
</itemize>

<sect1><heading>Compilazione di cross compilatori
<sect2><heading>Linux come piattaforma di destinazione
<p>
Supponendo di aver ottenuto il codice sorgente per gcc, solitamente è 
sufficiente seguire le istruzioni contenute nel file <tt/INSTALL/
di GCC. Un comando <tt>configure -target=i486-linux -host=XXX</tt>
sulla piattaforma <tt/XXX/ seguito da un <tt/make/ dovrebbe funzionare. Si 
noti che saranno necessari gli include di Linux, gli include 
del kernel e sarà necessario eseguire anche la compilazione 
del cross assembler e del cross linker dai sorgenti in 
<htmlurl url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/"
name="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/">.

<sect3><heading>Linux come piattaforma sorgente, MSDOS come destinazione
<p>
Apparentemente dovrebbe essere possibile utilizzando il pacchetto 
"emx" o l'extender "go". Si invita a dare un'occhiata a
<htmlurl url="ftp://sunsite.unc.edu/pub/Linux/devel/msdos"
name="ftp://sunsite.unc.edu/pub/Linux/devel/msdos">.
<p>
L'autore, non ha ancora verificato le funzionalità e pertanto non può 
dare alcuna garanzia in merito.

<sect><heading>Il porting e la compilazione
<sect1><heading>Simboli definiti automaticamente
<label id="index.25">

<p>
È possibile elencare i simboli definiti automaticamente dalla propria 
versione di gcc eseguendolo con l'opzione <tt/-v/. Ad esempio:

<tscreen><verb>
$ echo 'main(){printf("hello world\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__ -
</verb></tscreen>

Se si sta scrivendo del codice che utilizza delle caratteristiche 
specifiche per Linux, è una buona idea includere le parti non portabili 
in 

<tscreen><verb>
#ifdef __linux__
/* ... altro codice ... */
#endif /* linux */
</verb></tscreen>

Si utilizzi <tt>__linux__</tt> per questo scopo, <bf/non/ semplicemente 
<tt>linux</tt>. Sebbene anche il secondo sia definito, non è conforme a 
POSIX.

<sect1><heading>Chiamata del compilatore
<p>
La documentazione per le opzioni del compilatore è rappresentata dalla 
info page di gcc (in Emacs, si utilizzi <tt>C-h i</tt> quindi si 
selezioni la voce 'gcc'). Il proprio distributore potrebbe non aver 
incluso questa parte nel sistema, o la versione che si possiede potrebbe 
essere vecchia; la cosa migliore da fare in questo caso consiste nello 
scaricare l'archivio sorgente gcc da 
<htmlurl url="ftp://prep.ai.mit.edu/pub/gnu"
name="ftp://prep.ai.mit.edu/pub/gnu"> o da uno dei suoi siti mirror.
<p>
La pagina di manuale gcc (<tt/gcc.1/) di solito è obsoleta. Tentando di
leggerla si troverà questo avvertimento. 

<sect2><heading>Opzioni del compilatore
<label id="index.26">
<label id="index.27">

<p>
L'output di gcc può essere ottimizzato aggiungendo <tt/-O/<bf/n/
alla sua riga di comando, dove <bf/n/ rappresenta un intero opzionale. I 
valori significativi di <bf/n/, ed il loro esatto effetto, variano a 
seconda della versione; tipicamente vanno da 0 (nessuna ottimizzazione) a 
2 (molte ottimizzazioni) a 3 (moltissime ottimizzazioni). 
<p>
Internamente, gcc le traduce in una serie di opzioni <tt/-f/ e <tt/-m/. È 
possibile vedere esattamente quale livello <tt/-O/ si lega a ogni opzione 
eseguendo <tt/gcc -v -Q/ (<tt/Q/ è un'opzione non documentata). 
Ad esempio, -O2 sul sistema dell'autore produce questo risultato:

<tscreen><verb>
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
</verb></tscreen>

L'utilizzo di un livello di ottimizzazione maggiore di quanto previsto 
per il proprio compilatore (ad esempio, -O6) avrà lo stesso 
risultato che utilizzare il livello più alto che è in grado di supportare. 
Tuttavia, la distribuzione di codice impostato per la compilazione in 
questo modo non è una buona idea - se in versioni future saranno 
incorporate ulteriori ottimizzazioni, potrebbe accadere che interrompano 
il proprio codice. 

<label id="index.28">
<p>
Gli utenti di gcc dalla versione 2.7.0 fino alla 2.7.2 dovrebbero notare 
che esiste un errore in -O2. In particolare, '<bf/-fstrenght-reduction/' 
non funziona. È disponibile una patch per risolvere questo problema, che
necessita della ricompilazione del gcc, altrimenti è sufficiente assicurarsi
di usare sempre l'opzione <tt/-fno-strength-reduce/.

<sect3><heading>Opzioni specifiche per il processore
<p>
Esistono altre opzioni <tt/-m/ che non sono attivate da nessun 
<tt/-O/, e si dimostrano utili in molti casi. Le principali 
sono <tt/-m386/ e <tt/-m486/, che indicano a gcc di favorire 
rispettivamente 386 o 486. Il codice compilato con una di queste due 
opzioni funzionerà anche su macchine dell'altro tipo; il codice 486 è più 
voluminoso, ma non è più lento se eseguito su 386.

Attualmente non esiste un'opzione <tt/-mpentium/ o <tt/-m586/.  Linus 
suggerisce di utilizzare 
<tt/-m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2/, per 
ottenere l'ottimizzazione del codice 486 ma senza i salti necessari per 
l'allineamento (di cui il pentium non ha bisogno). Michael Meissner (di 
Cygnus) dice:

<quote>
La mia impressione è che <tt/-mno-strength-reduce/ produca anche un codice più 
veloce sull'x86 (si noti che non mi sto riferendo all'errore relativo
all'opzione '-fstrength-reduction': altra questione). Ciò è dovuto
alla carenza di registri dell'x86 (ed il metodo di GCC di 
raggruppare i registri in registri sparsi piuttosto che in altri 
registri non aiuta molto). '<tt/strenght-reduce/' ha come effetto l'utilizzo 
di registri addizionali per sostituire moltiplicazioni con addizioni. 
Sospetto anche che <tt/-fcaller-saves/ possa causare una perdita di
prestazioni.
</quote>
<quote>
Un'altra considerazione consiste nel fatto che <tt/-fomit-frame-pointer/ possa 
o meno rappresentare un vantaggio. Da un lato, rende disponibile un altro 
registro per l'uso; tuttavia, il modo in cui x86 codifica il suo set di 
istruzioni comporta che gli indirizzi relativi di stack occupino più spazio 
rispetto agli indirizzi relativi di frame; di conseguenza, sarà 
disponibile ai programmi una quantità (leggermente) inferiore di Icache. 
Inoltre, <tt/-fomit-frame-pointer/ implica il continuo aggiustamento del 
puntatore allo stack da parte del compilatore, dopo ogni chiamata, 
quando, con un frame, può lasciare che lo stack esegua un accumulo per 
alcune chiamate. 
</quote>

L'ultima parola su questo argomento viene ancora da Linus:

<quote>
Se si desidera ottenere prestazioni ottimali, non credete alle mie parole,
effettuate delle prove. Esistono molte opzioni nel compilatore gcc, e può 
darsi che un insieme particolare dia l'ottimizzazione migliore per la 
propria impostazione.
</quote>

<sect2><heading>Internal compiler error: cc1 got fatal signal 11
<label id="index.29"> 
<label id="index.30"> 
<label id="index.31"> 
<label id="index.32"> 
<label id="index.33"> 

<p>
(Ovvero: "Errore interno del compilatore: cc1 ha ricevuto il segnale fatale 11").
<P>
Il segnale 11 è SIGSEGV, o 'segmentation violation'.  Solitamente 
significa che il programma ha confuso i puntatori e ha tentato di scrivere 
su una porzione di memoria che non possedeva. Potrebbe trattarsi di 
un errore di gcc.
<p>
Tuttavia, gcc è ben verificato ed affidabile, nella maggior 
parte dei casi. Utilizza anche un gran numero di strutture dati complesse, 
e una grande quantità di puntatori. In breve, è il miglior tester di 
RAM tra quelli disponibili comunemente. Se non è possibile replicare 
l'errore - il sistema non si ferma nello stesso punto quando si riavvia 
la compilazione - molto probabilmente si tratta di un problema legato 
all'hardware (CPU, memoria, scheda madre o cache). Non lo si deve 
considerare un errore del compilatore solo perché il proprio computer 
supera i controlli di avvio del sistema o è in grado di eseguire Windows o 
qualunque altro programma; questi 'test' sono comunemente ritenuti, a 
ragione, di nessun valore.  Comunque è sbagliato ritenere che si tratti di 
un errore, perché una compilazione del kernel si blocca sempre durante 
`<tt/make zImage/' - è logico che ciò accada: `<tt/make zImage/' 
probabilmente compila più di 200 file. In genere si ricerca un 
bug in un insieme più <bf/piccolo/ di così.
<p>
Se è possibile duplicare l'errore, e (ancora meglio) produrre un breve 
programma che lo dimostra, è possibile inviarlo come report di errori 
all'FSF, o alla mailing list di <tt/linux-gcc/. Si faccia riferimento 
alla documentazione di gcc per i dettagli relativi alle informazioni 
effettivamente necessarie.

<sect1><heading>Portabilità
<p>
È stato detto che, in questi giorni, se non può essere portato
a Linux, allora è qualcosa che non vale la pena di possedere. :-)
<p>
In generale, sono necessarie solo piccole modifiche per ottenere la 
conformità POSIX al 100% di Linux.  Sarebbe anche molto utile restituire 
agli autori ogni modifica al codice in modo che, in futuro, si possa
ottenere un eseguibile funzionante tramite il solo comando '<tt/make/'. 

<sect2><heading>BSD (inclusi bsd_ioctl, demone e &lt;sgtty.h&gt;)
<p>
È possibile compilare il proprio programma con <tt>-I/usr/include/bsd</tt>
ed eseguire il link con <tt>-lbsd</tt> (ossia, aggiungere 
<tt>-I/usr/include/bsd</tt> a <tt/CFLAGS/ e <tt>-lbsd</tt> alla riga 
<tt/LDFLAGS/ nel proprio <tt/Makefile/). Non è più necessario aggiungere 
<tt>-D__USE_BSD_SIGNAL</tt> se si desidera un comportamento dei segnali di 
tipo BSD, dal momento che questa caratteristica viene ottenuta 
automaticamente quando si ha <tt>-I/usr/include/bsd</tt> e l'include 
<tt>&lt;signal.h&gt;</tt>.

<sect2><heading>Segnali 'mancanti' (<tt/SIGBUS/, <tt/SIGEMT/,
<tt/SIGIOT/, <tt/SIGTRAP/, <tt/SIGSYS/ ecc) 
<label id="index.34"> 
<label id="index.35"> 
<label id="index.36"> 
<label id="index.37"> 
<label id="index.38"> 

<p>
Linux è conforme a POSIX. Quelli elencati nel seguito sono segnali non 
definiti in POSIX - ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), 
paragrafo B.3.3.1.1:

<quote>
"I segnali SIGBUS, SIGEMT, SIGIOT, SIGTRAP, e SIGSYS sono stati omessi da 
POSIX.1 perché il loro comportamento dipende dall'implementazione e non è 
stato possibile classificarlo adeguatamente. Implementazioni conformi 
potranno contenere questi segnali, ma devono documentare le circostanze in cui 
sono rilasciati ed elencare ogni restrizione riguardante il loro rilascio."
</quote>

Il modo più economico e scadente di gestire la cosa consiste nel ridefinire 
questi segnali in <tt/SIGUNUSED/. Il modo <bf/corretto/ consiste 
nell'inserire il codice che li gestisce in appropriati <tt>#ifdef</tt>

<tscreen><verb>
#ifdef SIGSYS
/* ... codice SIGSYS non-posix .... */
#endif
</verb></tscreen>

<sect2><heading>Codice K &amp; R
<label id="index.39"> 

<p>
GCC è un compilatore ANSI; una grande quantità di codice esistente non è 
ANSI. Non c'è molto da fare per risolvere questo problema, oltre 
all'aggiungere <tt/-traditional/ alle opzioni del compilatore. Si invita a 
consultare l'info page di gcc.
<p>
Si noti che <tt/-traditional/ ha altri effetti oltre a cambiare il 
linguaggio accettato da gcc. Ad esempio, attiva 
<tt>-fwritable-strings</tt>, che sposta le stringhe costanti nello spazio 
dati (dallo spazio di codice, dove non possono essere scritte). 
Questo aumenta l'occupazione di memoria del programma. 

<sect2><heading>Conflitto dei simboli di preprocessore con prototipi nel codice
<label id="index.40"> 
<label id="index.41"> 

<p>
Uno dei problemi più frequenti consiste nel fatto che alcune funzioni 
comuni sono definite come macro negli header file di Linux e il 
preprocessore si rifiuterà di eseguire il parsing di definizioni 
prototipo simili. I più comuni sono <tt/atoi()/ e <tt/atol()/.

<sect2><heading><tt>sprintf()</tt>
<label id="index.42"> 

<p>
Soprattutto quando si esegue il porting da SunOS, è necessario essere 
consapevoli del fatto che <tt>sprintf(string, fmt, ...)</tt> restituisce 
un puntatore a stringhe, mentre Linux (seguendo ANSI) restituisce il 
numero di caratteri che sono stati messi nella stringa.

<sect2><heading><tt/fcntl/ e affini. Quali sono le definizioni di 
<tt/FD_*/?
<label id="index.43"> 
<label id="index.44"> 
<label id="index.45"> 
<label id="index.46"> 
<label id="index.47"> 
<label id="index.48"> 
<label id="index.49"> 

<p>
Le definizioni si trovano in <tt>&lt;sys/time.h&gt;</tt>. Se si sta 
utilizzando <tt/fcntl/, probabilmente si vorrà includere anche 
<tt>&lt;unistd.h&gt;</tt>.
<p>
In genere, la pagina di manuale di una funzione elenca gli 
<tt>#include</tt> necessarie nella sua sezione SYNOPSIS.

<sect2><heading>Il timeout di <tt>select()</tt>.  Programmi in busy-waiting
<label id="index.50"> 

<p>
Una volta, il parametro timeout di <tt>select()</tt> era utilizzato a 
sola lettura. Già allora, le pagine di manuale avvertivano:

<quote>
select() dovrebbe probabilmente restituire il tempo rimanente dal timeout 
originale, se esistente, modificando il valore del tempo. Questo potrà essere 
implementato in versioni future del sistema. Pertanto, sarebbe sbagliato 
ritenere che il puntatore al timeout non sarà modificato dalla chiamata 
select().
</quote>

Ora il futuro è arrivato. Di ritorno da una <tt>select()</tt>, l'argomento 
di timeout sarà impostato al tempo rimanente che si sarebbe atteso se i 
dati non fossero arrivati. Se non è arrivato alcun dato, il valore sarà 
zero, e le chiamate future utilizzando la stessa struttura timeout 
eseguiranno immediatamente il return.
<p>
Per rimediare, in caso di errore, si metta il valore di timeout nella 
struttura ogni volta che si chiama <tt>select()</tt>. Si modifichi il 
codice come:

<code>
struct timeval timeout;
timeout.tv_sec = 1; timeout.tv_usec = 0;
while (some_condition)
	select(n,readfds,writefds,exceptfds,&amp;timeout);
</code>

in

<code>
struct timeval timeout;
while (some_condition) {
	timeout.tv_sec = 1; timeout.tv_usec = 0;
	select(n,readfds,writefds,exceptfds,&amp;timeout);
}
</code>

Alcune versioni di Mosaic evidenziavano questo problema. La velocità 
dell'animazione del globo rotante era inversamente correlata alla velocità 
con cui i dati giungevano dalla rete!

<sect2><heading>Chiamate di sistema interrotte
<label id="index.51"> 
<label id="index.52"> 

<sect3><heading>Sintomo

<p>
Quando un programma viene interrotto utilizzando <tt>Ctrl-Z</tt> e poi 
viene riavviato - o in altre situazioni che generano dei segnali: 
interruzione con <tt>Ctrl-C</tt>, terminazione di un processo figlio ecc. - 
si ottengono messaggi del tipo "interrupted system call" o "write: 
unknown error".

<sect3><heading>Problema

<p>
I sistemi POSIX controllano la presenza di segnali più frequentemente 
rispetto a sistemi UNIX più vecchi. Linux può eseguire dei gestori di 
segnali:

<itemize>
<item>in modo asincrono (tramite un timer)

<item>al ritorno da ogni chiamata di sistema

<item>durante l'esecuzione delle seguenti chiamate di sistema:
<tt>select()</tt>, <tt>pause()</tt>, <tt>connect()</tt>, 
<tt>accept()</tt>, <tt>read()</tt> su terminali, su socket, su
pipe o su file in <tt>/proc</tt>, <tt>write()</tt> su terminali, 
su socket, su pipe o sulla line printer; <tt>open()</tt>
su FIFO, su PTY o su linee seriali, <tt>ioctl()</tt> su terminali; 
<tt>fcntl()</tt> con il comando <tt>F_SETLKW</tt>; <tt>wait4()</tt>, 
<tt>syslog()</tt>, ogni operazione TCP o NFS.
</itemize>

Per altri sistemi operativi potrebbe essere necessario includere in questa 
lista le chiamate di sistema <tt>creat()</tt>, <tt>close()</tt>, 
<tt>getmsg()</tt>, <tt>putmsg()</tt>, <tt>msgrcv()</tt>, 
<tt>msgsnd()</tt>, <tt>recv()</tt>, <tt>send()</tt>, <tt>wait()</tt>, 
<tt>waitpid()</tt>, <tt>wait3()</tt>, <tt>tcdrain()</tt>, 
<tt>sigpause()</tt>, <tt>semop()</tt>. 
<p>
Se un segnale (per il quale il programma ha installato un gestore) avviene 
durante una chiamata di sistema, viene chiamato il gestore. Quando il 
gestore restituisce il controllo (alla chiamata di sistema), essa rileva 
che è stata interrotta e restituisce immediatamente -1 e 
<tt/errno = EINTR/. Il programma non si aspetta che questo accada, 
pertanto si blocca. 
<p>
È possibile scegliere tra due alternative, per rimediare.

<itemize>
<item>Per ogni gestore di segnali che viene installato, aggiungere 
<tt/SA_RESTART/ ai flag <tt/sigaction/. Per esempio, modificare 

<code>
signal (sig_nr, my_signal_handler);
</code>

in

<code>
signal (sig_nr, my_signal_handler);
{ struct sigaction sa;
  sigaction (sig_nr, (struct sigaction *)0, &amp;sa);
#ifdef SA_RESTART
  sa.sa_flags |= SA_RESTART;
#endif
#ifdef SA_INTERRUPT
  sa.sa_flags &= ~ SA_INTERRUPT;
#endif
  sigaction (sig_nr, &amp;sa, (struct sigaction *)0);
}
</code>

Si noti che mentre questo viene applicato alla maggior parte delle 
chiamate di sistema, è necessario controllare <tt/EINTR/ personalmente 
riguardo a <tt>read()</tt>, <tt>write()</tt>, <tt>ioctl()</tt>, 
<tt>select()</tt>, <tt>pause()</tt> e <tt>connect()</tt> . Si veda sotto.

<item>Controllare <tt/EINTR/ esplicitamente.
</itemize>

Seguono due esempi per <tt/read()/ e <tt/ioctl()/.
<p>
Una parte di codice originale utilizzante <tt/read()/

<code>
int result;
while (len > 0) {
	result = read(fd,buffer,len);
	if (result < 0) break;
	buffer += result; len -= result;
}
</code>

diventa

<code>
int result;
while (len > 0) {
	result = read(fd,buffer,len);
	if (result < 0) { if (errno != EINTR) break; }
	else { buffer += result; len -= result; }
}
</code>

e una parte di codice utilizzante <tt/ioctl()/

<code>
    int result;
    result = ioctl(fd,cmd,addr);
</code>

diventa

<code>
    int result;
    do { result = ioctl(fd,cmd,addr); }
    while ((result == -1) && (errno == EINTR));
</code>

Si noti che in alcune versioni di Unix BSD il comportamento predefinito 
consiste nel riavviare le chiamate di sistema. Per ottenere l'interruzione 
delle chiamate di sistema è necessario utilizzare i flag 
<tt/SV_INTERRUPT/ o <tt/SA_INTERRUPT/.

<sect2><heading>Stringhe scrivibili (il programma genera 'segmentation fault'  
in modo casuale)
<label id="index.53"> 
<label id="index.54"> 
<label id="index.55"> 
<label id="index.56"> 

<p>
GCC ha una visione ottimistica dei suoi utenti, considerando le costanti 
stringa esattamente quello che sono - delle costanti. Pertanto, le 
memorizza nell'area del codice, dove possono essere inserite ed estratte 
dall'immagine di disco del programma (invece di occupare uno
swapspace). Ne consegue che ogni tentativo di riscriverle
causerà 'segmentation fault'.
<p>
Questo può causare dei problemi a vecchi programmi che, per esempio 
eseguono una chiamata <tt>mktemp()</tt> con una stringa costante come 
argomento. <tt>mktemp()</tt> tenta di riscrivere il suo argomento.
<p>
Per correggere,
<itemize>
<item>compilare con l'opzione <tt>-fwritable-strings</tt>, per fare in modo 
che gcc posizioni le costanti nello spazio dati, oppure 

<item>riscrivere le parti che causano dei problemi per allocare una stringa 
non costante ed eseguire la <tt>strcpy</tt> dei dati in essa prima della 
chiamata.
</itemize>

<sect2><heading>Perché la chiamata <tt>execl()</tt> fallisce?
<label id="index.57"> 

<p>
Probabilmente accade perché viene eseguita in modo errato. Il primo 
argomento per <tt>execl</tt> è il nome del programma da eseguire. 
Il secondo e i successivi diventano l'array <tt/argv/ del programma 
che si sta chiamando. Ricordare che: <tt>argv[0]</tt> viene
impostato anche per un programma eseguito senza argomenti. Pertanto si 
dovrebbe scrivere 

<code>
    execl("/bin/ls","ls",NULL);
</code>

e non solo

<code>
    execl("/bin/ls", NULL);
</code>

L'esecuzione del programma senza nessun argomento è interpretata come un 
invito a stampare le sue dipendenze a librerie dinamiche, almeno 
utilizzando <tt>a.out</tt>. ELF si comporta diversamente. 
<p>
(Se si desidera questa informazione di libreria, esistono interfacce 
più semplici; si veda il paragrafo relativo al caricamento dinamico, o la 
pagina di manuale per <tt/ldd/).

<sect><heading>Debugging e Profiling

<sect1><heading>Manutenzione preventiva (lint)
<label id="index.58"> 

<p>
Non esiste un <tt/lint/ ampiamente utilizzato per Linux, dal momento che 
la maggior parte della gente si accontenta degli avvertimenti che 
gcc può generare. Probabilmente, quello più utile è il <tt>-Wall</tt> 
opzione che significa 'Warnings, all' ma probabilmente ha un maggior valore 
mnemonico, se pensato come qualcosa contro cui si sbatte la testa
(NdT. "wall" in inglese significa "muro").
<p>
Esiste un lint di dominio pubblico disponibile su 
<htmlurl url="ftp://larch.lcs.mit.edu/pub/Larch/lclint"
name="ftp://larch.lcs.mit.edu/pub/Larch/lclint">. Putroppo non sono in 
grado di giudicare la sua validità.

<sect1><heading>Debugging
<label id="index.59"> 

<sect2><heading>Come si ottengono le informazioni di debug in 
un programma?
<label id="index.60"> 
<label id="index.61"> 
<label id="index.62"> 

<p>
È necessario compilare ed eseguire il link di tutte le sue parti con 
l'opzione <tt/-g/, e senza <tt>-fomit-frame-pointer</tt>. Non è necessario 
ricompilarlo interamente, solo le parti di cui si esegue il debug.
<p>
Nelle configurazioni a.out le librerie condivise sono compilate con 
<tt>-fomit-frame-pointer</tt>, con la quale gdb non funzionerà. Questo 
perché l'opzione <tt>-g</tt> implica un link statico.
<p>
Se il linker va in errore fornendo un messaggio che indica 
l'impossibilità di trovare <tt/libg.a/, significa che non si possiede 
<tt>/usr/lib/libg.a</tt>, che consiste nella speciale libreria C abilitata 
al debugging. Tale libreria può essere fornita nel pacchetto binario 
libc, oppure (in versioni di libreria C più recenti) può essere necessario 
ottenere il codice sorgente libc ed eseguire personalmente la compilazione.
Tuttavia, è possibile ottenere sufficienti informazioni per la maggior 
parte degli scopi semplicemente sostituendola con un collegamento 
simbolico con <tt>/usr/lib/libc.a</tt>.

<sect3><heading>Come eliminarle?
<label id="index.63"> 

<p>
Molto software GNU è impostato affinché la compilazione e il link 
siano eseguite con l'opzione <tt/-g/, che determina la generazione di 
eseguibili molto voluminosi (e spesso statici). Questa non è una buona 
idea.
<p>
Se il programma possiede uno script di configurazione 
`<tt/autoconf/', è possibile disabilitare le informazioni di
debugging controllando il <tt/Makefile/. Naturalmente, se si sta 
utilizzando ELF, il link del programma viene eseguito in modo 
dinamico indipendentemente dall'impostazione <tt/-g/, pertanto si può 
semplicemente usare <tt/strip/.

<sect2><heading>Software disponibile
<label id="index.64"> 

<p>
Molte persone utilizzano gdb, che può essere ottenuto in forma sorgente 
dai siti di archivio GNU <htmlurl url="ftp://prep.ai.mit.edu/pub/gnu"
name="ftp://prep.ai.mit.edu/pub/gnu">, oppure in formato binario da 
<htmlurl url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC"
name="tsx-11 (ftp://tsx-11.mit.edu/pub/linux/packages/GCC)"> o da 
sunsite. <tt/xxgdb/ è un debugger X basato su gdb (ossia, è 
necessario che sia installato gdb). È possibile trovare i sorgenti presso 
<htmlurl url="ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz"
name="ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz">.
<p>
Rick Sladkey ha eseguito il porting del debugger UPS. Può essere 
eseguito anche sotto X, ma a differenza di <tt/xxgdb/, non è un semplice 
front end X per un debugger basato su testo. Possiede diverse 
caratteristiche molto interessanti, e se si ha la necessità di eseguire 
diversi debug, è il caso di provarlo. La versione precompilata per 
Linux e i patch per i sorgenti UPS possono essere trovati in 
<htmlurl url="ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/"
name="ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/">, mentre i 
sorgenti originali in <htmlurl 
url="ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z"
name="ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z">.
<p>
Un altro strumento utile per il debug è '<tt>strace</tt>', che 
visualizza le chiamate di sistema fatte da un processo. Questo strumento 
possiede anche molti altri utilizzi, inclusa la possibilità di sapere 
i nomi di file compilati, di cui non si possiede il sorgente; di esasperare
i race condition in programmi che si sospettano contenerle, e in 
generale di imparare come funzionano le cose. La versione più recente 
di <tt>strace</tt> (attualmente la 3.0.8) può essere trovata in 
<htmlurl url="ftp://ftp.std.com/pub/jrs/" 
name="ftp://ftp.std.com/pub/jrs/">.

<sect2><heading>Programmi background (demone)
<p>
I programmi demone tipicamente eseguono presto la <tt>fork()</tt>, e 
terminano il programma chiamante. Questo rende la sessione di debug 
molto breve.
<p>
Il modo più semplice per aggirare questo ostacolo consiste nell'impostare 
un breakpoint per <tt/fork/, e quando il programma si blocca, forzare 
la restituzione di 0. 

<tscreen><verb>
(gdb) list
1		#include <stdio.h>
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
Step singolo fino all'uscita dalla funzione fork,
che non contiene informazioni sul numero di riga.
child
7		}
</verb></tscreen>

<sect2><heading>Core file
<p>
Quando Linux viene avviato, solitamente è configurato per non produrre 
core file. Se si desidera, è possibile utilizzare il comando 
interno dell'interprete comandi per riabilitarli: per <it/shell/ 
compatibili C (come <tt/tcsh/) corrisponde al comando 

<tscreen><verb>
% limit core unlimited
</verb></tscreen>

mentre per interpreti comandi di tipo Bourne (<tt/sh/, <tt/bash/, <tt/zsh/, 
<tt/pdksh/) utilizzare

<tscreen><verb>
$ ulimit -c unlimited
</verb></tscreen>

Se si desidera una maggiore flessibilità nell'assegnazione dei nomi ai 
core file (nel caso, per esempio, di analisi post-mortem con
un debugger che contiene errori) è possibile eseguire una piccola 
modifica al proprio kernel. Cercare in <tt>fs/binfmt_aout.c</tt> e
<tt>fs/binfmt_elf.c</tt> il codice tipo:

<code>
  memcpy(corefile,"core.",5);
#if 0
  memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
  corefile[4] = '\0';
#endif
</code>

e modificare gli <tt/0/ in <tt/1/.

<sect1><heading>Profiling
<p>
Il profiling rappresenta un modo per esaminare le parti di un 
programma richiamate più frequentemente o eseguite più a lungo. È buona 
norma ottimizzare il codice e vedere dove viene perso del tempo. È 
necessario compilare tutti i file oggetto sui quali si desiderano 
informazioni sul tempo di esecuzione con l'opzione <tt/-p/, e per 
interpretare il file di output sarà necessario anche <tt/gprof/
(dal pacchetto binutils). Si veda la pagina di manuale <tt/gprof/
per ulteriori dettagli.

<sect><heading>Linking
<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. 

<sect1><heading>Librerie condivise e statiche
<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 <tt>/lib</tt> e 
<tt>/usr/lib/</tt>.

<label id="index.65"> 
<label id="index.66"> 

<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 (<tt/*.sa/ per a.out, 
<tt/*.so/ per ELF) si trovino dove dovrebbero essere e siano leggibili.
<p>
Su Linux, le librerie statiche hanno nomi come <tt>libname.a</tt>, mentre 
le librerie condivise sono denominate <tt>libname.so.x.y.z</tt> dove 
<tt>x.y.z</tt> 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 <tt/.sa/ 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 <tt/ldd/ (List Dynamic Dependencies)

<tscreen><verb>
$ ldd /usr/bin/lynx
        libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
        libc.so.5 => /lib/libc.so.5.2.18
</verb></tscreen>

Questo esempio mostra che il browser WWW 'lynx' dipende dalla 
presenza di <tt>libc.so.5</tt> (la libreria C) e <tt>libncurses.so.1</tt>
(utilizzata per il controllo del terminale). Se un programma non ha 
dipendenze, <tt>ldd</tt> risponderà 'statically linked'
o 'statically linked (ELF)'.

<sect1><heading>Interrogazione delle librerie 
('In quale libreria si trova sin()?')
<label id="index.67"> 
<label id="index.68"> 
<label id="index.69"> 

<p>
<tt/nm/ <bf/nome_libreria/ dovrebbe listare tutti i simboli per i 
quali esistono dei riferimenti in <bf/nome_libreria/. Il comando funziona 
sia per librerie statiche che dinamiche. Si supponga di voler saper dov'è 
definita <tt>tcgetattr()</tt>: si potrebbe utilizzare

<tscreen><verb>
$ nm libncurses.so.1 |grep tcget
         U tcgetattr
</verb></tscreen>

`<tt/U/' significa 'undefined' - mostra che la libreria <tt/ncurses/
la utilizza ma non la definisce. In alternativa, si potrebbe usare

<tscreen><verb>
$ nm libc.so.5 | grep tcget
00010fe8 T __tcgetattr
00010fe8 W tcgetattr
00068718 T tcgetpgrp
</verb></tscreen>

`<tt/W/' 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 
<tt/tcgetpgrp/) è indicata con una '<tt/T/'.

<label id="index.70"> 

<p>
Comunque la risposta breve alla domanda del titolo, consiste in 
<tt>libm.(so|a)</tt>. Tutte le funzioni definite in <tt>&lt;math.h&gt;</tt>
sono tenute nella libreria <tt>math</tt>; ne consegue che sarà 
necessario eseguire il collegamento con l'opzione <tt>-lm</tt> quando si 
utilizza una di esse. 

<sect1><heading>Ricerca dei file
<p>
<tt>ld: Output file requires shared library `libfoo.so.1`</tt><newline>
(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 è <tt>/usr/lib</tt>.  Se si vuole che le librerie vengano 
cercate in altre locazioni, è necessario specificare le loro directory 
tramite l'opzione <tt/-L/ 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 <tt/-lfoo/ fa in modo che ld cerchi <tt/libfoo.sa/
(condivisa) e, in caso di insuccesso, <tt/libfoo.a/ (statica). Per ELF, 
verrà eseguita la ricerca di <tt/libfoo.so/, quindi di <tt/libfoo.a/. 
<tt/libfoo.so/ è generalmente un collegamento simbolico a 
<tt/libfoo.so.x/.

<sect1><heading>Compilazione delle proprie librerie
<sect2><heading>Controllo della versione
<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): <tt/libfoo.so.1.2/
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 <tt/libc.so.5.2.18/, 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. 

<sect2><heading>ELF. Di cosa si tratta?
<label id="index.71"> 

<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. 

<sect3><heading>Uteriori dettagli
<p>
Questo paragrafo è tratto dal documento '<tt>/news-archives/comp.sys.sun.misc</tt>'.

<quote>
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 <tt/.debug/ 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 
<tt/.debug/ di COFF (come grafi di eredità del C++ ecc). 
</quote>
<quote>
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 <tt/elf_open()/ si eseguono chiamate 
<tt/elf_foobar()/ sulle sue componenti invece di occuparsi della sua immagine 
effettiva su disco (cosa che con COFF si faceva impunemente).
</quote> 

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. 

<sect3><heading>Librerie condivise di ELF
<p>
Per eseguire la compilazione di <tt>libfoo.so</tt> come libreria 
condivisa, i passi di base hanno la seguente forma:

<tscreen><verb>
$ 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
</verb></tscreen>

Questi comandi genererano una libreria condivisa denominata 
<tt/libfoo.so.1.0/, i collegamenti appropriati per ld (<tt/libfoo.so/) e 
il caricamento dinamico (<tt/libfoo.so.1/) per trovarla. Per eseguire un 
collaudo, si aggiunge la directory corrente a <tt/LD_LIBRARY_PATH/.

<label id="index.72"> 
<p>
Quando si è sicuri che la libreria funziona, deve essere spostata, 
ad esempio, in <tt>/usr/local/lib</tt>, e devono essere creati appropriati
collegamenti. Il collegamento da <tt/libfoo.so.1/ a <tt/libfoo.so.1.0/
è mantenuto aggiornato da <tt>ldconfig</tt>, che nella maggior parte dei 
sistemi viene eseguito come parte del processo di avviamento. Il
collegamento <tt/libfoo.so/ 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 <tt>libfoo.so -> libfoo.so.1</tt>, 
in modo che ldconfig mantenga correnti entrambi i collegamenti. In caso 
contrario, potrebbe in seguito verificarsi ogni genere di stranezza.

<tscreen><verb>
$ su
# cp libfoo.so.1.0 /usr/local/lib
# /sbin/ldconfig
# ( cd /usr/local/lib ; ln -s libfoo.so.1 libfoo.so )
</verb></tscreen>

<sect3><heading>Numerazione delle versioni, soname e symlink
<label id="index.73"> 
<label id="index.74"> 

<p>
Ogni libreria ha un <bf/soname/. 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 <tt/libfoo.so/ potrebbe avere il soname <tt/libbar.so/, di 
conseguenza tutti i programmi collegati ad essa, all'avvio, cercherebbero 
<tt/libbar.so/.
<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, <tt/libfoo.so.1.2/, e 
assegnare ad essa il soname <tt/libfoo.so.1/. Se aggiunta in una 
directory di libreria 'standard' (ossia, <tt>/usr/lib</tt>), 
ldconfig creerà un collegamento simbolico 
<tt>libfoo.so.1 -> libfoo.so.1.2</tt> in modo che sia possibile trovare 
l'immagine appropriata durante l'esecuzione. È necessario anche un 
collegamento <tt>libfoo.so -> libfoo.so.1</tt> 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 <tt/libfoo.so.2.0/, e assegnarle 
il soname <tt/libfoo.so.2/. Quindi, convertire il collegamento a 
<tt/libfoo.so/ in modo che punti alla nuova versione e tutto è a posto.
<p>
Si noti che non è <bf/necessario/ 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 

<tscreen><verb>
gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor
</verb></tscreen>

e tutto funzionerà alla perfezione.

<sect2><heading>a.out. Il formato tradizionale
<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 
<htmlurl 
url="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz"
name="ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz">
e si legga il documento di 20 pagine.

<sect3><heading>ZMAGIC e QMAGIC
<label id="index.75"> 
<label id="index.76"> 

<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.

<sect3><heading>Posizione dei file
<p>
Una libreria condivisa a.out (DLL) è formata da due file reali e da 
un collegamento simbolico. Per la libreria '<tt/foo/' utilizzata come 
esempio, questi file sarebbero <tt/libfoo.sa/ e <tt/libfoo.so.1.2/; 	
il collegamento simbolico sarebbe <tt/libfoo.so.1/ e punterebbe all'ultimo 
di questi file. Ma a cosa servono? 
<p>
Durante la compilazione, ld ricerca <tt/libfoo.sa/. 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 <tt/libfoo.so.1/. 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 
<tt/libfoo.so.1.3/ - è 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 <tt/cp/ o l'utilizzo del programma <tt/makehole/ 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.

<sect3><heading>"libc-lite"?
<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 <tt/curse/, <tt/dbm/, <tt/termcap/ ecc.  Se il proprio 
<tt>/lib/libc.so.4</tt> ha un collegamento con un lite lib, il 
sistema avvisa di sostituirlo con una versione completa.

<sect2><heading>Linking: problemi comuni
<p>
Inviatemi i problemi derivanti dal linking! Anche se non potrò fare
niente per risolverli, ne scriverò un resoconto dettagliato.

<descrip>
<tag>Programmi eseguono il link statico anziché dinamico</tag>
<label id="index.77"> 
<label id="index.78"> 

Controllare di avere i collegamenti corretti affinché ld possa trovare 
tutte le librerie condivise. Per ELF questo significa un collegamento
simbolico <tt/libfoo.so/ per l'immagine, in a.out un file <tt/libfoo.sa/. 
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.

<tag>Lo strumento DLL 'mkimage' non riesce a trovare libgcc</tag>
<label id="index.79"> 

Da <tt/libc.so.4.5.x/ e oltre, <tt/libgcc/ non è più condivisa. Pertanto, 
è necessario sostituire le occorrenze di '<tt/-lgcc/'
con '<tt/gcc -print-libgcc-file-name/'.
<p>
Inoltre, bisogna cancellare tutti i file <tt>/usr/lib/libgcc*</tt>. Questo 
è molto importante.

<tag>Messaggi <tt>__NEEDS_SHRLIB_libc_4 multiply defined</tt></tag> 
Altra conseguenza del problema descritto al punto precedente.

<tag>Messaggio ``Assertion failure'' quando si ricompila una DLL?</tag>
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 '<tt/getsize/' fornito nel pacchetto <tt/tools-2.17.tar.gz/. Tuttavia, 
probabilmente l'unica soluzione consiste nel sostituire il numero di 
versione maggiore della libreria, forzandolo affinché sia impossibile 
tornare indietro.

<tag><tt/ld: output file needs shared library libc.so.4/</tag>
Questo accade solitamente quando si sta eseguendo il collegamento con 
librerie diverse da libc (come le librerie X), e si utilizza l'opzione 
<tt/-g/ sulla riga di link utilizzando anche <tt/-static/.
<p>
Gli stub <tt/.sa/ per le librerie condivise contengono solitamente 
un simbolo indefinito <tt/_NEEDS_SHRLIB_libc_4/ che viene risolto da 
<tt/libc.sa/. Tuttavia, con <tt/-g/ si finisce di eseguire il 
collegamento con <tt/libg.a/ o <tt/libc.a/, il simbolo non 
viene mai risolto, portando all'errore sopra descritto.
<p>
In conclusione, aggiungere <tt>-static</tt> quando si compila con  
l'opzione <tt>-g</tt>, oppure non eseguire il collegamento con 
<tt>-g</tt>. Molto spesso è possibile ottenere informazioni di 
debugging sufficienti compilando i file individuali con 
<tt>-g</tt>, ed eseguendo il collegamento senza questa opzione.

</descrip>

<sect1><heading>Loading dinamico
<p>
Questo paragrafo è per il momento piuttosto breve, verrà 
esteso in futuro.

<sect2><heading>Concetti
<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). 

<sect2><heading>Messaggi di errore
<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.

<descrip>
<tag> <tt>can't load library: /lib/libxxx.so, Incompatible version</tt></tag>
(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

<tscreen><verb>
ftp: can't load library 'libreadline.so.2'
</verb></tscreen>

<tag> <tt>warning using incompatible library version xxx</tt></tag>
(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.

</descrip>

<sect2><heading>Controllo delle operazioni del loader dinamico
<label id="index.80"> 
<label id="index.81"> 

<p>
Esistono diverse variabili di ambiente a che influenzano il comportamento del
loader dinamico. La maggior parte di esse sono più utili a <tt/ldd/
di quanto non lo siano per l'utente medio, e possono essere impostate 
eseguendo ldd con diverse opzioni. Includono

<itemize>
<item> <tt/LD_BIND_NOW/ --- 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.

<item> <tt/LD_PRELOAD/ --- 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 <tt/malloc.o/ e utilizzare i comandi

<tscreen><verb>
$ LD_PRELOAD=malloc.o; export LD_PRELOAD
$ programma_di_test
</verb></tscreen>

<tt/LD_ELF_PRELOAD/ e <tt/LD_AOUT_PRELOAD/ sono simili, ma possono essere 
applicati solo al tipo binario appropriato. Se 
<tt/LD_/<bf/qualcosa/<tt/_PRELOAD/ e <tt/LD_PRELOAD/ sono entrambi impostati, 
verrà utilizzato quello più specifico.

<item> <tt/LD_LIBRARY_PATH/ --- elenco, separato da virgole, di 
directory in cui ricercare le librerie condivise. <bf/Non/ ha effetti 
su ld, ma solo durante l'esecuzione. Inoltre, è disabilitato per programmi che 
eseguono setuid o setgid. <tt/LD_ELF_LIBRARY_PATH/ e <tt/LD_AOUT_LIBRARY_PATH/
possono anche essere utilizzati per impostare la 
ricerca in modo differente per diversi tipi di binari. <tt/LD_LIBRARY_PATH/
non dovrebbe essere necessario nelle operazioni normali; piuttosto aggiungere 
le directory a <tt>/etc/ld.so.conf/</tt> ed eseguire ldconfig.

<item> <tt/LD_NOWARN/ --- si applica solo ad a.out. Quando impostato (ossia 
con <tt/LD_NOWARN=true; export LD_NOWARN/) evita che il <it/loader/ fornisca i 
warning non fatali (come i messaggi per incompatibilità di versione 
minore). 

<item> <tt/LD_WARN/ --- 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. 

<item> <tt/LD_TRACE_LOADED_OBJECTS/ --- si applica solamente a ELF, e fa in 
modo che i programmi credano di essere in esecuzione sotto ldd:

<tscreen><verb>
$ 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
</verb></tscreen>

</itemize>

<sect2><heading>Scrivere programmi con il loading dinamico
<label id="index.82"> 
<label id="index.83"> 

<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 
<tt>dlopen(3) manual page</tt>, che può essere trovata nel pacchetto 
ld.so. Segue un semplice esempio: è necessario effettuare il link con 
<tt>-ldl</tt>

<tscreen><verb>
#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");
    }

}
</verb></tscreen>

<sect><heading>Come contattare gli sviluppatori

<sect1><heading>Comunicazione degli errori
<label id="index.84"> 

<p>
Per prima cosa è necessario cominciare a <bf>circoscrivere il problema</bf>. È 
specifico di Linux, oppure accade con gcc su altri sistemi? È 
specifico della versione di kernel? Della versione di 
libreria? Sparisce se si esegue il link statico? È 
possibile ritagliare una piccola parte del programma che 
dimostra l'errore?
<p>
Fatto questo, si è a conoscenza del/i programma/i in cui 
si trova l'errore. Per GCC, la procedura di comunicazione 
degli errori è spiegata nel file <tt/info/. Per ld.so
o per le librerie C o maths, inviare una mail a 
<htmlurl url="mailto:linux-gcc@vger.rutgers.edu"
name="linux-gcc@vger.rutgers.edu">. Se possibile, includere un breve e 
autonomo programma che possa dimostrare l'errore, e una descrizione sia di 
cosa si intendeva che facesse, sia di cosa fa effettivamente.

<sect1><heading>Aiuto nello sviluppo 
<p>
Se si desidera aiutare lo sviluppo di GCC o della 
libreria C, la prima cosa da fare consiste nell'unirsi 
alla mailing list <htmlurl url="mailto:linux-gcc@vger.rutgers.edu"
name="linux-gcc@vger.rutgers.edu">. Se si vuole semplicemente dare un'occhiata 
alle discussioni, è possibile consultare 
<htmlurl url="http://homer.ncm.com/linux-gcc/"
name="http://homer.ncm.com/linux-gcc/">. La seconda cosa e le successive 
dipendono solo dalle vostre intenzioni!

<sect><heading>Ultime cose
<sect1><heading>Ringraziamenti
<p>
<quote>
Only presidents, editors, and people with tapeworms 
have the right to use the editorial "we".
(Mark Twain)
</quote>
<p>
Ovvero
<quote>
Soli i presidenti, gli editori e la gente con il verme solitario hanno
il diritto di usare il "noi" editoriale.
(Mark Twain)
</quote>
<p>
Questo HOWTO si basa molto strettamente al GCC-FAQ di 
Mitchum DSouza; la maggior parte delle informazioni (per 
non dire una grande quantità di testo) è derivato 
direttamente da quel documento. Esperienze riferite all'autore
all'interno di questo HOWTO potrebbero riferirsi anche a Mitchum DSouza;
generalmente le frasi del tipo 'Non 
si è mai collaudato questa parte; non maledite l'autore se il vostro 
disco/sistema si è abbrustolito' possono essere applicate 
a entrambi.
Inoltre hanno contribuito a questo documento (in 
ordine ASCII per nome):
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, 
e naturalmente Linus Torvalds, senza il quale 
l'intero lavoro non avrebbe avuto senso.
Vi prego di non sentirvi offesi se nella lista non 
compare il vostro nome e avete contribuito a questo 
documento (come HOWTO o come FAQ). Inviate mail ed 
sarà eseguita la correzione.

<sect1><heading>Traduzioni
<p>
Attualmente, non esistono traduzioni di questo documento 
Se desiderate farne una, siete liberi 
di farlo ma vi prego di farmelo sapere! Ci sono 
pochissime probabilità che io sia in grado di parlare la 
lingua in cui desiderate tradurre il documento, ma a 
parte questo sarei lieto di aiutarvi in qualsiasi modo.

<sect1><heading>Comunicazioni, opinioni, correzioni
<p>
Sono benvenute inviate email all'indirizzo 
<htmlurl url="mailto:dan@detached.demon.co.uk"
name="dan@detached.demon.co.uk">. La chiave pubblica PGP (ID 5F263625) è 
disponibile dalle pagine web dell'autore
<htmlurl url="http://ftp.linux.org.uk/~barlow/"
name="http://ftp.linux.org.uk/~barlow/">, se ci sono necessità di 
riservatezza. 

<sect1><heading>Informazioni legali
<p>
All trademarks used in this document are acknowledged as being owned
by their respective owners.  

This document is copyright (C) 1996 Daniel Barlow <htmlurl
url="mailto:dan@detached.demon.co.uk"
name="dan@detached.demon.co.uk">. It may be reproduced and distributed
in whole or in part, in any medium physical or electronic, as long as
this copyright notice is retained on all copies. Commercial
redistribution is allowed and encouraged; however, the author would
like to be notified of any such distributions. 
<P>
All translations, derivative works, or aggregate works incorporating
any Linux HOWTO documents must be covered under this copyright
notice. That is, you may not produce a derivative work from a HOWTO
and impose additional restrictions on its distribution. Exceptions to
these rules may be granted under certain conditions; please contact
the Linux HOWTO coordinator at the address given below.  
<p>
In short, we wish to promote dissemination of this information through
as many channels as possible. However, we do wish to retain copyright
on the HOWTO documents, and would like to be notified of any plans to
redistribute the HOWTOs.  
<P>
If you have questions, please contact Tim Bynum, the Linux HOWTO
coordinator, at <htmlurl url="mailto:linux-howto@sunsite.unc.edu"
name="linux-howto@sunsite.unc.edu">.  
<p>
<quote>
L'unica licenza valida &egrave quella originale in lingua
inglese. Di seguito ne trovate una traduzione abbastanza fedele che
per&ograve; non ha alcun valore.
</quote>
<P>
Tutti i marchi utilizzati in questo documento sono 
riconosciuti come appartenenti ai rispettivi proprietari.
<p>
Questo documento ha copyright (C) 1996 di Daniel Barlow 
<htmlurl url="mailto:dan@detached.demon.co.uk"
name="dan@detached.demon.co.uk">. Può essere riprodotto e distribuito 
completamente o in parte, su ogni mezzo fisico o elettronico, purché questo 
messaggio di copyright sia mantenuto in tutte le copie. È 
consentita e incoraggiata la ridistribuzione commerciale; 
tuttavia, l'autore gradirebbe essere informato su 
ciascuna di tali distribuzioni.
<P>
Tutte le traduzioni, lavori derivati, o lavori aggregati 
che includono un qualunque documento Linux deve essere 
coperto da questo messaggio di copyright. Ossia, non è 
possibile produrre un lavoro derivato da un HOWTO e 
imporre delle restrizioni addizionali sulla sua 
distribuzione. Eccezioni a queste regole possono essere 
ammesse sotto particolari condizioni; si prega di 
contattare il coordinatore degli HOWTO di Linux 
all'indirizzo sotto riportato.
<P>
In breve, desideriamo promuovere la diffusione di queste 
informazioni attraverso più canali possibile. Tuttavia, 
desideriamo anche mantenere il copyright sui documenti 
HOWTO, e vorremmo essere informati se qualcuno ha 
intenzione di ridistribuire gli HOWTO.
<p>
Se avete delle domande, contattate Tim Bynum, il 
coordinatore degli HOWTO di Linux, all'indirizzo 
<htmlurl url="mailto:linux-howto@sunsite.unc.edu"
name="linux-howto@sunsite.unc.edu"> tramite email.

<sect><heading>Riferimenti in italiano
<p>Questa sezione riporta riferimenti a documenti italiani. Nel caso
in cui un documento non sia ancora tradotto si rimanda al WEB
server del Pluto.

<itemize>
<item>&lsqb;1&rsqb; <htmlurl
url="http://www.pluto.linux.it/ildp/HOWTO/ELF-HOWTO.html" 
name="http://www.pluto.linux.it/ildp/HOWTO/ELF-HOWTO.html">

<item>&lsqb;2&rsqb; <htmlurl
url="http://www.pluto.linux.it/ildp/" 
name="http://www.pluto.linux.it/ildp/"> WEB server del
PLUTO, sono disponibili anche le traduzioni di altri HOWTO.

<item>&lsqb;3&rsqb; <htmlurl
url="http://www.pluto.linux.it/ildp/HOWTO/GCC-HOWTO.html"
name="http://www.pluto.linux.it/ildp/HOWTO/GCC-HOWTO.html">
</itemize>

<sect><heading>Indice Analitico
<p>

<!-- index.3 ha che vedere con la gomma da masticare: non inserito -->

<descrip>
<tag> <tt/-fwritable-strings/ </tag> 
<ref id="index.39" name="39"> <!-- OK -->
<ref id="index.56" name="56"> <!-- OK -->

<tag> /lib/cpp </tag> 
<ref id="index.16" name="16"> <!-- OK -->

<tag> a.out </tag> 
<ref id="index.1" name="1"> <!-- OK -->

<tag> <tt/ar/ </tag> 
<ref id="index.10" name="10"> <!-- OK -->

<tag> <tt/as/ </tag> 
<ref id="index.8" name="8"> <!-- OK -->

<tag> &lt;asm/*.h&gt; </tag> 
<ref id="index.19" name="19"> <!-- OK -->

<tag> <tt/atoi()/ </tag> 
<ref id="index.40" name="40"> <!-- OK -->

<tag> <tt/atol()/ </tag> 
<ref id="index.41" name="41"> <!-- OK -->

<tag> binaries too big </tag> 
<ref id="index.63" name="63"> <!-- OK -->
<ref id="index.65" name="65"> <!-- OK -->
<ref id="index.77" name="77"> <!-- OK -->

<tag> <tt/cos()/ </tag> 
<ref id="index.68" name="68"> <!-- OK -->

<tag> debugging </tag> 
<ref id="index.59" name="59"> <!-- OK -->

<tag> <tt/dlopen()/ </tag> 
<ref id="index.82" name="82"> <!-- OK -->

<tag> <tt/dlsym()/ </tag> 
<ref id="index.83" name="83"> <!-- OK -->

<tag> documentazione </tag> 
<ref id="index.4" name="4"> <!-- OK -->

<tag> EINTR </tag> 
<ref id="index.52" name="52"> <!-- OK -->

<tag> elf </tag> 
<ref id="index.0" name="0"> <!-- OK -->
<ref id="index.71" name="71"> <!-- OK -->

<tag> <tt/execl()/ </tag> 
<ref id="index.57" name="57"> <!-- OK -->

<tag> <tt/fcntl/ </tag> 
<ref id="index.47" name="47">    <!-- OK -->

<tag> <tt/FD_CLR/ </tag> 
<ref id="index.44" name="44">  <!-- OK -->

<tag> <tt/FD_ISSET/ </tag> 
<ref id="index.45" name="45">   <!-- OK -->

<tag> <tt/FD_SET/ </tag> 
<ref id="index.43" name="43"> <!-- OK -->

<tag> <tt/FD_ZERO/ </tag> 
<ref id="index.46" name="46">   <!-- OK -->

<tag> <tt/file/ </tag> 
<ref id="index.2" name="2"> <!-- OK -->

<tag> &lt;float.h&gt </tag> 
<ref id="index.20" name="20"> <!-- OK -->

<tag> gcc </tag> 
<ref id="index.6" name="6"> <!-- OK -->

<tag> <tt/gcc -fomit-frame-pointer/ </tag> 
<ref id="index.61" name="61"> <!-- OK -->

<tag> <tt/gcc -g/ </tag> 
<ref id="index.60" name="60"> <!-- OK -->

<tag> gcc -v </tag> 
<ref id="index.14" name="14"> <!-- OK -->

<tag> gcc, errori (bug) </tag> 
<ref id="index.15" name="15"> <!-- OK -->
<ref id="index.28" name="28"> <!-- OK -->
<ref id="index.29" name="29"> <!-- OK -->
<ref id="index.84" name="84"> <!-- OK -->

<tag> gcc, opzioni (flag) </tag> 
<ref id="index.13" name="13"> <!-- OK --> 
<ref id="index.25" name="25"> <!-- OK -->
<ref id="index.26" name="26"> <!-- OK -->

<tag> gdb </tag> 
<ref id="index.64" name="64"> <!-- OK -->

<tag> header file </tag> 
<ref id="index.17" name="17"> <!-- OK -->

<tag> chiamate a sistema interrotte </tag> 
<ref id="index.51" name="51"> <!-- OK -->

<tag> <tt/ld/ </tag> 
<ref id="index.9" name="9"> <!-- OK -->

<tag> <tt/LD_*/ variabili d'ambiente </tag> 
<ref id="index.80" name="80"> <!-- OK -->

<tag> ldd </tag> 
<ref id="index.81" name="81"> <!-- OK -->

<tag> libc </tag> 
<ref id="index.7" name="7"> <!-- OK -->

<tag> <tt/libg.a/ </tag> 
<ref id="index.62" name="62"> <!-- OK -->

<tag> libgcc </tag> 
<ref id="index.79" name="79"> <!-- OK -->

<tag> &lt;limits.h&gt; </tag> 
<ref id="index.21" name="21"> <!-- OK -->

<tag> lint </tag> 
<ref id="index.58" name="58"> <!-- OK -->

<tag> &lt;linux/*.h&gt; </tag> 
<ref id="index.18" name="18"> <!-- OK -->

<tag> pagine del manuale </tag> 
<ref id="index.5" name="5"> <!-- OK -->

<tag> <tt/&lt;math.h&gt;/ </tag> 
<ref id="index.70" name="70"> <!-- OK -->

<tag> maths </tag> 
<ref id="index.69" name="69"> <!-- OK -->

<tag> <tt/mktemp()/ </tag> 
<ref id="index.55" name="55"> <!-- OK -->

<tag> ottimizzazione </tag> 
<ref id="index.27" name="27"> <!-- OK -->

<tag> QMAGIC </tag> 
<ref id="index.76" name="76"> <!-- OK -->

<tag> segmentation fault </tag> 
<ref id="index.30" name="30"> <!-- OK -->
<ref id="index.54" name="54"> <!-- OK -->

<tag> segmentation fault, in GCC </tag> 
<ref id="index.33" name="33"> <!-- OK -->

<tag> select() </tag> 
<ref id="index.50" name="50"> <!-- OK -->

<tag> <tt/SIGBUS/ </tag> 
<ref id="index.34" name="34"> <!-- OK -->

<tag> <tt/SIGEMT/ </tag> 
<ref id="index.35" name="35"> <!-- OK -->

<tag> <tt/SIGIOT/ </tag> 
<ref id="index.36" name="36"> <!-- OK -->

<tag> SIGSEGV </tag> 
<ref id="index.31" name="31"> <!-- OK -->
<ref id="index.53" name="53"> <!-- OK -->

<tag> SIGSEGV, in gcc </tag> 
<ref id="index.32" name="32"> <!-- OK -->

<tag> <tt/SIGSYS/ </tag> 
<ref id="index.38" name="38"> <!-- OK -->

<tag> <tt/SIGTRAP/ </tag> 
<ref id="index.37" name="37"> <!-- OK -->

<tag> <tt/sin()/ </tag> 
<ref id="index.67" name="67"> <!-- OK -->

<tag> soname </tag> 
<ref id="index.73" name="73"> <!-- OK -->

<tag> <tt/sprintf()/ </tag> 
<ref id="index.42" name="42"> <!-- OK -->

<tag> librerie collegate staticamente, in modo inatteso </tag> 
<ref id="index.66" name="66"> <!-- OK -->
<ref id="index.78" name="78"> <!-- OK -->

<tag> &lt;stdarg.h&gt; </tag> 
<ref id="index.23" name="23"> <!-- OK -->

<tag> &lt;stddef.h&gt; </tag> 
<ref id="index.24" name="24"> <!-- OK -->

<tag> <tt/strings/ </tag> 
<ref id="index.11" name="11"> <!-- OK -->

<tag> <tt>&lt;sys/time.h&gt;</tt> </tag> 
<ref id="index.48" name="48"> <!-- OK -->

<tag> <tt>&lt;unistd.h&gt;</tt> </tag> 
<ref id="index.49" name="49"> <!-- OK -->

<tag> &lt;varargs.h&gt; </tag> 
<ref id="index.22" name="22"> <!-- OK -->

<tag> numeri di versione </tag> 
<ref id="index.12" name="12"> <!-- OK -->
<ref id="index.74" name="74"> <!-- OK -->

<tag> cose misteriose </tag> 
<ref id="index.72" name="72"> <!-- OK -->

<tag> ZMAGIC </tag> 
<ref id="index.75" name="75"> <!-- OK -->
</descrip>

</article>
