Condividi tramite


Architettura x86

Il processore Intel x86 usa un'architettura CISC (Instruction Set Computer) complessa, il che significa che esiste un numero modesto di registri speciali anziché grandi quantità di registri per utilizzo generico. Significa anche che le istruzioni speciali complesse predominieranno.

Il processore x86 traccia il suo patrimonio almeno per quanto riguarda il processore Intel 8080 a 8 bit. Molte peculiarità nel set di istruzioni x86 sono dovute alla compatibilità con le versioni precedenti con quel processore (e con la sua variante Zilog Z-80).

Microsoft Win32 usa il processore x86 in modalità flat a 32 bit. Questa documentazione si concentrerà solo sulla modalità flat.

Registri

L'architettura x86 è costituita dai registri interi senza privilegi seguenti.

eax

Accumulatore

ebx

Registro di base

ecx

Registro contatori

edx

Registro dati: può essere usato per l'accesso alle porte di I/O e funzioni aritmetiche

Esi

Registro dell'indice di origine

Edi

Registro degli indici di destinazione

ebp

Registro del puntatore di base

Spagnolo

Puntatore dello stack

Tutti i registri integer sono a 32 bit. Tuttavia, molti di essi hanno sottoregistratori a 16 bit o a 8 bit.

ascia

Basso 16 bit di eax

Bx

Basso 16 bit di ebx

cx

Basso 16 bit di ecx

Dx

Basso 16 bit di edx

si

Basso 16 bit di esi

di

Basso 16 bit di edi

Bp

Basso 16 bit di ebp

Sp

Basso 16 bit di esp

ale

Basso 8 bit di eax

ah

Alto 8 bit di ax

laureato in legge

Basso 8 bit di ebx

Bh

Alto 8 bit di bx

Cl

Basso 8 bit di ecx

Ch

Alto 8 bit di cx

dl

Basso 8 bit di edx

Dh

Alto 8 bit di dx

L'uso di una sottoregister influisce solo sulla sottoregister e nessuna delle parti esterne alla sottoregister. Ad esempio, l'archiviazione nel registro ax lascia invariati i 16 bit alti del registro eax .

Quando si usa ? (Evaluate Expression) comando, i registri devono essere preceduti da un segno "at" ( @ ). Ad esempio, è consigliabile usare ? @ax anziché ? ax. In questo modo il debugger riconosce ax come registro anziché come simbolo.

Tuttavia, il parametro (@) non è necessario nel comando r (Registri). Ad esempio, r ax=5 verrà sempre interpretato correttamente.

Due altri registri sono importanti per lo stato corrente del processore.

eip

puntatore all'istruzione

flags

flags

Il puntatore all'istruzione è l'indirizzo dell'istruzione in esecuzione.

Il registro dei flag è una raccolta di flag a bit singolo. Molte istruzioni modificano i flag per descrivere il risultato dell'istruzione. Questi flag possono quindi essere testati tramite istruzioni di salto condizionale. Per informazioni dettagliate, vedere Flag x86.

Convenzioni di chiamata

L'architettura x86 ha diverse convenzioni di chiamata. Fortunatamente, tutti seguono le stesse regole di conservazione dei registri e restituzione delle funzioni:

  • Le funzioni devono mantenere tutti i registri, ad eccezione di eax, ecx edx, che possono essere modificati in una chiamata di funzione ed esp, che devono essere aggiornati in base alla convenzione di chiamata.

  • Il registro eax riceve i valori restituiti dalla funzione se il risultato è di 32 bit o minore. Se il risultato è a 64 bit, il risultato viene archiviato nella coppia edx:eax .

Di seguito è riportato un elenco di convenzioni di chiamata usate nell'architettura x86:

  • Win32 (__stdcall)

    I parametri della funzione vengono passati nello stack, inseriti da destra a sinistra e il chiamato pulisce lo stack.

  • Chiamata al metodo C++ nativa (nota anche come thiscall)

    I parametri della funzione vengono passati nello stack, inseriti da destra a sinistra, il puntatore "this" viene passato nel registro ecx e il chiamato pulisce lo stack.

  • COM (__stdcall per le chiamate al metodo C++)

    I parametri della funzione vengono passati nello stack, inseriti da destra a sinistra, quindi viene eseguito il push del puntatore "this" nello stack e quindi viene chiamata la funzione . Il chiamato pulisce lo stack.

  • __fastcall

    I primi due argomenti DWORD o più piccoli vengono passati nei registri ecx edx. I parametri rimanenti vengono passati nello stack, inseriti da destra a sinistra. Il chiamato pulisce lo stack.

  • __cdecl

    I parametri della funzione vengono passati nello stack, inseriti da destra a sinistra e il chiamante pulisce lo stack. La convenzione di chiamata __cdecl viene usata per tutte le funzioni con parametri a lunghezza variabile.

