Memory Mapping en mode 64 bits

Salut ce forum est dédié à comprendre les entrailles de l'ordinateur au plus bas niveau bienvenue dans le monde du reverse et de l'assembleur

Moderator: Rick

Post Reply
Hydraxx
Site Admin
Posts: 114
Joined: Mon Jan 12, 2026 4:04 pm
Location: France
Contact:

Memory Mapping en mode 64 bits

Post by Hydraxx »

Memory Mapping en mode 64 bits

Dans le chapitre précédent, nous avons vu qu'un programme travaille principalement avec des adresses virtuelles et que le processeur doit les traduire en adresses physiques.

En mode x86-64, cette traduction repose sur une hiérarchie de tables de pages.

Le chemin classique pour une page de 4 Kio est :

Code: Select all

Adresse virtuelle
      |
      v
CR3
      |
      v
PML4
      |
      v
PDPT
      |
      v
Page Directory
      |
      v
Page Table
      |
      v
Page physique + offset
Comprendre ce mécanisme est particulièrement important en développement système, en kernel et en reverse engineering.

1. Le registre CR3

Le processeur doit connaître le point de départ de la hiérarchie des tables de pages.

Sur x86-64, le registre de contrôle CR3 joue ce rôle.

Dans le modèle présenté ici, CR3 permet de retrouver physiquement la table de plus haut niveau :

Code: Select all

PML4 = Page Map Level 4
Schématiquement :

Code: Select all

CR3
 |
 | adresse physique
 v
PML4
Une fois la PML4 trouvée, le processeur utilise une partie de l'adresse virtuelle comme index afin de sélectionner une entrée.

Cette entrée mène au niveau suivant.

Le même principe est répété jusqu'à obtenir la page physique contenant les données recherchées.

CR3 est donc un élément essentiel du contexte mémoire d'un processus. Lorsqu'un autre espace d'adressage doit être utilisé, le système doit faire en sorte que le processeur utilise les tables correspondantes.

2. Décomposition d'une adresse virtuelle x86-64

Dans le modèle classique à quatre niveaux présenté dans ce chapitre, tous les 64 bits ne servent pas directement d'index pour la traduction.

Une adresse virtuelle est découpée ainsi :

Code: Select all

63                         48 47       39 38       30 29       21 20       12 11        0
+----------------------------+-----------+-----------+-----------+-----------+------------+
| extension / bits supérieurs|   PML4    |   PDPT    |    PD     |    PT     |   offset   |
+----------------------------+-----------+-----------+-----------+-----------+------------+
                               9 bits      9 bits      9 bits      9 bits      12 bits
Pour la partie traduite sur 48 bits :

Code: Select all

PML4 index = bits 47-39
PDPT index = bits 38-30
PD index   = bits 29-21
PT index   = bits 20-12
offset     = bits 11-0
Pourquoi 12 bits pour l'offset ?

Parce qu'une page classique contient :

Code: Select all

4096 octets = 2^12 octets
Il faut donc 12 bits pour sélectionner n'importe quel octet à l'intérieur d'une page de 4 Kio.

Pourquoi 9 bits pour chaque index ?

Code: Select all

2^9 = 512
Chaque niveau peut donc sélectionner l'une des 512 entrées de la table correspondante.

3. Adresses canoniques

Dans le modèle x86-64 à 48 bits utilisé par le chapitre, les bits supérieurs d'une adresse ne sont pas simplement des bits arbitraires.

Les adresses utilisées doivent respecter la forme dite canonique.

Avec un espace virtuel sur 48 bits, les bits 63 à 48 correspondent à une extension du bit 47.

On obtient donc schématiquement deux grandes zones d'adresses canoniques séparées par une plage qui ne représente pas des adresses valides dans ce mode.

Pour comprendre la traduction décrite dans ce chapitre, les bits réellement utilisés pour choisir les quatre niveaux et l'offset sont donc :

Code: Select all

47 ... 0
4. PML4 — Page Map Level 4

La PML4 constitue le premier niveau de la traduction dans cette organisation à quatre niveaux.

CR3 permet d'en retrouver la base physique.

Les bits :

Code: Select all

47 - 39
de l'adresse virtuelle servent d'index dans la PML4.

Cet index comporte 9 bits :

