Avanti Indietro Indice

3. ASSEMBLATORI

3.1 Assembly inline di GCC

Il noto compilatore GNU C/C++ (GCC), un compilatore ottimizzante a 32-bit alla base del progetto GNU, supporta l'architettura x86 abbastanza bene, e fornisce la possibilità di inserire codice assembly nei programmi C, in modo tale che l'allocazione dei registri può essere o specificata o lasciata a GCC. GCC funziona sulla maggior parte delle piattaforme disponibili, tra le quali sono degne di nota Linux, *BSD, VSTa, OS/2, *DOS, Win*, ecc.

Dove trovare GCC

Il sito originale di GCC è il sito FTP di GNU ftp://prep.ai.mit.edu/pub/gnu/ in cui si trova anche tutto il software applicativo del progetto GNU che è stato rilasciato.

Versioni configurate e precompilate per Linux possono essere trovate in ftp://sunsite.unc.edu/pub/Linux/GCC/. Esistono un sacco di mirror FTP di entrambi i siti in tutte le parti del mondo, così come copie su CD-ROM.

Recentemente, lo sviluppo di GCC si è biforcato. Maggiori notizie sulla versione sperimentale, egcs, presso http://www.cygnus.com/egcs/.

Dovreste trovare dei sorgenti adattati per il vostro sistema operativo preferito e dei binari precompilati ai soliti siti FTP.

La versione più comune per DOS si chiama DJGPP e può essere trovata nelle directory con questo nome nei siti FTP. Vedere:

http://www.delorie.com/djgpp/

C'è anche una versione di GCC per OS/2 chiamata EMX, che funziona anche sotto DOS ed include molte routine di libreria per l'emulazione di UNIX. Date un'occhiata dalle parti di:

http://www.leo.org/pub/comp/os/os2/gnu/emx+gcc/

http://warp.eecs.berkeley.edu/os2/software/shareware/emx.html

ftp://ftp-os2.cdrom.com/pub/os2/emx09c/

Dove trovare documentazione per l'assemblatore inline di GCC

La documentazione di GCC include file di documentazione in formato texinfo. Potete compilarli con TeX e poi stampare il risultato, oppure convertirli in .info e sfogliarli con emacs, oppure ancora convertirli in .html o (con gli strumenti appropriati) in tutto ciò che volete, oppure semplicemente leggerli così come sono.

Di solito i file .info si trovano in ogni buona installazione di GCC.

La sezione corretta da cercare è: C Extensions::Extended Asm::

La sezione Invoking GCC::Submodel Options::i386 Options:: potrebbe anch'essa rivelarsi utile. In particolare, dà i vincoli sui nomi dei registri specifici per l'i386: abcdSDB corrispondono rispettivamente a: %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp (nessuna lettera per %esp).

La DJGPP Games resource (non solo per hacker dei giochi) ha questa pagina apposta per l'assembly:

http://www.rt66.com/~brennan/djgpp/djgpp_asm.html

Infine, c'è una pagina web chiamata «DJGPP Quick ASM Programming Guide» che tratta URL, FAQ, sintassi asm AT&T per x86, alcune informazioni sull'asm inline e la conversione dei file .obj/.lib:

http://remus.rutgers.edu/~avly/djasm.html

GCC dipende da GAS per l'assembling e segue la sua sintassi (vedere in seguito); se usate l'asm inline, badate bene: è necessario che i caratteri «percento» siano protetti dall'espansione per poter essere passati a GAS. Vedere la sezione su GAS in seguito.

Potete trovare un sacco di esempi utili nella sottodirectory linux/include/asm-i386/ dei sorgenti del kernel di Linux.

Invocare GCC per fargli trattare correttamente l'assembly inline

Assicuratevi di invocare GCC con il flag -O ( oppure -O2, -O3, ecc.) per abilitare le ottimizzazioni e l'assembly inline. Se non lo fate, il vostro codice potrebbe venire compilato ma non essere eseguito correttamente!!! In realtà (lodi smisurate a Tim Potter, timbo@mohpit.air.net.au) è sufficiente utilizzare il flag -fasm (e forse -finline-functions) che attiva solo una parte di tutte le funzionalità abilitate da -O. Così, se avete problemi a causa di bug nelle ottimizzazioni della vostra particolare versione/implementazione di GCC, potete comunque usare l'asm inline. In maniera analoga, usate -fno-asm per disabilitare l'assembly inline (perché dovreste?).

Più in generale, buoni flag di compilazione per GCC sulla piattaforma x86 sono


        gcc -O2 -fomit-frame-pointer -m386 -Wall

