Programma sorgente in C

Compilatore: il compilatore è un software che traduce il sorgente C, in un linguaggio mnemonico di istruzioni: il linguaggio assembly.

Assemblatore: assembler si occupa di effettuare la traduzione tra linguaggio assembly e istruzioni binarie. Gli assembler in genere effettuano 2 passi.

Codice tradotto in assembly. Il linguaggio assembly è un insieme di istruzioni mnemoniche del set di istruzioni delle operazioni usate nel programma. Il linguaggio assembly non è linguaggio macchina (poiché contiene ancora istruzioni non binarie), ma è molto vicino e strettamente collegato ad esso, infatti le istruzioni mnemoniche assembly sono direttamente connesse alle istruzioni dell'ISA in questione.

Passo 1
...

Nel primo passo si analizza il codice e si controlla che sia sintatticamente corretto. Oltre a questo, l'assemblatore:

  • sostituisce le macro
  • sostituisce le pseudo-istruzioni
  • crea una tabella dei simboli dove mette i simboli sconosciuti (etichette), ognuna viene sostituta con un ILC (istrunction location counter). La tabella (symbol table) alla fine sarà un insieme di coppie simbolo-indirizzo.

ILC
Gli ILC, aiutano a determinare l'indirizzo relativo del programma.
Avendo un pezzo di codice di questo tipo:

loop:
  addi x1, x1, 1
  beq x1, x2, loop

Ad esempio, se nella riga dove avviene addi l'ILC è 0x100, nella riga in cui avviene il branch l'indirizzo incrementa di 4 byte, quindi: 0x104.

Oltre a questo avvengono anche delle sostituzioni di etichette. Ad esempio all'etichetta loop corrisponde l'.ILC6 (con indirizzo 0x104), mentre a quella di loop potrebbe spettare l'etichetta 4 (con indirizzo 0x98).

Passo 2
...

Nel secondo passo, il codice viene effettivamente tradotto. L'assemblatore sostituisce le istruzioni come add con il relativo codice operativo (che l'assemblatore detiene nella tabella degli opcode), inoltre utilizzate la tabella dei simboli creata nel passo precedente per sostituire le etichette con degli indirizzi.

Viene dunque creato un file oggetto, ovvero un binario pronto per essere eseguito.

Linker
Il linker collega, eventualmente più moduli, che compongono lo stesso programma, in unico file oggetto e di creare uno spazio degli indirizzi unico tra i moduli fusi. Poi memorizza il file oggetto in memoria secondaria.

Linker dinamico
Se un modulo viene aggiornato non occorre ricompilare tutti i moduli, ma sono quello che è stato modificato. Il file oggetto prodotto da un linker dinamico contiene solo le informazioni su dove poter reperire gli altri moduli. Durante l'esecuzione verranno caricati e risolti i riferimenti ad essi. (I moduli devono essere presenti nel sistema).

Linker statico
Se un modulo viene aggiornato, occorre ricompilare tutti i moduli. Il che è abbastanza scomodo, oltre che uno spreco di risorse. (Tutti i moduli sono contenuti in unico modulo, quindi non occorre che la libreria sia presente nel sistema)

Loader
Si preoccupa di caricare il programma in memoria principale e di riservare tutte le risorse necessarie per poterlo eseguire.

Ciò che può avvenire a questo punto è il lazy linking, ovvero le librerie esterne, non vengono caricate immediatamente tutte, ma solo quando vengono richieste la prima volta.