2015-09-08 14 views
5

Sto giocando con ISA x86, quando ho provato ad usare nasm per convertire alcune istruzioni di assemblaggio alle istruzioni della macchina, ho trovato qualcosa di interessante.stessa istruzione di assemblaggio ma diversa istruzione macchina

mov [0x3412],al 
mov [0x3412], bl 
mov [0x3412], cl 
mov [0x3412], dl 

1 00000000 A21234     mov [0x3412], al 
2 00000003 881E1234    mov [0x3412], bl 
3 00000007 880E1234    mov [0x3412], cl 
4 0000000B 88161234    mov [0x3412], dl 

Come si può vedere, mov [0x3412], al è un'eccezione alla regola. Inoltre, ho trovato che mov [0x3412], al sta mappando a due diverse istruzioni macchina.

[email protected]:~/asm$ ndisasm 123 
00000000 88061234   mov [0x3412],al 
00000004 A21234   mov [0x3412],al 

Oltre a questa istruzione speciale, c'è qualche altra associazione di istruzioni di assemblaggio a più di una istruzione di macchina in x86?

+13

Ti sei imbattuto in un artefatto del design Intel di 808X. AX è un registro generale a 16 bit, ma Intel ha reso l'AX (o la versione high-low a 8 bit di AH e AL) speciale per alcune operazioni. Intel ha visto il registro AX come accumulatore. L'AX (e AH, AL) hanno una codifica speciale per alcune istruzioni (di solito prende meno un byte). È possibile scegliere di utilizzare l'istruzione più breve o più lunga (più breve è meglio per la memoria limitata). Oltre MOV, AX/AH/AL hanno una codifica speciale per ADC, ADD, AND, CMP, OR, SBB, SUB, TEST, XOR. –

+4

@ MichaelPetch: questa è in realtà la risposta, non un semplice commento! – usr2564301

+3

Se sei interessato a questo tipo di cose, dovresti assolutamente dare un'occhiata al riferimento alle istruzioni. – Jester

risposta

11

Quello che state osservando è un artefatto di una delle considerazioni progettuali che Intel ha realizzato con il processore 8088. Per rimanere compatibili con il processore 8088, i processori basati su x86 di oggi portano avanti alcune di queste considerazioni sul design, in particolare per quanto riguarda il set di istruzioni. In particolare, Intel ha deciso che l'8088 dovrebbe essere più efficiente con l'utilizzo della memoria a scapito delle prestazioni. Hanno creato un set di istruzioni CISC di lunghezza variabile che ha alcune codifiche speciali per limitare le dimensioni di alcune istruzioni. Questo differisce da molte architetture basate su RISC (come il vecchio Motorola 88000) che utilizzava istruzioni a lunghezza fissa ma poteva ottenere prestazioni migliori.

Il trade off tra la velocità e un set di istruzioni a lunghezza fissa o variabile era perché richiedeva più tempo al processore per decodificare le istruzioni di lunghezza variabile complesse utilizzate per ottenere alcune delle più piccole codifiche di istruzioni. Questo era vero per Intel 8088.

Nella letteratura più antica (circa 1980) le considerazioni per ottenere un migliore utilizzo dello spazio erano molto più importanti. Le informazioni nella mia risposta relative al registro AXI provengono da un libro sul mio scaffale dal titolo 8088 Assembler Language Programming: The IBM PC, tuttavia alcune informazioni possono essere trovate in articoli online come this.

Dall'articolo in linea queste informazioni sono molto applicabili alla situazione con AX (accumulatore) e altri registri generici come BX, CX, DX.

AX è il "accumulatore '';.

alcune operazioni, come MUL e DIV, richiedere che uno degli operandi tramite nell'accumulatore Alcune altre operazioni, come ADD e SUB, può essere applicato su qualsiasi registri (cioè, uno degli otto registri generali e di uso speciale), ma sono più efficaci quando si lavora con l'accumulatore.

BX è la "base '' registro ;

è l'unico registro di uso generale che può essere utilizzato per l'indirizzamento indiretto. Ad esempio, l'istruzione MOV [BX], AX fa sì che il contenuto di AX venga memorizzato nella posizione di memoria il cui indirizzo è indicato in BX.

CX è il "conteggio '' registro.

Le istruzioni loop (LOOP, Loope e LOOPNE), lo spostamento e ruotare istruzioni (RCL, RCR, ROL, ROR, SHL, SHR e SAR) e le istruzioni per le stringhe (con i prefissi REP, REPE e REPNE) utilizzano tutte il registro dei conteggi per determinare quante volte si ripeteranno.

DX è il "dati '' registro;

viene utilizzato insieme con AX per le operazioni MUL e DIV word-size, e può anche contenere il numero di porta per il IN e OUT istruzioni, ma è soprattutto disponibile come un luogo conveniente per memorizzare i dati, così come lo sono tutti gli altri registri di uso generale.

come potete vedere Intel destinato lo scopo generale registri per essere utilizzato per una varietà di cose, tuttavia anche loro potrebbe essere usato per scopi specifici e spesso aveva un significato speciale per le istruzioni a cui erano associati. Nel tuo caso stai osservando il fatto che AX è considerato come un accumulatore . Intel lo ha preso in considerazione e per un certo numero di istruzioni ha aggiunto opcode speciali per memorizzare in modo più efficiente un'istruzione completa. Hai trovato questo con l'istruzione MOV (con AX, AL), ma vale anche per ADC, ADD, AND, CMP, OR, SBB, SUB, TEST, XOR. Ognuna di queste istruzioni ha una codifica opcode più breve se utilizzata con AL, AX che richiede un byte in meno. In alternativa puoi codificare AX, AL con gli opcode più lunghi. Nel tuo caso:

00000000 88061234   mov [0x3412],al 
00000004 A21234   mov [0x3412],al 

Sono le stesse istruzioni ma con due codifiche differenti.

Questo è un buon HTML x86 instruction set reference disponibile online, tuttavia Intel fornisce uno strumento molto dettagliato instruction reference per architetture IA-32 (i386 ecc.) E 64 bit.

+2

Un altro caso di opcode di forma abbreviata è per rotazione di uno, salvando il byte 'imm8' per' rol/ror/rcl/rcr'. Grazie alla strana stranezza del CISC x86, ruoti di 1 set 'OF' (il flag di overflow) in base ai dati, ma ruota di altri conteggi lasciandoli indefiniti. Questo può valere solo per l'opcode di forma abbreviata, non per 'C1 C0 01' (forma lunga' rol eax, 1') Secondo http://agner.org/optimize/ e http://users.atw.hu /instlatx64/GenuineIntel00506E3_Skylake_InstLatX64.txt, Intel IvyBridge, Haswell e Skylake hanno un doppio throughput per il formato lungo. SandyBridge impiega 2 uop per entrambe le forme, anche 'count! = 1'. –