-O2 è il giusto livello di ottimizzazione. Ottimizzare oltre produce codice che è parecchio più grande, ma solo di poco più veloce; tale sovraottimizzazione potrebbe essere utile solo per cicli stretti (se ce ne sono), che potreste comunque realizzare in assembly; se ne sentite la necessità, fatelo solo per le poche routine che ne hanno bisogno.

-fomit-frame-pointer consente al codice generato di evitare la stupida gestione del frame pointer, il che rende il codice più piccolo e veloce e libera un registro per ulteriori ottimizzazioni. Ciò preclude il comodo utilizzo degli strumenti per il debugging (gdb), ma nel momento in cui usate questi strumenti, non è che vi importi poi molto delle dimensioni e della velocità.

-m386 produce codice più compatto, senza alcun rallentamento misurabile (notate che codice piccolo significa anche meno I/O per il disco ed esecuzione più rapida), ma forse sui suddetti cicli stretti potreste apprezzare -mpentium per il GCC speciale che ottimizza per pentium (sempre che abbiate come obiettivo proprio una piattaforma pentium).

-Wall abilita tutti gli avvisi e vi aiuta a scovare errori stupidi ed ovvii.

Per ottimizzare ancora di più, l'opzione -mregparm=2 e/o il corrispondente attributo per le funzioni vi potrebbero essere utili<, ma potrebbero porre un sacco di problemi qualora doveste fare un link con codice estraneo...

Notate che potete rendere questi flag quelli predefiniti modificando il file /usr/lib/gcc-lib/i486-linux/2.7.2.2/specs o dovunque esso si trovi nel vostro sistema (meglio non aggiungere -Wall in quella sede, comunque).

3.2 GAS

GAS è l'assemblatore GNU, su cui fa affidamento GCC.

Dove trovarlo

Lo trovate nello stesso posto dove avete trovato GCC, in un pacchetto denominato binutils.

Cos'è la sintassi AT&T

Poiché GAS è stato concepito per supportare un compilatore UNIX a 32 bit, esso utilizza la notazione standard «AT&T», che assomiglia molto alla sintassi degli assemblatori standard per m68k ed è standard nel mondo UNIX. Questa sintassi non è né peggiore né migliore della sintassi «Intel». È semplicemente diversa. Una volta che ci si è abituati, la si trova molto più regolare della sintassi Intel, anche se un po' noiosa.

Ecco le cose a cui prestare maggiore attenzione quando si ha a che fare con la sintassi di GAS:

Esiste un programma per aiutarvi a convertire programmi dalla sintassi TASM alla sintassi AT&T. Date un'occhiata a

ftp://x2ftp.oulu.fi/pub/msdos/programming/convert/ta2asv08.zip

GAS ha una documentazione esauriente in formato TeXinfo, che trovate nella distribuzione dei sorgenti (e forse altrove). Potete sfogliare le pagine .info estratte con emacs o con ciò che più vi aggrada. C'era un file chiamato gas.doc o as.doc dalle parti del pacchetto sorgente di GAS, ma è stato incorporato nella documentazione in TeXinfo. Certo, in caso di dubbio, la documentazione definitiva sono i sorgenti stessi! Una sezione che vi interesserà particolarmente è Machine Dependencies::i386-Dependent::

Ancora, i sorgenti di Linux (il kernel del sistema operativo) si rivelano buoni esempi; date un'occhiata ai seguenti file sotto linux/arch/i386:

