Capitolo 2.   Dal sorgente all'eseguibile

L'assemblatore AT&T per linux si chiama as o GAS e fa parte del pacchetto gcc; essendo tale pacchetto disponibile per le piattaforme Windows, con il nome di cygwin, è possibile usare as anche in tale ambiente.

I sorgenti scritti con questo linguaggio hanno per convenzione l'estensione «.s» ma è possibile scegliere qualsiasi altro tipo di nome.

2.1   Traduzione del sorgente con as

Per assemblare un sorgente si deve eseguire il comando:

as -a -o nome_oggetto.o nome_sorgente.s

L'opzione -o serve ad indicare il nome del file oggetto ottenuto con la traduzione; essa però si conclude positivamente solo se non vengono riscontrati errori di sintassi dei quali eventualmente si riceve opportuna segnalazione (descrizione dell'errore e indicazione della riga in cui è avvenuto).

L'opzione -a non è obbligatoria e ha lo scopo di ottenere a video il sorgente affiancato dalla traduzione in codice macchina delle istruzioni e seguito dalle liste dei simboli (etichette dati e istruzioni); il fatto che tali informazioni vengano rese disponibili a video permette di poterle eventualmente ridirezionare su un file per un loro più comodo esame.

Altra opzione importante è --gstabs che costringe l'assemblatore a inserire maggiori informazioni all'interno del file oggetto; tali informazioni sono indispensabili se si vogliono usare programmi debugger come gdb, che è il più usato in ambiente GNU/Linux.

Una volta concluso il collaudo del programma ed eliminati tutti gli errori, è però consigliabile assemblare il programma senza l'opzione --gstabs in modo da avere un file oggetto, e quindi un eseguibile, più snello e con migliori prestazioni.

Per avere dettagli sulle molte altre opzioni disponibili si può eseguire il comando:

man as

Se si lavora con una CPU a 64 bit ma si vuole ottenere un programma oggetto a 32 bit si deve aggiungere l'opzione --32 al comando as.

2.2   Fase di linking e esecuzione

Per ottenere l'eseguibile occorre usare il programma per il linking ld nel modo seguente:

ld -o nome_eseguibile nome_oggetto.o

L'opzione -o permette di indicare il nome del file eseguibile.

Anche questo comando prevede molte opzioni e inoltre offre la possibilità di fare il linking di più file oggetto contemporaneamente; nei prossimi capitoli sfrutteremo alcune sue potenzialità esaminando programmi sempre più complessi.

Ovviamente è anche qui possibile consultare il manuale in linea con:

man ld

Per eseguire il programma occorre il comando:

./nome_eseguibile

oppure:

/percorso_per_raggiungere_eseguibile/nome_eseguibile

2.3   Cenni all'uso del debugger gdb

L'esecuzione di un programma scritto in assembly non sempre offre risultati che possono essere apprezzati direttamente; questo accade soprattutto quando si inizia a usare il linguaggio e quindi non si usano istruzioni per l'input e l'output.

Può inoltre capitare che, in presenza di risultati visibili da parte del programma, questi non coincidano con quelli attesi oppure che il programma abbia comportamenti imprevisti e strani; in tal caso siamo in presenza di errori run-time o di errori logici.

In entrambe queste situazioni diventa indispensabile l'uso di un debugger come gdb in modo da poter inserire dei breakpoint che permettono poi l'esecuzione passo dopo passo, e da poter visionare il contenuto della memoria e dei principali registri.

Per attivarlo si deve dare il comando:

gdb nome_eseguibile

Ci troviamo in questo modo nell'ambiente interattivo di gdb cha ha un suo prompt:

    (gdb)
    

e mette a disposizione una serie di comandi come:

Per maggiori dettagli si può consultare il manuale del comando gdb, che è comunque uno strumento abbastanza ostico anche se molto potente.

Per facilitare il compito ai programmatori assembly sono stati allora creati vari programmi che sono delle interfacce grafiche di gdb; esempi in tal senso possono essere ddd e insight.

Sono entrambi strumenti abbastanza semplici e intuitivi e per il loro uso dovrebbe essere sufficiente la consultazione dei rispettivi manuali on-line; di ddd vedremo esempi di utilizzo nei prossimi paragrafi.

Si ricorda in ogni caso che per poter usare questi programmi occorre avere assemblato il sorgente con l'opzione --gstabs.

2.4   Uso di gcc per i programmi assembly

Si può anche usare gcc in alternativa ad as per la traduzione del sorgente assembly; in questo caso il comando da lanciare è:

gcc -c -g -o nome_oggetto.o nome_sorgente.s

L'opzione -o ha il ruolo già illustrato in precedenza, l'opzione -c fa si che gcc si fermi alla creazione del file oggetto senza procedere con il linking e l'opzione -g (ovviamente facoltativa) ha lo stesso scopo di --gtabs quando si usa as.

Infine vediamo che è anche possibile fare tutto (traduzione e linking) con gcc con il comando:

gcc -g -o nome_eseguibile nome_sorgente.s

però in questo caso la parte esecutiva del programma deve iniziare con l'etichetta main: al posto di _start:; questo aspetto sarà forse più chiaro al momento in cui vedremo la struttura del sorgente assembly AT&T (paragrafo 3.4):

Quando si compila un programma sorgente in linguaggio c con il comando:

gcc -o nome_eseguibile nome_sorgente.c

otteniamo come risultato il programma eseguibile (se non ci sono errori); in realtà però avviene un doppio passaggio realizzato da gcc:

  1. viene creato un file oggetto temporaneo .o;

  2. viene creato l'eseguibile tramite il linker ld e viene rimosso il file oggetto temporaneo.

Il file oggetto temporaneo è un file in linguaggio macchina del tutto analogo a quello che si ottiene quando si assembla un sorgente .s.

Se si vuole vedere il codice assembly corrispondente all'oggetto creato da gcc quando compila un sorgente c, occorre eseguire il comando:

gcc -S nome_sorgente.c

e si ottiene come risultato il listato assembly in nome_sorgente.s.

Se si lavora con una CPU a 64 bit ma si vuole ottenere un programma eseguibile a 32 bit si deve aggiungere l'opzione -m32 al comando gcc (in tal caso deve essere installato il pacchetto gcc-multilib).