GUIDA Il Linguaggio Macchina di x86 e x86-64 (Parte 1)

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,208
1,845
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed

Il Linguaggio Macchina di x86 e x86-64 (Parte 1)​


Ho scritto e riscritto parzialmente questo articolo non so più quante volte, ogni qualvolta lo rileggevo, mi rendevo conto di aver trattato troppo alcuni argomenti e di aver così snaturato l'articolo stesso, l'oggetto di tutto: il linguaggio macchina di queste CPU.

Nell'articolo su 8086 risultava semplice un sunto minimale sulla CPU, senza andar troppo fuori dal seminato. In questo caso è differente. Ho deciso quindi di tralasciare gli aspetti relativi a queste due architetture e limitarmi a riportare quelli che sono i registri utilizzati, così come i set di istruzioni per giungere poi a ciò che è l'oggetto dell'articolo: la lunghezza delle istruzioni e i campi che le compongono, così come la codifica di questi registri in "linguaggio macchina".

Non sarà sicuramente un articolo di facile lettura ai "non informatici" (studenti o lavoratori), e per questo ho scelto di pubblicarlo - come il precedente - nella sezione relativa alla Programmazione.

Ho deciso di dividerlo in due parti, dove la prima riguarderà solamente i registri presenti in queste architetture e nei vari set mentre nella seconda parte si andrà a fondo, guardando il formato delle istruzioni e il codice macchina stesso (un pò come ho fatto con 8086).
Questa prima parte sarà povera di immagini e piuttosto schematica.
  1. Preambolo
  2. Registri a 32-bit
  3. Registri a 64-bit
  4. Registri a 80-bit
  5. Registri MMX (SIMD)
  6. Registri XMM (SSE, Streaming SIMD Extensions)
  7. Registri YMM (AVX)
  8. Registri ZMM (AVX-512)
  9. Conclusione prima parte

0 - Preambolo​

Alcuni concetti non saranno del tutto nuovi, si tratterà infatti di un'estensione di vecchi concetti, quelli relativi a 8086. Chi si sta avventurando nella lettura di questo articolo potrebbe trovare più confortevole un passaggio al precedente, Il linguaggio macchina di 8086.
Non è obbligatorio ai fini della comprensione, ma alleggerisce un minimo il carico di informazioni da elaborare.

1 - Registri a 32-bit​

La famiglia x86 racchiude i processori a 32bit. Tutti i registri di 8086 sono ancora presenti e sono stati estesi a 32bit.

reg_x86_gpr.png
Figura 1

La figura 1 dovrebbe essere esplicativa: in sostanza i registri di segmento sono rimasti quelli di prima ed hanno la medesima dimensione. I registri generali sono stati estesi, così come è stato esteso il registro IP, chiamato ora EIP, e il registro dei FLAGS, chiamato ora EFLAGS.

I registri CR, che sono registri di controllo; uno dei più noti è probabilmente CR3 in quanto contiene l'indirizzo fisico delle tabelle delle pagine quando si fa uso di memoria virtuale.
Riporto la descrizione dei registri tratta dall'articolo Memoria Virtuale: x64 Virtual Address Translation:

Riporto di seguito i signficati, solo a titolo informativo:
CR0: ogni bit ha un determinato significato, ed alcuni possono essere letti e scritti. Le info vanno dal tipo di cache utilizzato per un tipo di pagina, alla validità, all'accesso etc.
CR1: è riservato, la CPU genera una Invalid Opcode Exception se si tenta di accedervi;
CR2: riporta l'indirizzo che ha causato il Page Fault (#PF, per abbreviare);
CR3: indirizzo fisico della prima tabella delle pagine della gerarchia;
CR4: altre informazioni sullo stato di alcuni flags, sempre ampio 32bit;
CR5 e CR7: come CR1;