Code: Select all

0 à 511
Supposons par exemple :

Code: Select all

CR3 = adresse physique de la PML4
index PML4 = 1
Le processeur consulte alors l'entrée numéro 1 de cette table.

Conceptuellement :

Code: Select all

PML4
+---------------------+
| entrée 0            |
+---------------------+
| entrée 1 ---------- | ----> PDPT
+---------------------+
| entrée 2            |
+---------------------+
| ...                 |
+---------------------+
| entrée 511          |
+---------------------+
L'entrée ne contient pas simplement une adresse : une entrée de table de pages contient également plusieurs bits de contrôle.

Ces bits peuvent notamment indiquer si l'entrée est valide/présente et quelles opérations sont autorisées.

5. Page Directory Pointer Table — PDPT

Une fois la bonne entrée de PML4 obtenue, le processeur atteint une :

Code: Select all

Page Directory Pointer Table
ou PDPT.

Les bits :

Code: Select all

38 - 30
de l'adresse virtuelle servent d'index dans cette table.

Encore une fois :

Code: Select all

9 bits
2^9 = 512 possibilités
L'entrée sélectionnée permet normalement de poursuivre vers un Page Directory.

Le chemin devient :

Code: Select all

CR3
 |
 v
PML4[index 47-39]
 |
 v
PDPT[index 38-30]
6. Page Directory

Le niveau suivant est le Page Directory, souvent abrégé PD.

Les bits utilisés sont :

Code: Select all

29 - 21
Ils fournissent encore un index compris entre 0 et 511.

L'entrée choisie permet, dans le cas classique d'une page de 4 Kio, de retrouver la Page Table suivante.

Code: Select all

CR3
 |
 v
PML4
 |
 v
PDPT
 |
 v
Page Directory
 |
 v
Page Table
Nous verrons cependant qu'avec les grandes pages, la traduction peut se terminer plus tôt.

7. Page Table

La Page Table constitue le dernier niveau pour une traduction classique vers une page de 4 Kio.

Les bits :

Code: Select all

20 - 12
sélectionnent l'entrée de Page Table.

Cette entrée permet de déterminer la page physique correspondante.

Il reste ensuite :

Code: Select all

bits 11 - 0
Ces 12 bits constituent l'offset à l'intérieur de la page.

Le résultat peut être représenté ainsi :

Code: Select all

Adresse virtuelle
      |
      +--> PML4 index
      +--> PDPT index
      +--> PD index
      +--> PT index
      +--> offset
                 |
                 v
        adresse dans la page
La traduction donne donc la base d'une page physique, puis l'offset indique quel octet de cette page est réellement demandé.

8. Traduction complète d'une adresse virtuelle

Prenons une adresse virtuelle quelconque :

Code: Select all

VA = 0x0000123456789012
Pour une page de 4 Kio, on peut extraire les différents champs avec des décalages et des masques.

Code: Select all

PML4 = (VA >> 39) & 0x1FF
PDPT = (VA >> 30) & 0x1FF
PD   = (VA >> 21) & 0x1FF
PT   = (VA >> 12) & 0x1FF
OFF  = VA & 0xFFF
Le masque :

Code: Select all

0x1FF
correspond à 9 bits à 1.

Le masque :

Code: Select all

0xFFF
correspond à 12 bits à 1.

Le processeur effectue conceptuellement :

Code: Select all

1. Lire CR3
2. Trouver la PML4
3. Utiliser les bits 47-39
4. Trouver la PDPT
5. Utiliser les bits 38-30
6. Trouver le Page Directory
7. Utiliser les bits 29-21
8. Trouver la Page Table
9. Utiliser les bits 20-12
10. Obtenir la page physique
11. Ajouter les bits 11-0 comme offset
Une manière de retenir le découpage est :

Code: Select all

9 + 9 + 9 + 9 + 12 = 48 bits
9. Exemple de calcul des index

Pour comprendre concrètement le mécanisme, on peut écrire une petite logique équivalente en C/C++ :

Code: Select all

uint64_t address = 0x0000123456789012;

