Catena di programmazione: Assembler, linker, loader
Il linguaggio macchina è costituito da un set di istruzioni codificate in binario. Per rendere più semplice la programmazione si utilizza uno speciale
linguaggio simbolico, denominato assembly, le cui istruzioni hanno una codifica più comprensibile per l'essere umano (ad es: ADD per sommare,
MUL per moltiplicare, ecc.). Ogni istruzione assembly corrisponde ad una istruzione macchina e viceversa. Poiché ogni tipo di processore ha un
proprio linguaggio macchina, esisterà anche un linguaggio assembly per ogni processore. Pertanto si avrà ad esempio un assembly per l'Intel 8086,
un assembly per il Motorola, ecc. I linguaggi assembly sono detti anche linguaggi a basso livello, in quanto sono più vicini al linguaggio della
macchina. Viceversa i linguaggi più vicini all'utente umano vengono detti linguaggi ad alto livello.
Ogni programma scritto in assembly può essere eseguito dal processore solo dopo essere stato tradotto in linguaggio macchina e successivamente
caricato in memoria centrale. La traduzione viene effettuata da un apposito programma detto assemblatore (assembler). Tale programma traduce i
codici mnemonici utilizzati nell'assembly nei corrispondenti codici macchina, traduce i nomi simbolici di variabili in indirizzi di memoria e genera il
cosiddetto codice oggetto.
Successivamente un altro programma detto collegatore (linker) collega tra di loro i diversi moduli oggetto che costituiscono il programma e collega
gli indirizzi di memoria dei diversi moduli. Anche quando il programma è costituito da un solo modulo è comunque necessaria l'operazione di
collegamento. Il risultato ottenuto è il programma eseguibile vero e proprio (in DOS e Windows si tratta di file caratterizzati dall'estensione ".exe").
Tale programma viene infine caricato in memoria da un ulteriore modulo di sistema detto caricatore (loader).
Sorgenti
assembly
Assemblatore
Moduli
oggetto
Linker
Modulo
eseguibile
Loader
Programma
eseguibile
in memoria
Catena di programmazione per programmi assembly
Compilatori e interpreti
L'utilizzo del linguaggio assembly nella programmazione è oggi riservato a programmi non troppo complessi ma per i quali è richiesta la massima
efficienza possibile (ad es: moduli di sistema operativo) oppure a programmi che devono interagire in modo molto diretto con l'hardware della
macchina (ad esempio: driver di periferiche, ecc.).
Per facilitare invece la scrittura di programmi molto complessi, difficilmente realizzabili in assembly, sono stati creati diversi linguaggi di
programmazione meno vincolati al modo di procedere dell'elaboratore. Tali linguaggi sono un po' più vicini al modo umano di procedere nella
risoluzione di un problema e sono detti pertanto linguaggi ad alto livello. I linguaggi ad alto livello sono caratterizzati da istruzioni più complesse e
strutturate rispetto a quelle dell'assembly. Ad esempio una singola istruzione ad alto livello può corrispondere ad una sequenza di numerose
istruzioni macchina. Inoltre ogni istruzione, essendo strutturata, può contenere a sua volta altre istruzioni (come ad esempio, per l'istruzione repeat
until del Pascal). Esempi di linguaggi ad alto livello sono: Cobol (orientato ad applicazioni gestionali), Fortran (orientato ad applicazioni
scientifiche), Pascal (orientato ad applicazioni generali), C++ (orientato ad applicazioni sistemistiche), ecc.
Ogni programma scritto in linguaggio ad alto livello (detto codice sorgente) per poter essere eseguito deve essere prima tradotto in un programma
scritto nel linguaggio macchina (detto codice eseguibile) del processore utilizzato per l'esecuzione. Tale traduzione viene effettuata da appositi
programmi che si dividono in due categorie: compilatori ed interpreti.
Il compilatore analizza e traduce un intero modulo sorgente e produce un primo codice intermedio (codice oggetto), il quale viene successivamente
acquisito dal linker che produrrà il codice eseguibile vero e proprio. Una volta che il programma sorgente è stato tradotto in eseguibile, esso potrà
essere eseguito in un momento successivo, ogni volta che lo si vuole.
L'interprete invece analizza, traduce ed esegue una istruzione per volta. Non viene salvato nessun codice eseguibile. Ogni volta che si vorrà
rieseguire lo stesso programma verrà nuovamente effettuato l'intero processo di analisi, traduzione, esecuzione, istruzione per istruzione. Pertanto
l'esecuzione risulterà di norma più lenta.
Un vantaggio di utilizzare un linguaggio interpretato è quello di poter verificare la correttezza del programma man mano che lo si scrive. Può essere
quindi utile in una fase di apprendimento di un linguaggio semplice (ad es: BASIC). Tuttavia per ottenere un software efficiente e maggiormente
protetto da manipolazioni (infatti è pressoché impossibile risalire da un codice eseguibile al corrispondente codice sorgente) è certamente preferibile
utilizzare un linguaggio compilato.
È da tenere presente che ogni compilatore traduce un sorgente in un linguaggio specifico per la macchina e il sistema operativo su cui il programma
dovrà essere eseguito. Ad esempio se si utilizza un compilatore Pascal per DOS o Windows, il programma eseguibile ottenuto potrà essere eseguito
solo su tali sistemi. Per eseguirlo invece su una macchina con un processore ed un sistema operativo diverso (ad es. Apple Macintosh) bisognerà
utilizzare un compilatore Pascal per tale sistema.
Un caso speciale è rappresentato dal recente linguaggio Java prodotto dalla Sun. Si tratta in questo caso di un linguaggio ad alto livello che viene compilato
e tradotto in uno speciale codice vicino alla macchina (detto bytecode), ma indipendente da essa; il bytecode verrà successivamente interpretato ed eseguito
da un apposito interprete (Java Virtual Machine), specifico per ogni sistema e attualmente disponibile per tutti i più diffusi sistemi operativi (Windows,
Linux, Macintosh, ecc.). Pertanto un programma scritto in Java, pur essendo "compilato", potrà essere eseguito su pressoché qualsiasi sistema, sia pure a
costo di una efficienza sensibilmente inferiore rispetto a quella di un linguaggio a tutti gli effetti compilato come C++.
Sorgenti ad
alto livello
Compilatore
Moduli
oggetto
Linker
Modulo
eseguibile
Catena di programmazione per linguaggi ad alto livello compilati
Loader
Programma
eseguibile
in memoria
Programmazione in assembly 8086 in ambiente Borland Turbo Assembler (TASM)
Il programma sorgente in linguaggio assembly può essere scritto con qualsiasi editor di testo (es: blocco note, edit del Dos, ecc.). Il file deve avere
estensione ".asm". Es: "prova.asm".
Aprire preventivamente una finestra DOS e posizionarsi nella propria cartella di lavoro.
Es:
CD c:\alunni\3ai\gruppo10
Per ottenere il programma eseguibile è necessario effettuare i seguenti passaggi. Ogni passaggio è eseguito mediante un comando sotto DOS.
1 Assemblamento.
Il comando da utilizzare è TASM.
Es:
>
tasm prova.asm (l’estensione .asm può essere omessa)
Se non sono segnalati errori viene prodotto il codice oggetto, con estensione “.obj”, ad es: “prova.obj” (controllare digitando ad esempio:
“dir *.obj”).
Se vengono segnalati errori, viene indicato il numero di linea dove c’è l’errore e il tipo di errore. Controllare e correggere il programma sorgente,
quindi rieffettuare l’assemblamento.
2 Collegamento (Link)
Il comando da utilizzare è TLINK.
Es:
>
tlink prova.obj (l’estensione .obj può essere omessa)
Se non sono segnalati errori viene prodotto il codice eseguibile, con estensione “.exe”, ad esempio “prova.exe”. (controllare digitando ad esempio:
“dir *.exe”).
3 Caricamento ed esecuzione
Per eseguire il programma basta digitare il nome.
Es:
>
prova.exe (l’estensione .exe può essere omessa)
Esecuzione controllata in ambiente di debug
Per eseguire il programma in ambiente controllato per l’analisi o il debug si utilizza il comando TD.
Es:
>
td prova.exe (l’estensione .exe può essere omessa)
Si apre l’ambiente del Borland Turbo Debug in cui si può controllare l’esecuzione del programma, facendo ad esempio eseguire le istruzioni una per
volta e controllando come vengono modificati i registri e le celle di memoria.
Registri
Programma in
memoria
(esadecimale)
Flag (registro dei flag)
Programma in
memoria
(simbolico)
Memoria
(esadecimale)
Memoria
(formato ASCII)
Comandi principali:

F8 (Run | Step over) : esegue una istruzione per volta

View | Dump: mostra un’area di memoria. L’area di memoria di interesse è il segmento contenente i dati del programma (DS:0000).

Ctrl F2 (Run | Program reset): per resettare l’esecuzione

F9 (Run): per eseguire tutto il programma a partire dal punto attuale.

Alt-x (File| Quit): per uscire dall’ambiente
Ogni comando può essere eseguito anche senza usare il mouse. Basta premere Alt insieme alla lettera evidenziata nel comando. Es: Alt-f, q per
uscire.