Avanti Indietro Indice

4. METAPROGRAMMAZIONE E MACRO

La programmazione in assembly è una scocciatura, tranne che per sezioni critiche dei programmi.

Dovreste usare gli strumenti appropriati per il compito giusto, quindi non scegliete l'assembly quando non è adatto; C, OCAML, perl, Scheme potrebbero essere una scelta migliore per la maggior parte della vostra programmazione.

Comunque, ci sono casi in cui questi strumenti non consentono un controllo sufficientemente accurato della macchina e l'assembly risulta utile o addirittura necessario. In questi casi, vi sarà utile un sistema di macro e metaprogrammazione che permetterà di ridurre ogni struttura ricorrente in una definizione riutilizzabile molte volte, il che consente una programmazione più sicura, la propagazione automatica delle modifiche alla struttura stessa, ecc.

Un assemblatore «liscio» è spesso insufficiente, anche quando si sviluppano semplicemente piccole routine per un linking con il C.

4.1 Cosa è integrato nei pacchetti menzionati

Sì, lo so che questa sezione non contiene molte informazioni aggiornate. Sentitevi liberi di contribuire ciò che scoprite sulla vostra pelle...

GCC

GCC permette (e richiede) che voi specifichiate vincoli sui registri nel vostro codice assembly inline cosicché l'ottimizzatore ne è sempre al corrente; perciò il codice assembly inline, in realtà, non è per forza costituito da codice esatto, ma da strutture.

Potete poi inserire il vostro assembly in macro di CPP ed in funzioni C inline, così si può usare come una qualsiasi macro o funzione C. Le funzioni inline assomigliano molto alle macro, ma il loro uso risulta talvolta più pulito. Badate che in tutti questi casi si avrà una duplicazione di codice, quindi in questo codice asm dovrebbero essere definite solo etichette locali (del tipo 1:). Comunque, una macro permetterebbe che il nome di una etichetta non definita localmente venga passato come parametro (oppure utilizzate metodi aggiuntivi di metaprogrammazione). Inoltre, propagare codice asm inline diffonderà potenziali bug presenti in esso, state quindi doppiamente attenti ai vincoli sui registri in situazioni simili.

Infine, il linguaggio C stesso può essere considerato una buona astrazione rispetto al linguaggio assembly, il che vi solleva dalla maggior parte dei problemi legati all'assembling.

Fate attenzione: alcune ottimizzazioni riguardanti il passaggio di argomenti a funzioni tramite registri possono rendere dette funzioni inadatte ad essere chiamate da routine esterne (ed in particolare da quelle scritte a mano in assembly) nel modo standard; l'attributo «asmlinkage» potrebbe impedire ad una routine di preoccuparsi di tale flag di ottimizzazione; guardatevi i sorgenti del kernel per gli esempi.

GAS

GAS fornisce del supporto per le macro, come è spiegato in dettaglio nella documentazione texinfo. GCC, oltra a riconoscere i file .s come assembly «grezzo» da inviare a GAS, riconosce anche i file .S come file da passare attraverso CPP prima di mandarli a GAS. Ancora una volta, guardate i sorgenti di Linux per gli esempi.

GASP

Aggiunge tutti i tipici trucchetti delle macro a GAS. Consultate la sua documentazione texinfo.

NASM

Anche NASM ha del supporto per le macro. Date un'occhiata alla documentazione relativa. Se avete qualche idea brillante, potreste voler contattare gli autori, dal momento che lo stanno sviluppando attivamente. Nel frattempo, date un'occhiata ai filtri esterni presentati in seguito.

AS86

Ha un po' di semplice supporto per le macro, ma non sono riuscito a trovare della documentazione. I sorgenti sono molto chiari perciò se siete interessati dovreste capirli facilmente. Se le capacità di base non vi bastano, dovreste usare un filtro esterno (vedere in seguito).

ALTRI ASSEMBLATORI

4.2 Filtri esterni