e i registri DR, per il debugging. Potete trovare maggiori info anche utilizzando Wikipedia oppure Wiki OSDev (le risorse saranno linkate al termine dell'articolo), senza perdervi nelle documentazioni di Intel.

2 - Registri a 64-bit​

reg_x64_gpr.png
Figura 2

Anche qui ci saranno alcune vecchie conoscenze risalenti a 8086. I registri sono poi stati estesi a 64bit e invece della E hanno come prefisso R (RAX, RBX,...). Non c'è modo di indirizzare direttamente la parte alta di RAX (o di uno di questi registri); la parte più bassa sarà sempre in EAX e così via.

Ma, un momento: dove sono finiti AH, CH, DH, BH? Esistono, ed hanno il medesimo significato di prima. Tuttavia hanno una limitazione importante: non si possono usare in presenza del REX prefix; lo vedremo in seguito più dettagliatamente, basti sapere che questo prefisso viene inserito quando vengono utilizati i nuovi registri che iniziano con la lettera R.

Sono poi stati aggiunti numerosi altri registri, come r8, r9 e a seguire gli altri. Anche qui è possibile accedere alla double word, word o byte, in questo caso usando uno dei suffissi (d, w, b).

3 - Registri a 80-bit​

Da i386 è stato introdotto un ulteriore chip, chiamato x87 Coprocessor, noto anche come FPU. E' l'unità che si occupa dei calcoli in virgola mobile, e che è presente ovviamente anche oggi nei moderni PC (ma integrata nella CPU).

Qui sono stati introdotti alcuni registri, 8 precisamente, da ST(0) a ST(7).

4 - Registri MMX (SIMD)​

Si tratta della prima generazione SIMD (Single Instruction, Multiple Data); sono stati introdotti registri e istruzioni che consentono di operare su dati a 64bit (dimensione dei registri MMX) e cosa più importante su "packet data"... 64-bit alla volta! Supponete di avere 4 word, per un totale quindi di 64-bit. Usando un registro MMX è possibile elaborare (moltiplicare, dividere etc etc) 4 word alla volta. In sostanza invece di fare 4 somme separate, se ne fa una unica.
Il concetto verrà ripreso più avanti, quindi chiariremo in seguito il loro utilizzo. I registri MMX (che sono 8, da MMX0 a MMX7) sono ormai obsoleti, e altri set di istruzioni hanno introdotto ulteriori registri (e istruzioni).

Faccio notare che sembra una cosa da poco forse, ma in applicazioni matematiche o che fanno uso di grafica, sono un passo avanti enorme. Si tratta di "parallelismo a livello di istruzione", e velocizza molto le operazioni. I software fanno ancora uso di set successivi a questo per applicazioni di questo tipo (oltre che ovviamente alla scheda video).

5 - Registri XMM (SSE, Streaming SIMD Extensions)​

I registri XMM sono a 128-bit. Si tratta di 8 registri in x86 da XMM0 a XMM7 ai quali se ne aggiungono altri 8 in x64, da XMM8 a XMM15.

Questo è un esempio di un codie che fa uso di SIMD per la somma di due vettori (compilabile con MSVC, GCC non è compatibile con questa sintassi, deve essere adattato):
C:
#include<stdio.h>

#define   LEN    12

int main() {
  int vect1[LEN] = {1,2,3,4,5,6,7,8,9,10,11,12};
  int vect2[LEN] = {1,2,3,4,5,6,7,8,9,10,11,12};

  int res_vect1[LEN];
 
  int i = 0;
 
  __asm
  {
    lea      eax, vect1
    lea      ebx, vect2
    xor      ecx, ecx

    _while:
    cmp      ecx, LEN * 4
    jge      _end
  
      movups   xmm0, [eax + ecx]
      movups   xmm1, [ebx + ecx]
  
      addps    xmm0, xmm1              
      movups   [res_vect1 + ecx], xmm0 
    
      add      ecx, 4
      jmp      _while
  
    _end:
 
  }

  printf("Sum:\n\tV = (");
  for(; i<LEN; i++) {
    printf("%d, ", *(res_vect1+i));
  }
  printf("\b\b)\n");

  return 0;
}

Vi lascio il link ad un articolo dove SIMD è stato utilizzato per velocizzare il calcolo dei frattali dell'insieme di Mandelbrot: https://nullprogram.com/blog/2015/07/10/

6 - Registri YMM (AVX)​

Questo set è conosciuto come AVX e vede l'introduzione di altre istruzioni e di nuovi registri che estendono i precedenti; i registri si chiamano YMM e sono a 256-bit. Come prima, sono 8 registri in x86 e 16 in x86-64.
Più tardi, come per SSE che vede più versioni, è arrivato AVX2, che aggiunge altre istruzioni.

Queste istruzioni le si riconosce subito, infatti iniziano tutte con una v.

7 - Registri ZMM (AVX-512)​

Questo è un nuovo set di istruzioni, si tratta di ben 32 registri da 512-bit e sono i registri ZMM.

8 - Conclusione prima parte​

Questa prima parte è conclusa, ed era più per fornire un'idea generale di registri e istruzioni presenti in queste architetture. La parte 2 entrerà nel vivo del codice macchina!
Spero di non aver fatto confusione, se notate qualcosa di non chiaro o altro, commentate qui sotto e fatemelo presente. Se avete domande, sentitevi liberi di chiedere.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!