The Linux GCC HOWTO
 Daniel Barlow ([email protected])
 v1.17, 28 Febbraio 1996

 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'ELF-
 HOWTO (per la traduzione in italiano vedi [1]). Quella che state
 leggendo � la prima versione rilasciata pubblicamente (nonostante il
 numero). Ogni feedback � benvenuto.  Revisione e manutenzione della
 traduzione italiana: Andrea Girotto ([email protected])

 1.  Preliminari

 1.1.  Confronto tra ELF e a.out

 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.



 Per riconoscere il tipo di un binario � possibile utilizzare l'utility
 file (ad esempio: file /bin/bash). Per un programma ELF, dar� una
 risposta contenente ELF; per un programma a.out la risposta sar�
 qualcosa del tipo Linux/i386.

 Le differenze tra ELF e a.out sono descritte ampiamente in questo
 documento. ELF � il formato pi� recente, generalmente ritenuto il
 migliore.


 1.2.  Questioni amministrative

 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.


 1.3.  Tipografia

 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
 macchina da scrivere, come pure sono state messe in evidenza le
 "variabili" ed altre parti che dovevano essere enfatizzate.

 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.

 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:



 % setenv FOO bar




 al posto di:



      $ FOO=bar; export FOO




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


 2.  Dove ottenere quello che serve.

 2.1.  Questo documento.

 Questo documento fa parte della serie dei Linux HOWTO, pertanto si pu�
 ottenere da tutti gli archivi di Linux HOWTO, come
 http://sunsite.unc.edu/pub/linux/docs/HOWTO/ (le traduzioni italiane
 sono disponibili presso [2]). La versione HTML in inglese pu� anche
 essere trovata (probabilmente leggermente pi� aggiornata) su
 http://ftp.linux.org.uk/~barlow/howto/gcc-howto.html (traduzione
 italiana [3]).


 2.2.  Ulteriore documentazione.

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



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


 2.3.  GCC

 La distribuzione ufficiale del GCC Linux pu� sempre essere trovata in
 formato binario (gi� compilato) all'indirizzo
 ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/. Nel momento in cui
 viene scritto questo documento, la versione pi� recente � la 2.7.2
 (gcc-2.7.2.bin.tar.gz).

 � possibile ottenere la distribuzione sorgente pi� recente di GCC
 fornita dalla Free Software Foundation dagli archivi
 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 (configure) dovrebbe impostare tutto da solo. Si
 verifichi anche l'eventuale presenza di patch da applicare presso:
 ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/.

 Per compilare qualcosa di non banale (ma anche alcune cose banali)
 sar� necessario possedere anche quanto descritto nel paragrafo che
 segue.


 2.4.  Libreria C e header file

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


 1. se il proprio sistema � ELF oppure a.out

 2. quale dei due si desidera avere.

 Se si sta passando da libc 4 a libc 5, si raccomanda di leggere l'ELF-
 HOWTO, rintracciabile pi� o meno nello stesso luogo in cui � stato
 trovato questo documento (traduzione italiana [1]).

 Da ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/ sono disponibili:


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


    libc-5.2.18.tar.gz
       Sorgenti per quanto descritto sopra. Sar� necessario anche il
       pacchetto .bin. 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.


    libc-4.7.5.bin.tar.gz
       Immagini di libreria condivisa 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.


 2.5.



 Strumenti associati (as, ld, ar, strings, ecc.)

 Si possono trovare su ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/,
 come ogni altra cosa sinora descritta. La versione corrente �
 binutils-2.6.0.2.bin.tar.gz.

 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.





 3.  Installazione e impostazione di GCC

 3.1.


 Versioni GCC

 � possibile scoprire quale versione GCC si sta eseguendo digitando gcc
 -v 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:



      $ gcc -v
      Reading specs from /usr/lib/gcc-lib/i486-box-linux/2.7.2/specs
      gcc version 2.7.2




 Le cose da notare sono:


    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.


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


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


       linux
          significa ELF se la versione � la 2.7.0 o seguente,
          altrimenti significa a.out.


       linuxaout
          significa a.out. � stato introdotto quando la definizione di
          linux � stata modificata da a.out in ELF, in modo che non sia
          possibile vedere un gcc linuxaout pi� vecchio della versione
          2.7.0.


       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.

    2.7.2
       numero della versione.

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


 3.2.  Dov'� finito?

 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:


 �  /usr/lib/gcc-lib/destinazione/versione/ (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.

 �  /usr/bin/gcc 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 gcc -v. Per forzare un'altra versione, digitare gcc -V
    versione. Ad esempio:



      # 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





 �  /usr/destinazione/(bin|lib|include)/. 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 as, 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 /usr/(bin|lib|include).

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



 3.3.  Dove si trovano gli header file?

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


 �  la maggior parte di /usr/include/ 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 curses e 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).




 �  /usr/include/linux e /usr/include/asm (per i file <linux/*.h> e
    <asm/*.h>) dovrebbero essere link simbolici alle directory
    linux/include/linux e linux/include/asm 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.

    Potrebbe essere anche necessario eseguire il make config nelle
    directory del kernel dopo aver scaricato i sorgenti. Molti file
    dipendono da <linux/autoconf.h> che potrebbe non esistere, e in
    alcune versioni di kernel, asm � un link simbolico che viene creato
    al momento del make config.  Pertanto, se si scaricano i sorgenti
    del kernel sotto /usr/src/linux:



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










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


 3.4.  Compilazione di cross compilatori

 3.4.1.  Linux come piattaforma di destinazione

 Supponendo di aver ottenuto il codice sorgente per gcc, solitamente �
 sufficiente seguire le istruzioni contenute nel file INSTALL di GCC.
 Un comando configure -target=i486-linux -host=XXX sulla piattaforma
 XXX seguito da un 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
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/.


 3.4.1.1.  Linux come piattaforma sorgente, MSDOS come destinazione

 Apparentemente dovrebbe essere possibile utilizzando il pacchetto
 "emx" o l'extender "go". Si invita a dare un'occhiata a
 ftp://sunsite.unc.edu/pub/Linux/devel/msdos.
 L'autore, non ha ancora verificato le funzionalit� e pertanto non pu�
 dare alcuna garanzia in merito.


 4.  Il porting e la compilazione

 4.1.  Simboli definiti automaticamente

 � possibile elencare i simboli definiti automaticamente dalla propria
 versione di gcc eseguendolo con l'opzione -v. Ad esempio:



      $ 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__ -




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



      #ifdef __linux__
      /* ... altro codice ... */
      #endif /* linux */




 Si utilizzi __linux__ per questo scopo, non semplicemente linux.
 Sebbene anche il secondo sia definito, non � conforme a POSIX.


 4.2.  Chiamata del compilatore

 La documentazione per le opzioni del compilatore � rappresentata dalla
 info page di gcc (in Emacs, si utilizzi C-h i 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 ftp://prep.ai.mit.edu/pub/gnu o
 da uno dei suoi siti mirror.

 La pagina di manuale gcc (gcc.1) di solito � obsoleta. Tentando di
 leggerla si trover� questo avvertimento.


 4.2.1.

 Opzioni del compilatore

 L'output di gcc pu� essere ottimizzato aggiungendo -On alla sua riga
 di comando, dove n rappresenta un intero opzionale. I valori
 significativi di 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).

 Internamente, gcc le traduce in una serie di opzioni -f e -m. �
 possibile vedere esattamente quale livello -O si lega a ogni opzione
 eseguendo gcc -v -Q (Q � un'opzione non documentata).  Ad esempio, -O2
 sul sistema dell'autore produce questo risultato:



      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




 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.


 Gli utenti di gcc dalla versione 2.7.0 fino alla 2.7.2 dovrebbero
 notare che esiste un errore in -O2. In particolare, '-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 -fno-strength-
 reduce.


 4.2.1.1.  Opzioni specifiche per il processore

 Esistono altre opzioni -m che non sono attivate da nessun -O, e si
 dimostrano utili in molti casi. Le principali sono -m386 e -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 -mpentium o -m586.  Linus suggerisce
 di utilizzare -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:


      La mia impressione � che -mno-strength-reduce produca anche
      un codice pi� veloce sull'x86 (si noti che non mi sto rifer�
      endo 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). 'strenght-reduce' ha come effetto l'utilizzo di reg�
      istri addizionali per sostituire moltiplicazioni con
      addizioni.  Sospetto anche che -fcaller-saves possa causare
      una perdita di prestazioni.



      Un'altra considerazione consiste nel fatto che -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, -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.


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


      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 par�
      ticolare dia l'ottimizzazione migliore per la propria
      impostazione.



 4.2.2.  Internal compiler error: cc1 got fatal signal 11

 (Ovvero: "Errore interno del compilatore: cc1 ha ricevuto il segnale
 fatale 11").

 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.

 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 `make zImage' - � logico che ci� accada: `make
 zImage' probabilmente compila pi� di 200 file. In genere si ricerca un
 bug in un insieme pi� piccolo di cos�.

 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 linux-gcc. Si faccia riferimento alla
 documentazione di gcc per i dettagli relativi alle informazioni
 effettivamente necessarie.


 4.3.  Portabilit�

 � stato detto che, in questi giorni, se non pu� essere portato a
 Linux, allora � qualcosa che non vale la pena di possedere. :-)

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

 4.3.1.  BSD (inclusi bsd_ioctl, demone e <sgtty.h>)

 � possibile compilare il proprio programma con -I/usr/include/bsd ed
 eseguire il link con -lbsd (ossia, aggiungere -I/usr/include/bsd a
 CFLAGS e -lbsd alla riga LDFLAGS nel proprio Makefile). Non � pi�
 necessario aggiungere -D__USE_BSD_SIGNAL se si desidera un
 comportamento dei segnali di tipo BSD, dal momento che questa
 caratteristica viene ottenuta automaticamente quando si ha
 -I/usr/include/bsd e l'include <signal.h>.


 4.3.2.  SIGIOT , SIGTRAP , SIGSYS  ecc) Segnali 'mancanti' ( SIGBUS ,
 SIGEMT ,

 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:


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


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



      #ifdef SIGSYS
      /* ... codice SIGSYS non-posix .... */
      #endif





 4.3.3.  Codice K & R

 GCC � un compilatore ANSI; una grande quantit� di codice esistente non
 � ANSI. Non c'� molto da fare per risolvere questo problema, oltre
 all'aggiungere -traditional alle opzioni del compilatore. Si invita a
 consultare l'info page di gcc.

 Si noti che -traditional ha altri effetti oltre a cambiare il
 linguaggio accettato da gcc. Ad esempio, attiva -fwritable-strings,
 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.


 4.3.4.  Conflitto dei simboli di preprocessore con prototipi nel
 codice

 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 atoi() e atol().



 4.3.5.  sprintf()

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


 4.3.6.  fcntl  e affini. Quali sono le definizioni di FD_* ?

 Le definizioni si trovano in <sys/time.h>. Se si sta utilizzando
 fcntl, probabilmente si vorr� includere anche <unistd.h>.

 In genere, la pagina di manuale di una funzione elenca gli #include
 necessarie nella sua sezione SYNOPSIS.


 4.3.7.  Il timeout di select() .  Programmi in busy-waiting

 Una volta, il parametro timeout di select() era utilizzato a sola
 lettura. Gi� allora, le pagine di manuale avvertivano:


      select() dovrebbe probabilmente restituire il tempo rima�
      nente dal timeout originale, se esistente, modificando il
      valore del tempo. Questo potr� essere implementato in ver�
      sioni future del sistema. Pertanto, sarebbe sbagliato
      ritenere che il puntatore al timeout non sar� modificato
      dalla chiamata select().


 Ora il futuro � arrivato. Di ritorno da una select(), 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.

 Per rimediare, in caso di errore, si metta il valore di timeout nella
 struttura ogni volta che si chiama select(). Si modifichi il codice
 come:


 ______________________________________________________________________
 struct timeval timeout;
 timeout.tv_sec = 1; timeout.tv_usec = 0;
 while (some_condition)
         select(n,readfds,writefds,exceptfds,&timeout);
 ______________________________________________________________________



 in


 ______________________________________________________________________
 struct timeval timeout;
 while (some_condition) {
         timeout.tv_sec = 1; timeout.tv_usec = 0;
         select(n,readfds,writefds,exceptfds,&timeout);
 }
 ______________________________________________________________________



 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!


 4.3.8.  Chiamate di sistema interrotte

 4.3.8.1.  Sintomo

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


 4.3.8.2.  Problema

 I sistemi POSIX controllano la presenza di segnali pi� frequentemente
 rispetto a sistemi UNIX pi� vecchi. Linux pu� eseguire dei gestori di
 segnali:


 �  in modo asincrono (tramite un timer)

 �  al ritorno da ogni chiamata di sistema

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

 Per altri sistemi operativi potrebbe essere necessario includere in
 questa lista le chiamate di sistema creat(), close(), getmsg(),
 putmsg(), msgrcv(), msgsnd(), recv(), send(), wait(), waitpid(),
 wait3(), tcdrain(), sigpause(), semop().

 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
 errno = EINTR. Il programma non si aspetta che questo accada, pertanto
 si blocca.

 � possibile scegliere tra due alternative, per rimediare.


 �  Per ogni gestore di segnali che viene installato, aggiungere
    SA_RESTART ai flag sigaction. Per esempio, modificare


    ___________________________________________________________________
    signal (sig_nr, my_signal_handler);
    ___________________________________________________________________



 in








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



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

 �  Controllare EINTR esplicitamente.

 Seguono due esempi per read() e ioctl().

 Una parte di codice originale utilizzante read()


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



 diventa


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



 e una parte di codice utilizzante ioctl()


 ______________________________________________________________________
     int result;
     result = ioctl(fd,cmd,addr);
 ______________________________________________________________________



 diventa


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



 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 SV_INTERRUPT o SA_INTERRUPT.


 4.3.9.  Stringhe scrivibili (il programma genera 'segmentation fault'
 in modo casuale)

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

 Questo pu� causare dei problemi a vecchi programmi che, per esempio
 eseguono una chiamata mktemp() con una stringa costante come
 argomento. mktemp() tenta di riscrivere il suo argomento.

 Per correggere,

 �  compilare con l'opzione -fwritable-strings, per fare in modo che
    gcc posizioni le costanti nello spazio dati, oppure

 �  riscrivere le parti che causano dei problemi per allocare una
    stringa non costante ed eseguire la strcpy dei dati in essa prima
    della chiamata.


 4.3.10.  Perch� la chiamata execl()  fallisce?

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


 ______________________________________________________________________
     execl("/bin/ls","ls",NULL);
 ______________________________________________________________________



 e non solo


 ______________________________________________________________________
     execl("/bin/ls", NULL);
 ______________________________________________________________________



 L'esecuzione del programma senza nessun argomento � interpretata come
 un invito a stampare le sue dipendenze a librerie dinamiche, almeno
 utilizzando a.out. ELF si comporta diversamente.

 (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 ldd).


 5.  Debugging e Profiling

 5.1.  Manutenzione preventiva (lint)

 Non esiste un 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 -Wall 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").

 Esiste un lint di dominio pubblico disponibile su
 ftp://larch.lcs.mit.edu/pub/Larch/lclint. Putroppo non sono in grado
 di giudicare la sua validit�.


 5.2.  Debugging

 5.2.1.  Come si ottengono le informazioni di debug in un programma?

 � necessario compilare ed eseguire il link di tutte le sue parti con
 l'opzione -g, e senza -fomit-frame-pointer. Non � necessario
 ricompilarlo interamente, solo le parti di cui si esegue il debug.

 Nelle configurazioni a.out le librerie condivise sono compilate con
 -fomit-frame-pointer, con la quale gdb non funzioner�. Questo perch�
 l'opzione -g implica un link statico.

 Se il linker va in errore fornendo un messaggio che indica
 l'impossibilit� di trovare libg.a, significa che non si possiede
 /usr/lib/libg.a, 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 /usr/lib/libc.a.


 5.2.1.1.  Come eliminarle?

 Molto software GNU � impostato affinch� la compilazione e il link
 siano eseguite con l'opzione -g, che determina la generazione di
 eseguibili molto voluminosi (e spesso statici). Questa non � una buona
 idea.

 Se il programma possiede uno script di configurazione `autoconf', �
 possibile disabilitare le informazioni di debugging controllando il
 Makefile. Naturalmente, se si sta utilizzando ELF, il link del
 programma viene eseguito in modo dinamico indipendentemente
 dall'impostazione -g, pertanto si pu� semplicemente usare strip.


 5.2.2.  Software disponibile

 Molte persone utilizzano gdb, che pu� essere ottenuto in forma
 sorgente dai siti di archivio GNU ftp://prep.ai.mit.edu/pub/gnu,
 oppure in formato binario da tsx-11
 (ftp://tsx-11.mit.edu/pub/linux/packages/GCC) o da sunsite. xxgdb � un
 debugger X basato su gdb (ossia, � necessario che sia installato gdb).
 � possibile trovare i sorgenti presso
 ftp://ftp.x.org/contrib/xxgdb-1.08.tar.gz.

 Rick Sladkey ha eseguito il porting del debugger UPS. Pu� essere
 eseguito anche sotto X, ma a differenza di 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 ftp://sunsite.unc.edu/pub/Linux/devel/debuggers/, mentre i
 sorgenti originali in ftp://ftp.x.org/contrib/ups-2.45.2.tar.Z.

 Un altro strumento utile per il debug � 'strace', 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 strace (attualmente la 3.0.8) pu� essere trovata in
 ftp://ftp.std.com/pub/jrs/.


 5.2.3.  Programmi background (demone)

 I programmi demone tipicamente eseguono presto la fork(), e terminano
 il programma chiamante. Questo rende la sessione di debug molto breve.

 Il modo pi� semplice per aggirare questo ostacolo consiste
 nell'impostare un breakpoint per fork, e quando il programma si
 blocca, forzare la restituzione di 0.



      (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               }





 5.2.4.  Core file

 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 shell compatibili C
 (come tcsh) corrisponde al comando



      % limit core unlimited




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



      $ ulimit -c unlimited




 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 fs/binfmt_aout.c e
 fs/binfmt_elf.c il codice tipo:


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



 e modificare gli 0 in 1.


 5.3.  Profiling

 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 -p, e per
 interpretare il file di output sar� necessario anche gprof (dal
 pacchetto binutils). Si veda la pagina di manuale gprof per ulteriori
 dettagli.


 6.  Linking

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

 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.


 6.1.  Librerie condivise e statiche

 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 /lib e /usr/lib/.





 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 (*.sa per a.out, *.so per
 ELF) si trovino dove dovrebbero essere e siano leggibili.

 Su Linux, le librerie statiche hanno nomi come libname.a, mentre le
 librerie condivise sono denominate libname.so.x.y.z dove x.y.z
 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 .sa associati. Le librerie standard sono disponibili sia in
 formato condiviso, sia in formato statico.

 � possibile sapere quali librerie condivise sono richieste da un
 programma utilizzando ldd (List Dynamic Dependencies)



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




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


 6.2.  Interrogazione delle librerie ('In quale libreria si trova
 sin()?')

 nm nome_libreria dovrebbe listare tutti i simboli per i quali esistono
 dei riferimenti in nome_libreria. Il comando funziona sia per librerie
 statiche che dinamiche. Si supponga di voler saper dov'� definita
 tcgetattr(): si potrebbe utilizzare
      $ nm libncurses.so.1 |grep tcget
               U tcgetattr




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



      $ nm libc.so.5 | grep tcget
      00010fe8 T __tcgetattr
      00010fe8 W tcgetattr
      00068718 T tcgetpgrp




 `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 tcgetpgrp) �
 indicata con una 'T'.




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


 6.3.  Ricerca dei file

 ld: Output file requires shared library `libfoo.so.1`
 (Ovvero: "ld: Il file di output richiede la libreria condivisa
 'libfoo.so.1'")

 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 �
 /usr/lib.  Se si vuole che le librerie vengano cercate in altre
 locazioni, � necessario specificare le loro directory tramite
 l'opzione -L in gcc o ld.

 Se non dovesse funzionare, controllare che i file necessari si trovino
 effettivamente in quelle directory. Per a.out, il collegamento con
 -lfoo fa in modo che ld cerchi libfoo.sa (condivisa) e, in caso di
 insuccesso, libfoo.a (statica). Per ELF, verr� eseguita la ricerca di
 libfoo.so, quindi di libfoo.a.  libfoo.so � generalmente un
 collegamento simbolico a libfoo.so.x.


 6.4.  Compilazione delle proprie librerie

 6.4.1.  Controllo della versione

 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.

 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): 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 libc.so.5.2.18, e spesso sono utilizzate lettere, underscore,
 o quasi ogni altro carattere ASCII.

 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.


 6.4.2.  ELF. Di cosa si tratta?

 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.


 6.4.2.1.  Uteriori dettagli

 Questo paragrafo � tratto dal documento '/news-
 archives/comp.sys.sun.misc'.


      ELF (Executable Linking Format) � il nuovo e migliorato for�
      mato 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 denomi�
      nato DWARF (Debugging With Attribute Record Format) -
      attualmente non supportato completamente su Linux (ma ci si
      sta lavorando). Una lista linkata di DIE (o Debugging Infor�
      mation Entries) di DWARF costituisce la sezione .debug di
      ELF.  Invece di essere un insieme di piccoli record a dimen�
      sione 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 .debug di COFF (come grafi di eredit�
      del C++ ecc).



      L'accesso ai file ELF avviene tramite la libreria di accesso
      ELF SVR4 (Solaris 2.0 ?), che fornisce un'interfaccia sem�
      plice 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 neces�
      sario vedere un file ELF come file Unix, � possibile
      eseguire l'accesso come file Elf *, dopo una chiamata
      elf_open() si eseguono chiamate elf_foobar() sulle sue com�
      ponenti invece di occuparsi della sua immagine effettiva su
 disco (cosa che con COFF si faceva impunemente).



 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.


 6.4.2.2.  Librerie condivise di ELF

 Per eseguire la compilazione di libfoo.so come libreria condivisa, i
 passi di base hanno la seguente forma:



      $ 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




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



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



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





 6.4.2.3.  Numerazione delle versioni, soname e symlink

 Ogni libreria ha un 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 libfoo.so potrebbe avere il soname libbar.so, di
 conseguenza tutti i programmi collegati ad essa, all'avvio,
 cercherebbero libbar.so.

 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,
 libfoo.so.1.2, e assegnare ad essa il soname libfoo.so.1. Se aggiunta
 in una directory di libreria 'standard' (ossia, /usr/lib), ldconfig
 creer� un collegamento simbolico libfoo.so.1 -> libfoo.so.1.2 in modo
 che sia possibile trovare l'immagine appropriata durante l'esecuzione.
 � necessario anche un collegamento libfoo.so -> libfoo.so.1 affinch�
 ld possa trovare il soname corretto da utilizzare durante il link.

 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
 libfoo.so.2.0, e assegnarle il soname libfoo.so.2. Quindi, convertire
 il collegamento a libfoo.so in modo che punti alla nuova versione e
 tutto � a posto.

 Si noti che non � 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.

 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



      gcc -shared -Wl,-soname,libfoo.so.major -o libfoo.so.major.minor




 e tutto funzioner� alla perfezione.


 6.4.3.  a.out. Il formato tradizionale

 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
 ftp://tsx-11.mit.edu/pub/linux/packages/GCC/src/tools-2.17.tar.gz e si
 legga il documento di 20 pagine.


 6.4.3.1.  ZMAGIC e QMAGIC

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

 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.

 Il proprio comando 'file' dovrebbe essere in grado di identificare se
 un programma � QMAGIC.


 6.4.3.2.  Posizione dei file

 Una libreria condivisa a.out (DLL) � formata da due file reali e da un
 collegamento simbolico. Per la libreria 'foo' utilizzata come esempio,
 questi file sarebbero libfoo.sa e libfoo.so.1.2; il collegamento
 simbolico sarebbe libfoo.so.1 e punterebbe all'ultimo di questi file.
 Ma a cosa servono?

 Durante la compilazione, ld ricerca 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.

 Durante l'esecuzione, il loader dinamico cerca 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
 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.

 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 cp o l'utilizzo del programma 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.


 6.4.3.3.  "libc-lite"?

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


 6.4.4.  Linking: problemi comuni

 Inviatemi i problemi derivanti dal linking! Anche se non potr� fare
 niente per risolverli, ne scriver� un resoconto dettagliato.


    Programmi eseguono il link statico anzich� dinamico



       Controllare di avere i collegamenti corretti affinch� ld possa
       trovare tutte le librerie condivise. Per ELF questo significa un
       collegamento simbolico libfoo.so per l'immagine, in a.out un
       file 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.
    Lo strumento DLL 'mkimage' non riesce a trovare libgcc


       Da libc.so.4.5.x e oltre, libgcc non � pi� condivisa. Pertanto,
       � necessario sostituire le occorrenze di '-lgcc' con 'gcc
       -print-libgcc-file-name'.

       Inoltre, bisogna cancellare tutti i file /usr/lib/libgcc*.
       Questo � molto importante.


    Messaggi __NEEDS_SHRLIB_libc_4 multiply defined
       Altra conseguenza del problema descritto al punto precedente.


    Messaggio ``Assertion failure'' quando si ricompila una DLL?
       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 'getsize' fornito nel pacchetto 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.


    ld: output file needs shared library libc.so.4
       Questo accade solitamente quando si sta eseguendo il
       collegamento con librerie diverse da libc (come le librerie X),
       e si utilizza l'opzione -g sulla riga di link utilizzando anche
       -static.

       Gli stub .sa per le librerie condivise contengono solitamente un
       simbolo indefinito _NEEDS_SHRLIB_libc_4 che viene risolto da
       libc.sa. Tuttavia, con -g si finisce di eseguire il collegamento
       con libg.a o libc.a, il simbolo non viene mai risolto, portando
       all'errore sopra descritto.

       In conclusione, aggiungere -static quando si compila con
       l'opzione -g, oppure non eseguire il collegamento con -g. Molto
       spesso � possibile ottenere informazioni di debugging
       sufficienti compilando i file individuali con -g, ed eseguendo
       il collegamento senza questa opzione.



 6.5.  Loading dinamico

 Questo paragrafo � per il momento piuttosto breve, verr� esteso in
 futuro.


 6.5.1.  Concetti

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


 6.5.2.  Messaggi di errore

 I lettori sono pregati di inviare i proprii errori di link all'autore,
 che anche se non potr� risolverli, comunque scriver� un resoconto
 dettagliato.

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



         ftp: can't load library 'libreadline.so.2'





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



 6.5.3.  Controllo delle operazioni del loader dinamico

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


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

 �  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 malloc.o e utilizzare i
    comandi



      $ LD_PRELOAD=malloc.o; export LD_PRELOAD
      $ programma_di_test





 LD_ELF_PRELOAD e LD_AOUT_PRELOAD sono simili, ma possono essere appli�
 cati solo al tipo binario appropriato. Se LD_qualcosa_PRELOAD e
 LD_PRELOAD sono entrambi impostati, verr� utilizzato quello pi� speci�
 fico.

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

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

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

 �  LD_TRACE_LOADED_OBJECTS --- si applica solamente a ELF, e fa in
    modo che i programmi credano di essere in esecuzione sotto ldd:



      $ LD_TRACE_LOADED_OBJECTS=true /usr/bin/lynx
              libncurses.so.1 => /usr/lib/libncurses.so.1.9.6
              libc.so.5 => /lib/libc.so.5.2.18






 6.5.4.  Scrivere programmi con il loading dinamico

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



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

      }





 7.  Come contattare gli sviluppatori

 7.1.  Comunicazione degli errori

 Per prima cosa � necessario cominciare a circoscrivere il problema. �
 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?

 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 info. Per ld.so o per le librerie C o maths, inviare
 una mail a [email protected]. 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.


 7.2.  Aiuto nello sviluppo

 Se si desidera aiutare lo sviluppo di GCC o della libreria C, la prima
 cosa da fare consiste nell'unirsi alla mailing list linux-
 [email protected]. Se si vuole semplicemente dare un'occhiata alle
 discussioni, � possibile consultare http://homer.ncm.com/linux-gcc/.
 La seconda cosa e le successive dipendono solo dalle vostre
 intenzioni!


 8.  Ultime cose

 8.1.  Ringraziamenti


      Only presidents, editors, and people with tapeworms have the
      right to use the editorial "we".  (Mark Twain)


 Ovvero

      Soli i presidenti, gli editori e la gente con il verme soli�
      tario hanno il diritto di usare il "noi" editoriale.  (Mark
      Twain)


 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.


 8.2.  Traduzioni

 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.


 8.3.  Comunicazioni, opinioni, correzioni

 Sono benvenute inviate email all'indirizzo [email protected].
 La chiave pubblica PGP (ID 5F263625) � disponibile dalle pagine web
 dell'autore http://ftp.linux.org.uk/~barlow/, se ci sono necessit� di
 riservatezza.


 8.4.  Informazioni legali

 All trademarks used in this document are acknowledged as being owned
 by their respective owners.

 This document is copyright (C) 1996 Daniel Barlow
 [email protected]. 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.

 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.

 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.

 If you have questions, please contact Tim Bynum, the Linux HOWTO
 coordinator, at [email protected].


      L'unica licenza valida � quella originale in lingua inglese.
      Di seguito ne trovate una traduzione abbastanza fedele che
      per� non ha alcun valore.


 Tutti i marchi utilizzati in questo documento sono riconosciuti come
 appartenenti ai rispettivi proprietari.

 Questo documento ha copyright (C) 1996 di Daniel Barlow
 [email protected]. 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.

 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.

 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.


 Se avete delle domande, contattate Tim Bynum, il coordinatore degli
 HOWTO di Linux, all'indirizzo [email protected] tramite
 email.


 9.  Riferimenti in italiano

 Questa sezione riporta riferimenti a documenti italiani. Nel caso in
 cui un documento non sia ancora tradotto si rimanda al WEB server del
 Pluto.


 �  [1] http://www.pluto.linux.it/ildp/HOWTO/ELF-HOWTO.html

 �  [2] http://www.pluto.linux.it/ildp/ WEB server del PLUTO, sono
    disponibili anche le traduzioni di altri HOWTO.

 �  [3] http://www.pluto.linux.it/ildp/HOWTO/GCC-HOWTO.html


 10.  Indice Analitico




     -fwritable-strings
       ``39'' ``56''


     /lib/cpp
       ``16''


     a.out
       ``1''


     ar
       ``10''


     as
       ``8''


     <asm/*.h>
       ``19''


     atoi()
       ``40''


     atol()
       ``41''


     binaries too big
       ``63'' ``65'' ``77''


     cos()
       ``68''



     debugging
       ``59''


     dlopen()
       ``82''


     dlsym()
       ``83''


     documentazione
       ``4''


     EINTR
       ``52''


     elf
       ``0'' ``71''


     execl()
       ``57''


     fcntl
       ``47''


     FD_CLR
       ``44''


     FD_ISSET
       ``45''


     FD_SET
       ``43''


     FD_ZERO
       ``46''


     file
       ``2''


     <float.h>
       ``20''


     gcc
       ``6''


     gcc -fomit-frame-pointer
       ``61''


     gcc -g
       ``60''
     gcc -v
       ``14''


     gcc, errori (bug)
       ``15'' ``28'' ``29'' ``84''


     gcc, opzioni (flag)
       ``13'' ``25'' ``26''


     gdb
       ``64''


     header file
       ``17''


     chiamate a sistema interrotte
       ``51''


     ld
       ``9''


     LD_* variabili d'ambiente
       ``80''


     ldd
       ``81''


     libc
       ``7''


     libg.a
       ``62''


     libgcc
       ``79''


     <limits.h>
       ``21''


     lint
       ``58''


     <linux/*.h>
       ``18''


     pagine del manuale
       ``5''


     <math.h>
       ``70''
     maths
       ``69''


     mktemp()
       ``55''


     ottimizzazione
       ``27''


     QMAGIC
       ``76''


     segmentation fault
       ``30'' ``54''


     segmentation fault, in GCC
       ``33''


     select()
       ``50''


     SIGBUS
       ``34''


     SIGEMT
       ``35''


     SIGIOT
       ``36''


     SIGSEGV
       ``31'' ``53''


     SIGSEGV, in gcc
       ``32''


     SIGSYS
       ``38''


     SIGTRAP
       ``37''


     sin()
       ``67''


     soname
       ``73''


     sprintf()
       ``42''
     librerie collegate staticamente, in modo inatteso
       ``66'' ``78''


     <stdarg.h>
       ``23''


     <stddef.h>
       ``24''


     strings
       ``11''


     <sys/time.h>
       ``48''


     <unistd.h>
       ``49''


     <varargs.h>
       ``22''


     numeri di versione
       ``12'' ``74''


     cose misteriose
       ``72''


     ZMAGIC
       ``75''