Visualizzazione del debugger di registri e flag

Di seguito è riportato un esempio di visualizzazione del registro del debugger:

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

Nel debug in modalità utente è possibile ignorare iopl e l'intera ultima riga della visualizzazione del debugger.

Flag x86

Nell'esempio precedente i codici a due lettere alla fine della seconda riga sono flag. Si tratta di registri a bit singolo e con un'ampia gamma di usi.

La tabella seguente elenca i flag x86:

Contrassegno codice Nome contrassegno Valore Stato flag Descrizione
di Overflow Flag 0 1 nvov Nessun overflow - Overflow
df Flag di direzione 0 1 updn Direzione verso l'alto - Direzione verso il basso
if Interrupt Flag 0 1 diei Interruzioni disabilitate - Interruzioni abilitate
Sf Contrassegno di firma 0 1 plng Positivo (o zero) - Negativo
zf Contrassegno zero 0 1 nzzr Diverso da zero - Zero
af Bandiera porta ausiliaria 0 1 naac Nessun trasporto ausiliario - Trasporto ausiliario
pf Contrassegno parità 0 1 Pepo Parità dispari - Parità pari
cfr Contrassegno di trasporto 0 1 nccy Nessun trasporto - Trasporto
tf Trap Flag Se tf è uguale a 1, il processore genererà un'eccezione STATUS_SINGLE_STEP dopo l'esecuzione di un'istruzione. Questo flag viene usato da un debugger per implementare la traccia in un unico passaggio. Non deve essere usato da altre applicazioni.
iopl Livello di privilegi di I/O Livello di privilegio I/O Questo è un numero intero a due bit, con valori compresi tra zero e 3. Viene usato dal sistema operativo per controllare l'accesso all'hardware. Non deve essere usato dalle applicazioni.

Quando i registri vengono visualizzati come risultato di un comando nella finestra Di comando del debugger, si tratta dello stato del flag visualizzato. Tuttavia, se si vuole modificare un flag usando il comando r (Registri), è necessario farvi riferimento dal codice del flag.

Nella finestra Registri di WinDbg il codice del flag viene usato per visualizzare o modificare i flag. Lo stato del flag non è supportato.

Ecco un esempio. Nella visualizzazione del registro precedente viene visualizzato lo stato del flag ng . Ciò significa che il flag del segno è attualmente impostato su 1. Per modificare questa operazione, usare il comando seguente:

r sf=0

In questo modo il flag del segno viene impostato su zero. Se si esegue un'altra visualizzazione del registro, il codice di stato ng non verrà visualizzato. Verrà invece visualizzato il codice di stato pl .

La bandiera del segno, la bandiera zero e la bandiera di trasporto sono i flag più usati.

Condizioni

Una condizione descrive lo stato di uno o più flag. Tutte le operazioni condizionali su x86 sono espresse in termini di condizioni.

L'assembler usa un'abbreviazione di una o due lettere per rappresentare una condizione. Una condizione può essere rappresentata da più abbreviazioni. Ad esempio, AE ("sopra o uguale") è la stessa condizione di NB ("not below"). Nella tabella seguente sono elencate alcune condizioni comuni e il relativo significato.

Nome condizione Flag significato

Z

ZF=1

Risultato dell'ultima operazione pari a zero.

NZ

ZF=0

Risultato dell'ultima operazione non pari a zero.

A

CF=1

L'ultima operazione richiedeva un trasporto o un prestito. Per i numeri interi senza segno, indica l'overflow.

NC

CF=0

L'ultima operazione non richiedeva un trasporto o un prestito. Per i numeri interi senza segno, indica l'overflow.

S

SF=1

Il risultato dell'ultima operazione ha un set di bit elevato.

NS

SF=0

Il risultato dell'ultima operazione è chiaro a bit elevato.

O

OF=1

Se considerato come operazione con segno integer, l'ultima operazione ha causato un overflow o un underflow.

NO

OF=0

Se considerato come operazione con segno integer, l'ultima operazione non ha causato un overflow o un underflow.

Le condizioni possono essere usate anche per confrontare due valori. L'istruzione cmp confronta i due operandi e quindi imposta i flag come se sottraesse un operando dall'altro. È possibile usare le condizioni seguenti per controllare il risultato di cmp value1, value2.

Nome condizione Flag Significato dopo un'operazione CMP.

E

ZF=1

value1 == value2.

NE

ZF=0

value1 != value2.

GE NL

SF=OF

value1>= value2. I valori vengono considerati numeri interi con segno.

LE NG

ZF=1 o SF!=OF

value1<= value2. I valori vengono considerati numeri interi con segno.