uint64_t pml4Index = (address >> 39) & 0x1FF;
uint64_t pdptIndex = (address >> 30) & 0x1FF;
uint64_t pdIndex   = (address >> 21) & 0x1FF;
uint64_t ptIndex   = (address >> 12) & 0x1FF;
uint64_t offset    = address & 0xFFF;
Attention : ce code ne traduit pas réellement l'adresse virtuelle en adresse physique.

Il ne fait qu'extraire les cinq champs de l'adresse.

Pour effectuer la traduction réelle, il faudrait également connaître et lire les tables de pages correspondantes.

10. Pourquoi plusieurs niveaux ?

On pourrait imaginer une gigantesque table contenant directement une entrée pour chaque page virtuelle.

Le problème serait sa taille.

Avec des pages de 4 Kio, un immense espace virtuel pourrait nécessiter un nombre gigantesque d'entrées, même si le processus n'utilise réellement qu'une petite partie de cet espace.

Une structure hiérarchique permet de ne créer les tables intermédiaires que lorsqu'elles sont nécessaires.

On obtient donc un compromis entre :
  • taille des structures de traduction ;
  • flexibilité ;
  • gestion d'un espace virtuel immense ;
  • coût de la traduction.
11. Large Pages

La page classique étudiée jusqu'ici possède une taille de :

Code: Select all

4 Kio
x86-64 permet également d'utiliser des pages plus grandes.

Un cas important est la page de :

Code: Select all

2 Mio = 2^21 octets
Avec une page de 2 Mio, il faut :

Code: Select all

21 bits
pour représenter l'offset à l'intérieur de la page.

La traduction peut donc s'arrêter au niveau du Page Directory.

Schématiquement :

Code: Select all

Page 4 Kio :

CR3
 -> PML4
 -> PDPT
 -> PD
 -> PT
 -> page 4 Kio


Page 2 Mio :

CR3
 -> PML4
 -> PDPT
 -> PD
 -> page 2 Mio
Pour une page de 2 Mio, les bits :

Code: Select all

20 - 0
servent d'offset.

Les grandes pages permettent notamment de couvrir davantage de mémoire avec moins d'entrées de traduction.

Cela peut réduire la pression exercée sur certaines structures de traduction, notamment le TLB.

En contrepartie, une page beaucoup plus grande est moins fine : réserver une grande page pour une petite quantité de données peut gaspiller davantage de mémoire.

12. TLB — Translation Lookaside Buffer

Le parcours :

Code: Select all

PML4 -> PDPT -> PD -> PT
nécessite plusieurs accès mémoire.

Effectuer systématiquement tout ce parcours avant chaque accès aux données serait coûteux.

Les processeurs utilisent donc un cache spécialisé appelé :

TLB — Translation Lookaside Buffer

Le TLB mémorise des traductions récentes entre pages virtuelles et pages physiques.

Conceptuellement :

Code: Select all

CPU veut accéder à une adresse virtuelle
             |
             v
          Cherche TLB
          /        \
       trouvé     absent
         |           |
         v           v
     TLB hit     TLB miss
         |           |
         |       page walk
         |           |
         +-------> traduction
TLB hit

La traduction recherchée est déjà présente dans le TLB.

Le processeur peut réutiliser rapidement l'information.

TLB miss

La traduction n'est pas présente dans le TLB.

Le processeur doit effectuer un page walk, c'est-à-dire parcourir les structures de pagination nécessaires pour retrouver la traduction.

La nouvelle traduction peut ensuite être mise en cache dans le TLB.

Le TLB possède évidemment une capacité limitée. Il ne peut pas conserver les traductions de toutes les pages virtuelles existantes.

13. Intérêt des grandes pages pour le TLB

Une entrée TLB correspondant à une page de 4 Kio couvre :

Code: Select all

4096 octets
Une traduction correspondant à une page de 2 Mio couvre beaucoup plus de mémoire.

Ainsi, pour certaines charges de travail manipulant de grandes zones mémoire, les grandes pages peuvent permettre à un nombre limité d'entrées TLB de couvrir davantage de mémoire.

C'est l'un des intérêts des large pages.

Cela ne signifie cependant pas que les grandes pages sont systématiquement meilleures : leur utilisation dépend du programme et de ses besoins.

14. Intérêt pour le reverse engineering

Dans un débogueur user mode comme x64dbg, on manipule principalement des adresses virtuelles.

Par exemple :

Code: Select all

