Intel x86 Assembly Language & Microarchitecture
Register Fundamentals
Ricerca…
Registri a 16 bit
Quando Intel ha definito l'8086 originale, era un processore a 16 bit con un bus indirizzo a 20 bit (vedere sotto). Hanno definito 8 registri a 16 bit generici, ma hanno assegnato loro ruoli specifici per determinate istruzioni:
-
AXIl registro Accumulatore.
Molti opcode hanno assunto questo registro o erano più veloci se specificato. -
DXIl registro dei dati.
A volte questo è stato combinato con i 16 bit alti di un valore a 32 bit conAX, ad esempio come risultato di un multiplo. -
CXIl registro dei conteggi.
Questo è stato utilizzato in una serie di istruzioni orientate al ciclo come contatore implicito per tali cicli - ad esempioLOOPNE(ciclo se non uguale) eREP(spostamento / confronto ripetuto) -
BXIl registro di base.
Questo potrebbe essere usato per indicizzare la base di una struttura in memoria - nessuno dei registri precedenti potrebbe essere usato per indicizzare direttamente nella memoria. -
SIIl registro dell'indice di origine.
Questo era l'indice implicito della fonte in memoria per determinate operazioni di spostamento e confronto. -
DIIl registro dell'indice di destinazione.
Questo era l'indice di destinazione implicito nella memoria per determinate operazioni di spostamento e confronto. -
SPIl registro del puntatore dello stack.
Questo è il registro meno generico nel set! Indicava la posizione corrente nello stack, che era utilizzata esplicitamente per le operazioniPUSHePOP, implicitamente perCALLeRETcon subroutine e MOLTO implicitamente durante gli interrupt. Come tale, usarlo per qualsiasi altra cosa era pericoloso per il tuo programma! -
BPIl registro del puntatore di base.
Quando le subroutine chiamano altre subroutine, lo stack contiene più "stack frames".BPpoteva essere usato per mantenere il frame dello stack corrente, e quando veniva chiamata una nuova subroutine, doveva essere salvata sullo stack, il nuovo stack frame creato e usato, e al ritorno dalla subroutine interna il vecchio valore del frame dello stack poteva essere ripristinato .
Gli appunti:
I primi tre registri non possono essere utilizzati per l'indicizzazione in memoria.
BX,SIeDIper indice di default nel segmento dati corrente (vedi sotto).MOV AX, [BX+5] ; Point into Data Segment MOV AX, ES:[DI+5] ; Override into Extra SegmentDI, quando utilizzato in operazioni da memoria a memoria comeMOVSeCMPS, utilizza esclusivamente il segmento aggiuntivo (vedere sotto). Questo non può essere ignorato.SPeBPutilizzano il segmento di stack (vedi sotto) per impostazione predefinita.
Registri a 32 bit
Quando Intel ha prodotto l'80386, è passato da un processore a 16 bit a uno a 32 bit. L'elaborazione a 32 bit significa due cose: entrambi i dati manipolati erano a 32 bit e gli indirizzi di memoria a cui si stava accedendo erano a 32 bit. Per fare ciò, ma rimangono comunque compatibili con i processori precedenti, hanno introdotto nuove modalità per il processore. Era in modalità a 16 bit o in modalità a 32 bit, ma era possibile ignorare questa modalità in base alle istruzioni per i dati, l'indirizzamento o entrambi!
Prima di tutto, hanno dovuto definire registri a 32 bit. Lo hanno fatto semplicemente estendendo gli otto esistenti da 16 bit a 32 bit e dando loro nomi "estesi" con un prefisso E : EAX , EBX , ECX , EDX , ESI , EDI , EBP ed ESP . I 16 bit inferiori di questi registri erano gli stessi di prima, ma le metà superiori dei registri erano disponibili per operazioni a 32 bit come ADD e CMP . Le metà superiori non erano accessibili separatamente come avevano fatto con i registri a 8 bit.
Il processore doveva disporre di modalità separate a 16 e 32 bit perché Intel utilizzava gli stessi codici opzionali per molte delle operazioni: CMP AX,DX in modalità a 16 bit e CMP EAX,EDX in modalità a 32 bit aveva esattamente gli stessi opcode ! Ciò significava che lo stesso codice NON poteva essere eseguito in nessuna delle due modalità:
L'opcode per "Sposta immediatamente in
AX" è0xB8, seguito da due byte del valore immediato:0xB8 0x12 0x34
L'opcode per "Sposta immediatamente in
EAX" è0xB8, seguito da quattro byte del valore immediato:0xB8 0x12 0x34 0x56 0x78
Quindi l'utente deve sapere in quale modalità si trova il processore durante l'esecuzione del codice, in modo che sappia emettere il numero corretto di byte.
Registri a 8 bit
I primi quattro registri a 16 bit potevano avere i loro byte superiore e inferiore a cui si accede direttamente come propri registri:
-
AHeALsono le metà alta e bassa del registroAX. -
BHeBLsono le metà alta e bassa del registroBX. -
CHeCLsono le metà alta e bassa del registroCX. -
DHeDLsono le metà alta e bassa del registroDX.
Nota che questo significa che alterare AH o AL modificherà immediatamente anche AX ! Si noti inoltre che qualsiasi operazione su un registro a 8 bit non può influenzare il suo "partner" - l'incremento di AL tale che esso trabocchi da 0xFF a 0x00 non altera AH .
I registri a 64 bit hanno anche versioni a 8 bit che rappresentano i loro byte più bassi:
-
SILperRSI -
DILperRDI -
BPLperRBP -
SPLperRSP
Lo stesso vale per i registri da R8 a R15 : le rispettive parti di byte inferiori sono denominate R8B - R15B .
Registri di segmento
Segmentazione
Quando Intel stava progettando l'8086 originale, c'erano già un certo numero di processori a 8 bit con capacità a 16 bit, ma volevano produrre un vero processore a 16 bit. Volevano anche produrre qualcosa di meglio e più capace di ciò che era già là fuori, quindi volevano essere in grado di accedere a più del massimo di 65.536 byte di memoria impliciti dai registri di indirizzamento a 16 bit.
Registri originali del segmento
Così hanno implementato l'idea di "Segmenti" - un blocco di memoria di 64 kilobyte indicizzato dai registri degli indirizzi a 16 bit - che potrebbe essere ri-basato per indirizzare diverse aree della memoria totale. Per contenere queste basi di segmenti, hanno incluso i registri di segmento:
-
CSIl registro del segmento di codice.
Ciò mantiene il segmento del codice attualmente in esecuzione, indicizzato dal registroIPimplicito (Puntatore di istruzioni). -
DSIl registro dei segmenti di dati.
Questo contiene il segmento predefinito per i dati manipolati dal programma. -
ESIl registro dei segmenti extra.
Questo contiene un secondo segmento di dati, per operazioni simultanee di dati attraverso la memoria totale. -
SSIl registro del segmento di stack.
Questo contiene il segmento di memoria che contiene lo stack corrente.
Dimensione del segmento?
I registri di segmento potevano essere di qualsiasi dimensione, ma rendendoli larghi 16 bit rendeva facile l'interoperabilità con gli altri registri. La prossima domanda era: i segmenti dovrebbero sovrapporsi e, in caso affermativo, quanto? La risposta a questa domanda determinerebbe la dimensione totale della memoria a cui si potrebbe accedere.
Se non ci fosse sovrapposizione, lo spazio di indirizzamento sarebbe 32 bit - 4 gigabyte - una dimensione inaudita in quel momento! Una sovrapposizione più "naturale" di 8 bit produrrebbe uno spazio di indirizzamento a 24 bit o 16 megabyte. Alla fine, Intel ha deciso di salvare altri quattro pin di indirizzo sul processore, rendendo lo spazio di indirizzamento di 1 megabyte con una sovrapposizione di 12 bit: lo consideravano sufficientemente grande per il tempo!
Più registri di segmenti!
Quando Intel stava progettando l'80386, ha riconosciuto che la suite esistente di 4 registri segmenti non era sufficiente per la complessità dei programmi che volevano che fosse in grado di supportare. Quindi hanno aggiunto altri due:
-
FSIl registro del segmento lontano -
GSIl registro dei segmenti globali
Questi nuovi registri di segmento non avevano alcun utilizzo forzato dal processore: erano semplicemente disponibili per qualsiasi cosa il programmatore volesse.
Alcuni dicono che i nomi sono stati scelti per continuare semplicemente il tema
C,D,Edel set esistente ...
Registri a 64 bit
AMD è un produttore di processori che aveva concesso in licenza il design dell'80386 di Intel per produrre versioni compatibili, ma in competizione. Hanno apportato modifiche interne al design per migliorare il throughput o altri miglioramenti del design, pur essendo ancora in grado di eseguire gli stessi programmi.
Per Intel one-up, hanno creato estensioni a 64 bit per il design Intel a 32 bit e hanno prodotto il primo chip a 64 bit che poteva ancora eseguire codice x86 a 32 bit. Intel ha finito per seguire il design di AMD nelle loro versioni dell'architettura a 64 bit.
Il design a 64 bit ha apportato una serie di modifiche al set di registri, pur rimanendo compatibile con le versioni precedenti:
- I registri general purpose esistenti sono stati estesi a 64 bit e denominati con un prefisso
R:RAX,RBX,RCX,RDX,RSI,RDI,RBPeRSP.Di nuovo, le metà inferiori di questi registri erano gli stessi registri
Eprefisso di prima, e le metà superiori non potevano essere accessibili in modo indipendente. - Altri 8 registri a 64 bit sono stati aggiunti e non nominati ma semplicemente numerati:
R8,R9,R10,R11,R12,R13,R14eR15.- La metà inferiore di 32 bit di questi registri è da
R8DaR15D(D per DWORD come al solito). - È possibile accedere ai 16 bit più bassi di questi registri con il suffisso di una
Wal nome del registro: daR8WaR15W.
- La metà inferiore di 32 bit di questi registri è da
- Ora è possibile accedere agli 8 bit più bassi di tutti i 16 registri:
- Il tradizionale
AL,BL,CLeDL; - I byte bassi dei registri puntatori (tradizionalmente):
SIL,DIL,BPLeSPL; - E i byte bassi degli 8 nuovi registri: da
R8BaR15B. - Tuttavia,
AH,BH,CHeDHsono inaccessibili nelle istruzioni che utilizzano un prefisso REX (per dimensioni di operando a 64 bit o per accedere a R8-R15 o per accedere aSIL,DIL,BPLoSPL). Con un prefisso REX, il pattern a bit del codice macchina che in genere significaAHindicaSPLe così via. Vedere la Tabella 3-1 del manuale di riferimento delle istruzioni di Intel (volume 2).
- Il tradizionale
Scrivendo su un registro a 32 bit si azzerano sempre i 32 bit superiori del registro a larghezza intera, diversamente dalla scrittura in un registro a 8 o 16 bit (che si fonde con il vecchio valore, che è una dipendenza extra per l'esecuzione fuori ordine ).
Registro delle bandiere
Quando l'unità logica aritmetica x86 (ALU) esegue operazioni come NOT e ADD , contrassegna i risultati di queste operazioni ("diventato zero", "overflow", "diventato negativo") in uno speciale registro FLAGS 16 bit. I processori a 32 bit l'hanno aggiornato a 32 bit e lo hanno chiamato EFLAGS , mentre i processori a 64 bit l'hanno aggiornato a 64 bit e lo hanno chiamato RFLAGS .
Codici di condizione
Ma non importa il nome, il registro non è direttamente accessibile (eccetto per un paio di istruzioni - vedi sotto). Invece, i singoli flag sono referenziati in alcune istruzioni, come il salto condizionale o il Set condizionale, noto come Jcc e SETcc dove cc significa "codice di condizione" e fa riferimento alla seguente tabella:
| Codice di stato | Nome | Definizione |
|---|---|---|
E , Z | Uguale, zero | ZF == 1 |
NE , NZ | Non uguale, non zero | ZF == 0 |
O | straripamento | OF == 1 |
NO | No Overflow | OF == 0 |
S | firmato | SF == 1 |
NS | Non firmato | SF == 0 |
P | Parità | PF == 1 |
NP | Nessuna parità | PF == 0 |
| -------------- | ---- | ---------- |
C , B , NAE | Carry, Below, Not Above or Ugual | CF == 1 |
NC , NB , AE | No Carry, Not Below, Above or Ugual | CF == 0 |
A , NBE | Sopra, non sotto o uguale | CF == 0 e ZF == 0 |
NA , BE | Non sopra, sotto o uguale | CF == 1 o ZF == 1 |
| --------------- | ---- | ---------- |
GE , NL | Maggiore o uguale, non minore | SF == OF |
NGE , L | Non maggiore o uguale, meno | SF ! = OF |
G , NLE | Maggiore, non minore o uguale | ZF == 0 e SF == OF |
NG , LE | Non maggiore, minore o uguale | ZF == 1 o SF ! = OF |
In 16 bit, sottrarre 1 da 0 è 65,535 o -1 seconda che venga utilizzata l'aritmetica non firmata o firmata, ma la destinazione mantiene 0xFFFF entrambi i casi. È solo interpretando i codici di condizione che il significato è chiaro. È ancora più significativo dire se 1 è sottratto da 0x8000 : in aritmetica senza segno, questo semplicemente cambia 32,768 in 32,767 ; mentre in aritmetica firmata cambia -32,768 in 32,767 - un overflow molto più degno di nota!
I codici di condizione sono raggruppati in tre blocchi nella tabella: segno-irrilevante, non firmato e firmato. La denominazione all'interno di questi ultimi due blocchi utilizza "Sopra" e "Sotto" per i non firmati e "Maggiore" o "Meno" per i firmati. Quindi JB sarebbe "Jump if Below" (senza segno), mentre JL sarebbe "Jump if Less" (firmato).
Accesso diretto ai FLAGS
I suddetti codici di condizione sono utili per interpretare concetti predefiniti, ma i bit di flag attuali sono anche disponibili direttamente con le seguenti due istruzioni:
-
LAHFcarica il registroAHcon le bandierine -
SAHFStoreAHregistrati in Flags
Solo alcune bandiere vengono copiate con queste istruzioni. L'intero registro FLAGS / EFLAGS / RFLAGS può essere salvato o ripristinato nello stack:
-
PUSHF/POPFpush / pop a 16 bitFLAGSsui / dai la pila -
PUSHFD/POPFDPush / pop a 32 bitEFLAGSsui / dai la pila -
PUSHFQ/POPFQpush / pop a 64 bitRFLAGSsulla / dalla pila
Notare che interrompe il salvataggio e ripristina automaticamente il registro [R/E]FLAGS corrente.
Altre bandiere
Oltre ai flag ALU descritti sopra, il registro FLAGS definisce altri flag di stato del sistema:
-
IFla bandiera di interruzione.
Questo viene impostato con l'istruzioneSTIper abilitare globalmente gli interrupt e cancellato con l'istruzioneCLIper disabilitare globalmente gli interrupt. -
DFLa bandiera di direzione.
Le operazioni da memoria a memoria comeCMPSeMOVS(per confrontare e spostarsi tra le posizioni di memoria) aumentano o diminuiscono automaticamente i registri indice come parte dell'istruzione. Il flagDFindica quale succede: se cancellato con l'istruzioneCLD, vengono incrementati; se impostati con l'istruzioneSTD, vengono decrementati. -
TFThe Trap Flag. Questa è una bandiera di debug. Impostandolo si metterà il processore in modalità "single-step": dopo l'esecuzione di ogni istruzione, chiamerà il "Single Step Interrupt Handler", che dovrebbe essere gestito da un debugger. Non ci sono istruzioni per impostare o cancellare questo flag: è necessario manipolare il bit mentre è in memoria.
80286 bandiere
Per supportare le nuove strutture di multitasking nell'80286, Intel ha aggiunto ulteriori flag al registro FLAGS :
-
IOPLIl livello di privilegio I / O.
Per proteggere il codice multitasking, alcune attività necessitavano di privilegi per accedere alle porte I / O, mentre altre dovevano essere fermate per accedervi. Intel ha introdotto una scala Privilege a quattro livelli, con002 il più privilegiato e112 il meno. SeIOPLera inferiore al livello di privilegio corrente, qualsiasi tentativo di accedere alle porte I / O o abilitare o disabilitare le interruzioni causerebbe invece un errore di protezione generale. -
NTNested Task flag.
Questo flag è stato impostato se una TaskCALLe un'altra Task, che ha causato un cambio di contesto. Il flag impostato indicava al processore di eseguire un cambio di contesto quando veniva eseguito ilRET.
80386 bandiere
Il 386 aveva bisogno di bandiere aggiuntive per supportare funzionalità extra progettate nel processore.
-
RFLa bandiera di ripresa.
Il `386 ha aggiunto i registri di debug, che potevano richiamare il debugger su vari accessi hardware come leggere, scrivere o eseguire una determinata posizione memry. Tuttavia, quando il gestore debug ritornava per eseguire l'istruzione, l'accesso richiamava immediatamente il gestore debug! O almeno lo sarebbe se non fosse per il Flag di Resume, che viene automaticamente impostato in entrata nel gestore di debug e automaticamente cancellato dopo ogni istruzione. Se il Flag di ripresa è impostato, il gestore di debug non viene richiamato. -
VMLa bandiera virtuale 8086.
Per supportare il vecchio codice a 16 bit e il nuovo codice a 32 bit, l'80386 poteva eseguire attività a 16 bit in modalità "Virtual 8086", con l'aiuto di un dirigente Virtual 8086. Il flagVMindicava che questa attività era un'attività virtuale 8086.
80486 bandiere
Con il miglioramento dell'architettura Intel, è diventato più veloce grazie a tecnologie come le cache e l'esecuzione super-scalare. Questo doveva ottimizzare l'accesso al sistema facendo delle ipotesi. Per controllare queste ipotesi, erano necessarie più bandiere:
- Flag di allineamento
ACL'architettura x86 può sempre accedere a valori di memoria multi-byte su qualsiasi limite di byte, a differenza di alcune architetture che richiedono che siano allineati in base alla dimensione (i valori a 4 byte devono essere presenti su contorni a 4 byte). Tuttavia, era meno efficiente farlo, poiché erano necessari più accessi di memoria per accedere ai dati non allineati. Se è stato impostato il flagAC, un accesso non allineato genererebbe un'eccezione anziché eseguire il codice. In questo modo, il codice potrebbe essere migliorato durante lo sviluppo con l'ACset, ma disattivato per il codice di produzione.
Pentium Flags
Il Pentium ha aggiunto più supporto per la virtualizzazione, oltre al supporto per l'istruzione CPUID :
-
VIFIl flag di interrupt virtuale.
Questa è una copia virtualeIFdi questa attività, indipendentemente dal fatto che questa attività desideri disattivare gli interrupt, senza influire effettivamente sugli interrupt globali. -
VIPThe Virtual Interrupt Pending Flag.
Ciò indica che un interrupt è stato virtualmente bloccato daVIF, quindi quando l'attività esegue unaSTIpuò essere generato un interrupt virtuale per esso. -
IDIl flagCPUID-allowed.
Se consentire o meno a questa attività di eseguire l'istruzioneCPUID. Un monitor virtuale potrebbe non permetterlo e "mentire" con l'attività richiedente se esegue l'istruzione.