G NLE

ZF=0 e SF=OF

value1>value2. I valori vengono considerati numeri interi con segno.

L NGE

SF!=OF

value1<value2. I valori vengono considerati numeri interi con segno.

AE NB

CF=0

value1>= value2. I valori vengono considerati numeri interi senza segno.

BE NA

CF=1 o ZF=1

value1<= value2. I valori vengono considerati numeri interi senza segno.

Un'appliance virtuale di rete

CF=0 e ZF=0

value1>value2. I valori vengono considerati numeri interi senza segno.

B NAE

CF=1

value1<value2. I valori vengono considerati numeri interi senza segno.

Le condizioni vengono in genere usate per agire sul risultato di un'istruzione cmp o test . ad esempio:

cmp eax, 5
jz equal

confronta il registro eax con il numero 5 calcolando l'espressione (eax - 5) e impostando i flag in base al risultato. Se il risultato della sottrazione è zero, verrà impostato il flag zr e la condizione jz sarà true in modo che venga eseguito il salto.

Tipi di dati

  • byte: 8 bit

  • parola: 16 bit

  • dword: 32 bit

  • qword: 64 bit (include valori double a virgola mobile)

  • tword: 80 bit (include doppi estesi a virgola mobile)

  • oword: 128 bit

Notazione

La tabella seguente indica la notazione usata per descrivere le istruzioni del linguaggio assembly.

Notazione Significato

r, r1, r2...

Registri

m

Indirizzo di memoria (vedere la sezione Modalità di indirizzamento riuscito per altre informazioni).

#n

Costante immediata

r/m

Registrare o memoria

r/#n

Registra o costante immediata

r/m/#n

Registra, memoria o costante immediata

Cc

Codice di condizione elencato nella sezione Condizioni precedente.

T

"B", "W" o "D" (byte, parola o dword)

accT

Dimensione T): al se T = "B", ax se T = "W" o eax se T = "D"

Modalità di indirizzamento

Esistono diverse modalità di indirizzamento, ma tutte prendono il formato T ptr [expr], dove T è un tipo di dati (vedere la sezione Tipi di dati precedente) ed expr è un'espressione che coinvolge costanti e registri.

La notazione per la maggior parte delle modalità può essere dedotta senza molta difficoltà. Ad esempio, BYTE PTR [esi+edx*8+3] significa "prendere il valore del registro esi , aggiungerlo otto volte il valore del registro edx , aggiungere tre, quindi accedere al byte all'indirizzo risultante".

Pipelining

Il Pentium è a doppio problema, il che significa che può eseguire fino a due azioni in un tick di clock. Tuttavia, le regole su quando è in grado di eseguire due azioni contemporaneamente (note come associazione) sono molto complicate.

Poiché x86 è un processore CISC, non è necessario preoccuparsi degli slot di ritardo del salto.

Accesso alla memoria sincronizzato

Le istruzioni di caricamento, modifica e archiviazione possono ricevere un prefisso di blocco , che modifica l'istruzione nel modo seguente:

  1. Prima di eseguire l'istruzione, la CPU scarica tutte le operazioni di memoria in sospeso per garantire la coerenza. Tutti i prelettura dei dati vengono abbandonati.

  2. Durante l'emissione dell'istruzione, la CPU avrà accesso esclusivo al bus. In questo modo si garantisce l'atomicità dell'operazione di caricamento/modifica/archiviazione.

L'istruzione xchg rispetta automaticamente le regole precedenti ogni volta che scambia un valore con memoria.

Per impostazione predefinita, tutte le altre istruzioni non vengono bloccate.

Jump Prediction

I salti incondizionato vengono stimati per essere presi.

I salti condizionali vengono stimati per essere eseguiti o meno, a seconda che siano stati eseguiti l'ultima volta che sono stati eseguiti. La cache per la registrazione della cronologia dei salti è limitata.

Se la CPU non ha un record se il passaggio condizionale è stato eseguito o meno l'ultima volta che è stato eseguito, prevede salti condizionali indietro come eseguiti e salti condizionali in avanti come non eseguiti.

Allineamento

Il processore x86 correggerà automaticamente l'accesso alla memoria non idonea, con una riduzione delle prestazioni. Non viene generata alcuna eccezione.

Un accesso alla memoria viene considerato allineato se l'indirizzo è un multiplo intero delle dimensioni dell'oggetto. Ad esempio, tutti gli accessi BYTE sono allineati (tutto è un multiplo intero di 1), gli accessi di WORD agli indirizzi pari sono allineati e gli indirizzi DWORD devono essere un multiplo di 4 per essere allineati.

Il prefisso di blocco non deve essere usato per gli accessi alla memoria non idonei.