00007FF6........
est une adresse dans l'espace virtuel du processus analysé.

Pour la plupart des analyses user mode, il n'est pas nécessaire de refaire manuellement le parcours complet des tables de pages.

Cependant, connaître le mécanisme permet de comprendre ce qui se trouve derrière une adresse affichée par le débogueur.

Cela devient encore plus intéressant lorsqu'on travaille avec :
  • WinDbg en kernel ;
  • les structures mémoire du noyau ;
  • les Page Table Entries ;
  • la mémoire physique ;
  • les protections de pages ;
  • l'analyse bas niveau d'un processus.
15. Intérêt pour le développement kernel

En développement kernel, la distinction entre adresse virtuelle et adresse physique devient particulièrement importante.

Il faut retenir qu'une adresse comme :

Code: Select all

0xFFFF....
n'est pas simplement "une adresse dans la RAM".

C'est une adresse virtuelle qui doit être interprétée dans le contexte de l'espace d'adressage et des tables de pages correspondantes.

La chaîne fondamentale à connaître est donc :

Code: Select all

CR3
 |
 v
PML4
 |
 v
PDPT
 |
 v
PD
 |
 v
PT
 |
 v
Page physique
Le processeur accélère ensuite énormément cette opération grâce au TLB et à d'autres mécanismes matériels de cache.

16. Points essentiels à retenir
  • x86-64 utilise une pagination hiérarchique ;
  • CR3 permet de retrouver la racine des tables de pages ;
  • dans le modèle à quatre niveaux, cette racine est la PML4 ;
  • la traduction classique utilise PML4, PDPT, Page Directory et Page Table ;
  • chaque index classique fait 9 bits ;
  • 9 bits permettent de sélectionner 512 entrées ;
  • une page de 4 Kio utilise un offset de 12 bits ;
  • le découpage classique est 9 + 9 + 9 + 9 + 12 = 48 bits ;
  • une entrée de table contient une adresse ainsi que des bits de contrôle ;
  • les grandes pages permettent de terminer la traduction plus tôt ;
  • une page de 2 Mio utilise un offset de 21 bits ;
  • le TLB met en cache les traductions récentes ;
  • un TLB miss peut entraîner un page walk ;
  • ces notions sont particulièrement utiles en kernel, debugging et reverse engineering.
17. Exercices

Exercice 1 — Taille d'une page

Une page possède une taille de :

Code: Select all

4096 octets
Combien de bits sont nécessaires pour représenter l'offset à l'intérieur de cette page ?

Exercice 2 — Nombre d'entrées

Un index de table de pages possède 9 bits.

Combien d'entrées différentes peut-il sélectionner ?

Exercice 3 — Extraction de l'offset

Pour l'adresse :

Code: Select all

0x0000123456789012
quel masque utiliserais-tu pour récupérer l'offset d'une page de 4 Kio ?

Exercice 4 — Décomposition

Décompose l'adresse virtuelle suivante :

Code: Select all

0x0000123456789012
en :

Code: Select all

PML4 index
PDPT index
PD index
PT index
offset
Utilise :

Code: Select all

PML4 = (VA >> 39) & 0x1FF
PDPT = (VA >> 30) & 0x1FF
PD   = (VA >> 21) & 0x1FF
PT   = (VA >> 12) & 0x1FF
OFF  = VA & 0xFFF
Exercice 5 — Page de 2 Mio

Une page possède maintenant une taille de :

Code: Select all

2 Mio = 2^21 octets
Combien de bits faut-il pour l'offset ?

À quel niveau la traduction peut-elle s'arrêter dans le cas étudié dans ce chapitre ?

Exercice 6 — TLB

Explique la différence entre :

Code: Select all

TLB hit
TLB miss
Puis explique pourquoi le TLB améliore fortement les performances.

Exercice 7 — Reverse/kernel

Dans un débogueur, tu observes :

Code: Select all

Adresse virtuelle -> données du processus
Explique pourquoi cette adresse ne correspond pas nécessairement directement à la même valeur numérique en RAM physique.

Décris ensuite le chemin général permettant au processeur d'obtenir la page physique :

Code: Select all

CR3 -> ? -> ? -> ? -> ? -> page physique

Who is online

Users browsing this forum: No registered users and 1 guest