kernel/*.S, boot/compressed/*.S, mathemu/*.S

Se state scrivendo qualcosa tipo un linguaggio, un pacchetto per i thread, ecc. potreste anche guardare come si comportano altri linguaggi (OCaml, gforth, ecc.) o pacchetti per i thread (QuickThreads, MIT pthreads, LinuxThreads, etc), o quel che è.

Infine, limitarsi a compilare un programma C in assembly potrebbe mostrarvi la sintassi del genere di istruzioni che vi interessano. Vedere la precedente sezione Avete bisogno dell'assembly?.

Modo a 16 bit limitato

GAS è un assemblatore a 32 bit, il suo compito è quello di supportare un compilatore a 32 bit. Attualmente ha solo un supporto limitato per il modo a 16 bit, che consiste nell'anteporre i prefissi per i 32 bit alle istruzioni, cosicché scrivete codice a 32 bit che gira nel modo a 16 bit su una CPU a 32 bit. In entrambi i modi supporta l'uso dei registri a 16 bit, ma non l'indirizzamento a 16 bit.

Utilizzate le direttive .code16 e .code32 per passare da un modo all'altro. Notate che un'istruzione di assembly inline asm(".code16\n") consentirà a GCC di produrre codice a 32 bit che girerà in real mode!

Mi è stato detto che la maggior parte del codice necessario per supportare pienamente la programmazione nel modo a 16 bit è stata aggiunta a GAS da Bryan Ford (si prega di confermare), tuttavia non si trova in nessuna delle distribuzioni che ho provato, fino a binutils-2.8.1.x ... sarebbero gradite maggiori informazioni su questo argomento.

Una soluzione economica è quella di definire macro (vedere in seguito) che in qualche modo producono la codifica binaria (con .byte) solo per le istruzioni del modo a 16 bit di cui avete bisogno (quasi nessuna se usate il codice a 16 bit come sopra e se potete supporre con certezza che il codice girerà su una CPU x86 in grado di gestire i 32 bit). Per trovare la codifica corretta, potete ispirarvi ai sorgenti degli assemblatori in grado di gestire i 16 bit.

3.3 GASP

GASP (GAS Preprocessor) è il Preprocessore per GAS. Aggiunge macro e dei costrutti sintattici carini a GAS.

Dove trovare GASP

GASP si trova assieme a GAS nell'archivio binutils di GNU.

Come funziona

Funziona come un filtro, in modo molto simile a cpp e programmi analoghi. Non ho alcuna idea sui dettagli, ma assieme ad esso trovate documentazione relativa in texinfo, perciò limitatevi a sfogliarla (in .info), stamparla, sviscerarla. GAS con GASP mi sembra un comune assemblatore con macro.

3.4 NASM

Il progetto Netwide Assembler sta producendo un ulteriore assemblatore, scritto in C, che dovrebbe essere abbastanza modulare per supportare eventualmente tutte le sintassi ed i formati di oggetto conosciuti.

Dove trovare NASM

http://www.cryogen.com/Nasm

Le release binarie, nel vostro solito mirror di sunsite, sotto devel/lang/asm/. Dovrebbero inoltre essere disponibili come .rpm o .deb nei contrib delle vostre distribuzioni RedHat/Debian.

Cosa fa

Nel momento in cui questo HOWTO viene scritto, la versione corrente di NASM è 0.96.

La sintassi è in stile Intel. È integrato del supporto per le macro. I formati di file oggetto supportati sono bin, aout, coff, elf, as86, (DOS) obj, win32, rdf (il loro formato specifico).

NASM può essere usato come backend per il compilatore libero LCC (sono inclusi i file di supporto).

Di certo NASM si evolve troppo rapidamente perché questo HOWTO possa essere aggiornato. A meno che voi stiate usando BCC come compilatore a 16 bit (il che esula dagli scopi di questo HOWTO sulla programmazione a 32 bit), dovreste usare NASM invece di, ad esempio, ASM o MASM, perché è attivamente supportato online e gira su tutte le piattaforme.

Nota: con NASM trovate anche un disassemblatore, NDISASM.

Il suo parser scritto a mano lo rende molto più veloce di GAS anche se, ovviamente, non supporta tre fantastiliardi di architetture differenti. Se volete generare codice per x86, dovrebbe essere l'assemblatore da scegliere.

3.5 AS86

AS86 è un assemblatore 80x86 a 16 e 32 bit, parte del compilatore C di Bruce Evans (BCC). Segue fondamentalmente la sintassi Intel, anche se ne discosta leggermente per quanto riguarda le modalità di indirizzamento.

Dove procurarsi AS86

Una versione decisamente superata di AS86 è distribuita da HJLu semplicemente per compilare il kernel di Linux, in un pacchetto chiamato bin86 (versione corrente: 0.4), disponibile in ogni archivio di GCC per Linux. Tuttavia non consiglio a nessuno di usarlo per qualcosa che non sia compilare Linux. Questa versione supporta solo una versione modificata del formato per file oggetto di minix, che non è supportata dalle binutils GNU o altro e che ha qualche bug nel modo a 32 bit, quindi fareste proprio meglio a tenerla solo per compilare Linux.

Le versioni più recenti realizzate da Bruce Evans (bde@zeta.org.au) sono pubblicate assieme alla distribuzione FreeBSD. Beh, lo erano: non sono riuscito a trovare i sorgenti dalla distribuzione 2.1 in poi :( Quindi, metto i sorgenti da me:

http:///www.eleves.ens.fr:8080/home/rideau/files/bcc-95.3.12.src.tgz

Il progetto Linux/8086 (conosciuto anche come ELKS) sta in qualche modo mantenendo bcc (anche se non credo che abbiano incluso le patch per i 32 bit). Date un'occhiata dalle parti di http://www.linux.org.uk/Linux8086.html ftp://linux.mit.edu/.

Tra l'altro, queste versione più recenti, contrariamente a quelle di HJLu, supportano il formato GNU a.out per Linux, cosicché è possibile il linking tra il vostro codice ed i programmi Linux e/o l'utilizzo dei soliti strumenti dal pacchetto GNU binutil per manipolare i vostri dati. Questa versione può coesistere senza alcun danno con quella precedente (vedere la domanda relativa in seguito).

BCC, versione del 12 marzo 1995 e precedenti, esegue i push ed i pop di segmenti soltanto a 16 bit, il che è non poco seccante quando si programma nel modo a 32 bit.

Una patch è disponibile nel progetto Tunes http://www.eleves.ens.fr:8080/home/rideau/Tunes/ alla sottopagina files/tgz/tunes.0.0.0.25.src.tgz nella directory decompressa LLL/i386/ La patch dovrebbe anche essere disponibile direttamente da http://www.eleves.ens.fr:8080/home/rideau/files/as86.bcc.patch.gz Bruce Evans ha accettato questa patch, così se un giorno ci sarà da qualche parte una versione più recente di bcc, la patch dovrebbe essere stata inclusa.

Come invocare l'assemblatore?

Ecco la voce nel Makefile di GNU per usare bcc allo scopo di trasformare asm .s in oggetto .o ed ottenere un listato .l :


%.o %.l:        %.s
        bcc -3 -G -c -A-d -A-l -A$*.l -o $*.o $<

Togliete %.l, -A-l e -A$*.l se non volete alcun listato. Se volete qualcos'altro invece di un a.out GNU, potete consultare la documentazione di bcc circa gli altri formati supportati e/o utilizzare objcopy dal pacchetto delle GNU binutils.

Dove trovare documentazione

La documentazione è quella che è inclusa nel pacchetto bcc. Da qualche parte nel sito di FreeBSD sono inoltre disponibili le pagine di manuale. In caso di dubbi, i sorgenti stessi sono spesso una buona documentazione: non è molto ben commentata, ma lo stile di programmazione è chiaro. Potreste provare a vedere come as86 è utilizzato in Tunes 0.0.0.25...

E se non riesco più a compilare Linux con questa nuova versione?

Linus è sepolto vivo nella posta e la mia patch per compilare Linux con as86 a.out per Linux non ce l'ha fatta ad arrivargli (!). Ora, questo non dovrebbe avere importanza: limitatevi a tenere il vostro as86 dal pacchetto bin86 in /usr/bin e lasciate che bcc installi l'as86 buono come /usr/local/libexec/i386/bcc/as dove dovrebbe risiedere. Non avrete mai bisogno di chiamare esplicitamente questo as86 «buono», perché bcc fa tutto come si deve, compresa la conversione dal formato a.out di Linux quando viene invocato con le opzioni corrette; limitatevi perciò ad assemblare usando bcc come frontend, non fatelo direttamente con as86.

3.6 ALTRI ASSEMBLATORI

Queste sono altre scelte possibili, non convenzionali, nel caso in cui le precedenti non vi abbiano soddisfatto (perché?). Non le consiglio nei casi comuni (?), ma potrebbero rivelarsi molto utili se l'assemblatore deve essere integrato nel software che state progettando (ad esempio un sistema operativo o un ambiente di sviluppo).

L'assemblatore Win32Forth

Win32Forth è un sistema ANS FORTH a 32 bit libero che gira sotto Win32s, Win95, Win NT. Include un assemblatore libero a 32 bit (con sintassi prefissa o postfissa) integrato nel linguaggio FORTH. La gestione delle macro è realizzata con la piena potenza del linguaggio FORTH; comunque, l'unico contesto di input e di output supportato è Win32Forth stesso (nessuna creazione di file .obj ; certo, potreste aggiungerla voi stessi). Lo trovate qui: ftp://ftp.forth.org/pub/Forth/win32for/

Terse

Terse è uno strumento di programmazione con LA sintassi dell'assemblatore più compatta per la famiglia x86!

Vedere http://www.terse.com. Si dice che ce ne sia un clone libero da qualche parte. Sarebbe stato abbandonato in seguito a pretese infondate secondo le quali la sintassi apparterrebbe all'autore originale. Vi invito a continuarne lo sviluppo, nel caso la sintassi vi interessi.

Assemblatori non liberi e/o non a 32 bit.

Potete trovare più informazioni a riguardo, assieme alle basi della programmazione assembly per x86, nelle FAQ di Raymond Moon per comp.lang.asm.x86 http://www2.dgsys.com/~raymoon/faq/asmfaq.zip

Va notato che tutti gli assemblatori che si basano sul DOS dovrebbero funzionare sotto l'emulatore di DOS per Linux ed altri emulatori analoghi cosicché, se ne possedete già uno, potete continuare ad usarlo in un vero sistema operativo. Alcuni assemblatori recenti per DOS supportano anche COFF e/o altri formati di file oggetto che sono supportati dalla libreria GNU BFD, così potete usarli insieme ai vostri strumenti liberi a 32 bit, magari usando GNU objcopy (che fa parte delle binutils) come filtro di conversione.


Avanti Indietro Indice