@Matteo34
A quanto già detto da pabloski e ilfe98, aggiungo solo che se vuoi approfondire la questione puoi iniziare dal manuale dell'8086 di Intel, dove trovi le varie codifiche, e lo puoi trovare qui (l'avevo uppato io):
http://www.mediafire.com/download/u4aa3ry00j1545r/231455.zip
Nel caso di MOV:
Visualizza allegato 403433
Il campo indicato come "data" rappresenta l'operando di tipo immediato (la costante numerica). Il primo campo che vedi è la codifica dell'istruzione, e il bit "w" indica la dimensione dell'operando (0 = 8bit, 1 = 16bit). Quindi all'interno dell'opcode hai la dimensione degli operandi alla quale fa riferimento pabloski nell'esempio; infatti se w=1 allora è presente il campo data (nei casi dei valori immediati).
Questo da comprendere è più semplice rispetto a IA32/IA64... ma se vuoi guardare cose più attuali, puoi far riferimento al "Software developer manual Vol.2".
A proposito della decodifica, qualche mese fa ho pubblicato questo:
MCA.
Se vuoi vedere come vengono codificate rapidamente quelle istruzioni ti conviene generarle "raw" usando NASM (penso sia l'unico o uno dei pochi assembler che te lo consente).
Per fare un esempio pratico:
Codice:
mov al, 1
mov ax, 1
mov eax, 1
Assemblando con:
Ottieni:
Codice:
B0 01 B8 01 00 66 B8 01 00 00 00
Per capire dove finisce un'istruzione e ne inizia un'altra (a parte il mio MCA) puoi usare un normalissimo editor esadecimale; sotto Windows di solito tengo HxD, ma ne esistono di diversi. Selezionando una parte dei bytes (chiaro, non puoi farlo a caso, devi avere un'idea di ciò che selezioni) ti mostra lo mnemonico (guarda in basso a destra):
Visualizza allegato 403436
Da notare poi la differenza dell'istruzione che ho selezionato rispetto alle altre (che è quella riportata anche da pabloski): assemblando per 32bit viene aggiunto il byte 0x66, che è un prefisso chiamato "Operand size override prefix". In pratica l'opcode è sempre il medesimo, ma tramite quel prefisso viene fatto l'override di quella che è la dimensione di default (32bit) con 16bit (in quanto il registro di destinazione è a 16bit).
Nota infatti che per la versione con il registro AL l'opcode non è più lo stesso, ma è 0xB0. Puoi far sempre riferimento alla tabella mostrata sopra per 8086: 0xB8 = 10111000b e 0xB0 = 10110000b. E' stata usata la versione più compatta senza modregrm che ha la forma
1011 w reg
. A questo punto noterai che 0xB8 ha proprio il bit w=1, che è quello che fa anche estendere il numero ("data", il valore immediato); giusto a titolo informativo: reg identifica proprio il registro di destinazione.
Un pò come avviene per l'altra forma (8/16bit), se usi RAX (64bit) con un numero abbastanza grande come 0x123456789 (>32bit, altrimenti verrà utilizzato eax molto probabilmente), viene generato:
Codice:
48 B8 89 67 45 23 01 00 00 00
Dove 0x48 è un altro prefisso (REX prefix), 0xB8 è sempre l'opcode di prima. L'altro è il numero espresso come sempre usando little endian; nota che è stato esteso con 3byte a 0, venendo trattato come 64bit.
Ho forse sconfinato un pò troppo dalla domanda, ma spero sia comunque chiaro...