Qualunque sia il supporto per le macro del vostro assemblatore, o qualunque linguaggio utilizziate (perfino il C!), se secondo voi il linguaggio non è sufficientemente espressivo, potete far passare i file attraverso un filtro esterno con una regola come questa nel Makefile:


%.s:    %.S altre_dipendenze
            $(FILTRO) $(OPZIONI_DEL_FILTRO) < $< > $@

CPP

CPP non è molto espressivo, ma è sufficiente per le cose facili, è standard ed è chiamato in modo trasparente da GCC.

Per fare un esempio delle sue limitazioni, non si possono dichiarare oggetti in modo tale che i distruttori vengano chiamati automaticamente al termine del blocco di dichiarazione; non avete diversion o regole di visibilità (scoping), ecc.

CPP si trova assieme ad ogni compilatore C. Se ve la siete cavata senza averne uno, non preoccupatevi di procurarvi GCC (anche se mi chiedo come abbiate fatto).

M4

M4 vi dà tutta la potenza delle macro, con un linguaggio Turing-equivalente, ricorsione, espressioni regolari, ecc. Potete farci tutto ciò che CPP non riesce a fare.

Date un'occhiata a macro4th/This4th da ftp://ftp.forth.org/pub/Forth/ in Reviewed/ ANS/ (?), o le sorgenti di Tunes 0.0.0.25 come esempi di un utilizzo avanzato delle macro con m4. Comunque, il suo scomodo sistema di protezione dall'espansione vi obbliga ad utilizzare per le macro uno stile basato sulla ricorsione in coda con passaggio di continuazione esplicito (explicit continuation-passing) se volete una uso avanzato delle macro (il che ricorda TeX. A proposito, qualcuno ha provato ad usare TeX per le macro di qualcosa di diverso dalla composizione tipografica?). Questo comunque NON è peggio di CPP, il quale non permette né il quoting né la ricorsione. La versione giusta di m4 da procurarsi è GNU m4 1.4 (o successiva, se esiste), la quale ha il maggior numero di funzionalità ed il minor numero di bug o limitazioni rispetto alle altre. m4 è progettato per essere lento per tutto tranne gli utilizzi più semplici, il che potrebbe andare ancora bene per la maggior parte dei programmi assembly (non state scrivendo programmi in assembly da milioni di righe, vero?).

Macro con i vostri filtri

Potete scrivervi dei semplici filtri per l'espansione delle macro con i soliti strumenti: perl, awk, sed, ecc. Si fa in fretta ed avete il controllo su tutto. Ma ovviamente, la potenza nella gestione delle macro bisogna guadagnarsela con fatica.

Metaprogrammazione

Invece di usare un filtro esterno che espande le macro, un modo alternativo di procedere è quello di scrivere programmi che scrivono parti di altri programmi (o interi programmi).

Ad esempio, potreste utilizzare un programma che dia in uscita codice sorgente

Pensateci!

Backend da compilatori esistenti

Compilatori come SML/NJ, Objective CAML, MIT-Scheme, ecc. hanno il loro backend generico per gli assemblatori che potreste o meno voler usare se intendete generare semiautomaticamente del codice partendo dai linguaggi relativi.

Il New-Jersey Machine-Code Toolkit

C'è un progetto per costruire, usando il linguaggio di programmazione Icon, una base per produrre codice che manipola l'assembly. Date un'occhiata dalle parti di http://www.cs.virginia.edu/~nr/toolkit/

Tunes

Il progetto Tunes OS sta sviluppando il suo assemblatore come un'estensione al linguaggio Scheme, come parte del suo processo di sviluppo. Al momento non è ancora in grado di girare, tuttavia ogni aiuto è bene accetto.

L'assemblatore manipola alberi di sintassi simbolici, così può ugualmente servire come base per un traduttore di sintassi assembly, un disassemblatore, un backend comune per assemblatore/compilatore, ecc. Inoltre tutta la potenza di un vero linguaggio, Scheme, lo rende insuperato per quanto riguarda le macro e la metaprogrammazione.

http://www.eleves.ens.fr:8080/home/rideau/Tunes/


Avanti Indietro Indice