I compilatori possono generare codice assembly, codice oggetto collegabile o codice macchina pronto all'uso; Ho lavorato con esempi di tutti e tre i tipi. Sebbene i compilatori che emettono codice assembly possano essere più adattabili a piattaforme diverse rispetto a quelli che generano il codice oggetto, l'output del codice assembly è spesso più lento dell'output del codice macchina e l'esecuzione di un programma richiederà l'ulteriore passaggio del codice assembly. In realtà non è molto più difficile per un compilatore generare codice macchina che generare codice assembly; in alcuni casi potrebbe essere più semplice.
Per quanto riguarda la generazione di codice collegabile o pronto per l'esecuzione, è spesso più veloce e più facile per un compilatore produrre quest'ultimo; l'unico vantaggio di produrre il primo è che la costruzione di un programma richiede la ricompilazione solo delle parti che sono state modificate e quindi il collegamento di tutto, invece di dover alimentare tutto attraverso il compilatore. Se i progetti saranno generalmente di grandi dimensioni e la porzione che cambia in una piccola build, quindi essere in grado di compilare in modo selettivo le parti del codice che sono state modificate potrebbe essere una "vittoria". Se, tuttavia, si desidera ricostruire la maggior parte del programma su ogni build, la produzione di un codice macchina eseguibile potrebbe essere più veloce rispetto a uno stage intermedio.
Un ulteriore vantaggio di produrre codice macchina eseguibile è che un compilatore può essere in grado di sfruttare le cose che conosce sulle posizioni degli oggetti in modi che non sarebbero possibili quando si genera codice rilocabile. Ad esempio, se foo
e bar
sono dichiarati in moduli separati, un'istruzione foo=bar;
richiederebbe qualcosa del tipo:
ldr r0,[pc+(_addr_of_bar-*)]
ldr r1,[pc+(_addr_of_foo-*)]
ldr r2,[r0]
str r2,[r1]
...somewhere within 2K of the above:
_addr_of_bar: dw _bar
_addr_of_foo: dw _foo
Se le variabili foo
e bar
si verificano in corrispondenza di indirizzi noti che si trovano entro 4K l'uno dall'altro [ad es. 1600 byte a parte], il codice potrebbe essere semplificato a qualcosa di simile:
ldr r0,[pc+(_addr_of_foo_bar-*)]
ldr r1,[r0+600]
str r1,[r0-1000]
...somewhere within 2K of the above:
_addr_of_foo_bar: dw _foo+1000
Tali ottimizzazioni sono possibili solo se il compilatore sa come saranno posizionate le cose.