Aller au contenu

Fonctionnement d'un ordinateur/L'espace d'adressage du processeur

Un livre de Wikilivres.

L'espace d'adressage du processeur correspond à l'ensemble des adresses utilisables par le processeur. Par exemple, si je prends un processeur 16 bits, il peut adresser en tout 2^16 = 65536 adresses et l'ensemble de ces adresses forme son espace d'adressage. L'espace d'adressage n'est pas la mémoire réellement installée : s'il n'y a pas assez de RAM installée, des adresses seront inoccupées. De plus, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques, comme nous le verrons plus bas. Nous verrons aussi dans ce chapitre qu'il est possible qu'un processeur ait plusieurs espaces d'adressages séparés. Et même si cela peut sembler contre-intuitif, nous allons voir que les architectures avec plusieurs espaces d'adressage sont plus simples à comprendre !

L'adressage de la RAM et de la ROM

[modifier | modifier le wikicode]

Avoir plusieurs espaces d'adressage spécialisés est quelque chose que nous avons déjà rencontré dans les chapitres précédents, mais sans le dire ouvertement. Aussi, nous allons faire quelques rappels succincts sur les cas déjà rencontrés. En premier lieu, nous allons rappeler la différence entre architectures Von Neumann et Hardvard. La différence entre les deux tient dans l'adressage de la mémoire RAM et de la mémoire ROM : est-ce que les deux sont dans un seul espace d'adressage, ou est-ce qu'elles ont chacun leur propre espace d'adressage séparé.

Les architectures Von Neumann

[modifier | modifier le wikicode]

Si on n'a qu'un seul espace d'adressage unique, il est utilisé pour adresser non seulement la mémoire RAM, mais aussi la mémoire ROM. On est alors face à une architecture Von Neumann, où un seul espace d'adressage est découpé entre la mémoire RAM d'un côté et la mémoire ROM de l'autre. Une adresse correspond soit à la mémoire RAM, soit à la mémoire ROM, mais pas aux deux. Typiquement, la mémoire ROM est placée dans les adresses hautes, les plus élevées, alors que la RAM est placée dans les adresses basses en commençant par l'adresse 0. C'est une convention qui n'est pas toujours respectée, aussi mieux vaut éviter de la tenir pour acquise.

Vision de la mémoire par un processeur sur une architecture Von Neumann.

Les architectures Harvard

[modifier | modifier le wikicode]

Avec l'architecture Harvard, on a un espace d'adressage séparé pour la RAM et la ROM. Une même adresse peut correspondre soit à la ROM, soit à la RAM : le processeur voit bien deux mémoires séparées, chacune dans son propre espace d'adressage. Les deux espaces d'adressage n'ont pas forcément la même taille : l'un peut contenir plus de mémoire/adresses que l'autre. Il est par exemple possible d'avoir un plus gros espace d'adressage pour la RAM que pour la ROM. Mais cela implique que les adresses des instructions et des données soient de taille différentes. C'est peu pratique et c'est rarement implémenté, ce qui fait que le cas le plus courant est celui où les deux espaces d'adressages ont la même taille.

Vision de la mémoire par un processeur sur une architecture Harvard.

L'adressage des périphériques

[modifier | modifier le wikicode]

Si l'adressage des mémoires RAM/ROM est important, il faut aussi penser à l'adressage des périphériques. En effet, la communication avec les périphériques se fait par l'intermédiaire de registres d’interfaçage. Et là encore, ces registres peuvent avoir un espace d'adressage séparé, ou être inclus dans l'espace d'adressage des mémoires. Dans ce qui suit, nous allons supposer que l'architecture des de type Von Neumann pour simplifier les explications.

L'espace d'adressage séparé pour les entrées-sorties

[modifier | modifier le wikicode]

Les entrées-sorties et périphériques peuvent avoir leur propre espace d'adressage dédié, séparé de celui utilisé pour les mémoires. Sur ce genre d'architectures, on trouve un espace d'adressage pour la mémoire RAM et la mémoire ROM, et un espace d'adressage spécialisé pour les périphériques et les entrées-sorties.

Bit IO.

Une même adresse peut donc adresser soit une entrée-sortie, soit une case mémoire. Et pour faire la différence, le processeur doit avoir des instructions séparées pour adresser les périphériques et la mémoire. Il a des instructions de lecture/écriture pour lire/écrire en mémoire, et d'autres pour lire/écrire les registres d’interfaçage. Sans cela, le processeur ne saurait pas si une adresse est destinée à un périphérique ou à la mémoire. Cela élimine aussi les problèmes avec les caches : les accès à l'espace d'adressage de la RAM passent par l'intermédiaire de la mémoire cache, alors les accès dans l'espace d'adressage des périphériques le contournent totalement.

Là encore, les deux espaces d'adressage n'ont pas forcément la même taille. Il arrive que les deux espaces d'adressage aient la même taille, le plus souvent sur des ordinateurs complexes avec beaucoup de périphériques. Mais les systèmes embarqués ont souvent des espaces d'adressage plus petits pour les périphériques que pour la ou les mémoires. L'implémentation varie grandement suivant le cas, la première méthode imposant d'avoir deux bus séparés pour les mémoires et les périphériques, l'autre permettant un certain partage du bus d'adresse. Nous reviendrons dessus plus en détail dans le chapitre sur l'adressage des périphériques.

Les entrées-sorties mappées en mémoire

[modifier | modifier le wikicode]

Sur les ordinateurs avec un seul espace d'adressage, une partie de l'espace d'adressage peut être détourné pour communiquer avec les périphériques. L'idée est que le périphérique se retrouve inclus dans l'ensemble des adresses utilisées pour manipuler la mémoire : on dit qu'il est mappé en mémoire. Les adresses mémoires associées à un périphérique sont redirigées automatiquement vers le périphérique en question. On parle alors d'entrées-sorties mappées en mémoire.

IO mappées en mémoire

On remarque ainsi le défaut inhérent à cette technique : les adresses utilisées pour les périphériques ne sont plus disponibles pour la mémoire RAM. Dit autrement, on ne peut plus adresser autant de mémoire qu'avant. La perte peut être très légère ou très importante, en fonction des périphériques installés et de leur gourmandise en adresses mémoires. C'est ce qui causait autrefois un problème assez connu sur les ordinateurs 32 bits, qui ne géraient que 2^32 octets = 4 gibioctets. Certaines personnes installaient 4 gigaoctets de mémoire sur leur ordinateur 32 bits et se retrouvaient avec « seulement » 3,5 à 3,8 gigaoctets de mémoire, les périphériques prenant le reste.

Notons qu'il est possible que la RAM d'un périphérique soit mappée en RAM. Un exemple classique est celui des cartes graphiques qui incorporent une mémoire RAM appelée la mémoire vidéo. La mémoire vidéo est mappée en mémoire, ce qui permet au processeur d'écrire directement dedans. Toute lecture ou écriture dans les adresses associées est redirigée vers le bus PCI/AGP/PCI-Express. Nous verrons plus bas des exemples d'ordinateurs où la mémoire vidéo est mappée en mémoire, que ce soit totalement ou partiellement.

Si je dis totalement ou partiellement, c'est parce que les cartes graphiques modernes disposent de tellement de mémoire qu'on ne peut pas la mapper totalement dans l'espace d'adressage. Sur les systèmes 32 et 64 bits, avec un bus PCI-Express d'avant 2008, seuls 256 mégaoctets de mémoire vidéo sont mappés en mémoire RAM. Le reste de la mémoire vidéo est invisible du point de vue du processeur, mais manipulable par le GPU à sa guise. Après 2008, la spécification du PCI-Express ajouta un support de la technologie Resizable Bar, qui permet au processeur d’accéder directement à plus de 256 mégaoctets de mémoire vidéo, voire à la totalité de la mémoire vidéo.

La memory map d'un ordinateur

[modifier | modifier le wikicode]

Les deux sections précédentes nous ont appris que l'on peut utiliser un espace d'adressage séparé pour la ROM et un autre pour les périphériques. En tout, cela donne quatre possibilités distinctes.

IO mappées en mémoire IO séparées
ROM mappée en mémoire (architecture Von Neumann) Un seul espace d'adressage Deux espaces d'adressage :
  • un pour les mémoires RAM/ROM ;
  • un pour les IO.
ROM séparée (architecture Harvard) Deux espaces d'adressage :
  • un pour la RAM et les IO ;
  • un pour la ROM.
Trois espaces d'adressages :
  • un pour la RAM ;
  • un pour la ROM ;
  • un pour les IO.

Les quatre solutions ont des avantages et inconvénients divers, mais il est intéressant de contraster un espace d'adressage unique avec plusieurs espaces d'adressages. Avec un seul espace d'adressage, des adresses censées être disponibles pour la RAM sont détournées vers la ROM ou les périphériques. Et cela limite la quantité de RAM qui peut être réellement adressée en pratique.

Mais c'est un défaut qui se manifeste seulement pour les petits espaces d'adressages, de 8 à 16 bits, pour lesquels on ne peut pas adresser beaucoup de RAM. Par exemple, avec des adresses codées sur 16 bits, utiliser un espace d'adressage unique serait compliqué. On est déjà limité à 64 kibioctets de RAM, si on rajoute une ROM et beaucoup d'entrées-sorties, la quantité de RAM chute rapidement. Par contre, pour des adresses de 32 à 64 bits, l'usage d'un espace d'adressage unique est clairement la solution la plus simple. Une bonne partie de l'espace d'adressage est inutilisé, car il n'y a pas assez de RAM. Détourner ces adresses inutilisées pour mapper une ROM ou des entrées-sorties permet de mieux utiliser l'espace d'adressage.

Avec un espace d'adressage unique, les adresses hautes sont réservées aux périphériques et aux mémoires ROM, alors que les adresses basses sont pour la RAM. La ROM est au sommet de l'espace d'adressage, les périphériques sont juste en-dessous, la RAM commence à l'adresse 0 et prend les adresses basses. Faire simplifie grandement l'implémentation matérielle de l'adressage.

Espace d'adressage classique avec entrées-sorties mappées en mémoire

Notons que d'autres composants que les périphériques ou les mémoires peuvent se trouver dans l'espace d'adressage. On peut y trouver les horloges temps réels, des timers, des senseurs de température, ou d'autres composants placés sur la carte mère. Un exemple un peu original est le suivant : la console de jeu Nintendo DS incorporait une unité de calcul spécialisée dans les divisions et racines carrées, séparée du processeur, qui était justement mappée en mémoire !

Les premiers micro-ordinateurs et consoles de jeux

[modifier | modifier le wikicode]

Les vielles machines, notamment les premiers ordinateurs comme les Commodores et les Amiga et les vielles consoles de jeux, utilisaient un espace d'adressage unique. Elles n'avaient pas une variété de cartes graphiques ou de cartes sons différentes, comme sur les PCs modernes. Au contraire, elles avaient la même configuration matérielle, le matériel ne pouvait pas être changé ni upgradé.

De plus, de telles machines n'avaient pas de système d'exploitation, ou bien celui-ci était rudimentaire et ne contrôlait pas vraiment l'accès au matériel. Les programmeurs avaient donc totalement accès au matériel et mapper les entrées/sorties en mémoire rendait la programmation des périphériques très simple.

La commutation de banques (bank switching)

[modifier | modifier le wikicode]

Le bank switching, aussi appelé commutation de banque, permet d'utiliser plusieurs espaces d'adressage sur un même processeur, sans attribuer chaque espace d'adressage pour une raison précise. L'espace d'adressage est présent en plusieurs exemplaires appelés des banques. Les banques sont numérotées, chaque numéro de banque permettant de l'identifier et de le sélectionner.

Le but de cette technique est d'augmenter la mémoire disponible pour l'ordinateur. Par exemple, supposons que j'ai besoin d'adresser une mémoire ROM de 4 kibioctets, une RAM de 8 kibioctets, et divers périphériques. Le processeur a un bus d'adresse de 12 bits, ce qui limite l'espace d'adressage à 4 kibioctets. Dans ce cas, je peux réserver 4 banques : une pour la ROM, une pour les périphériques, et deux banques qui contiennent chacune la moitié de la RAM. La simplicité et l'efficacité de cette technique font qu'elle est beaucoup utilisée dans l'informatique embarquée.

exemple de Bank switching.

Cette technique demande d'utiliser un bus d'adresse plus grand que les adresses du processeur. L'adresse réelle se calcule en concaténant le numéro de banque avec l'adresse accédée. Le numéro de la banque actuellement en cours d'utilisation est mémorisé dans un registre appelé le registre de banque. On peut changer de banque en changeant le contenu de ce registre. Le processeur dispose souvent d'instructions spécialisées qui en sont capables.

Banque mémoire. Registre de banque.

La memory map des PC IBM x86

[modifier | modifier le wikicode]

Un autre exemple est celui des ordinateurs PC, avec des processeurs x86. L'organisation de leur espace d'adressage a évolué dans le temps et l'espace d'adressage s'est adapté. Mais il s'est adapté sans modifier l'existant, pour des raisons de compatibilité. Aussi, les processeurs x86 modernes peuvent fonctionner dans plusieurs modes, appelés mode réel, protégé, virtuel 8086, long, system management mode, et compatibilité 32 bits.

Le system management mode a déjà été abordé dans le chapitre sur les interruption. Pour simplifier, il ne s'agit pas d'un véritable mode au sens "adressage". Dans ce mode, le système d'exploitation est mis en pause et le BIOS ou un autre firmware s'exécute sans restriction. On y rentre grâce à une interruption dédiée, lancée par le noyau de l'OS. Le système d'exploitation exécute cette interruption afin de laisser la main au BIOS, pour lui déléguer certaines tâches.

Par contre, les autres modes sont bien plus intéressant, car ils ont chacun un espace d'adressage différent. Voyons-les dans le détail. Le tout peut être résumé ainsi :

AMD64StateDiagram

Le mode réel : l'adressage sur 20 bits

[modifier | modifier le wikicode]
IBM PC Memory areas

Le tout premier mode était le mode réel, qui utilisait des adresses de 20 bits, ce qui fait 1 mébioctet de mémoire adressable. La mémoire adressable était alors peuplée par de la RAM, une ROM pour le BIOS, et des périphériques standardisés comme des cartes vidéos VGA/EGA. La RAM prenait les adresses basses, la ROM était au sommet de l'espace d'adressage, et les périphériques entre les deux. Les 640 premiers kibioctets étaient attribués à la RAM et servaient pour les données du BIOS, l'OS et les logiciels. Ils étaient appelés la mémoire conventionnelle. Les adresses hautes étaient réservées pour les périphériques et le code du BIOS. Elles formaient la mémoire haute.

Le processeur démarre systématiquement en mode réel, y compris sur les ordinateurs modernes. Le BIOS s'exécute dans ce mode, avant de passer en mode protégé et de laisser la main à l'UEFI et au système d'exploitation. En mode réel, il n'y a aucun protection mémoire, aucune facilité pour exécuter plusieurs programmes à la fois, et les techniques que nous verrons dans les deux prochains chapitres pour ce faire sont désactivées. Autrefois, le système d'exploitation s'exécutait aussi en mode réel, c'est le cas du DOS.

Le premier mébioctet de mémoire est décomposé en deux portions de mémoire : les premiers 640 kibioctets sont ce qu'on appelle la mémoire conventionnelle, les octets restants forment la mémoire haute. La mémoire conventionnelle est réservée à la RAM. Elle est segmentée comme suit par le BIOS :

  • Les deux premiers kibioctets de la mémoire conventionnelle sont initialisés au démarrage de l'ordinateur. Ils sont utilisés pour stocker le vecteur d'interruption (on expliquera cela dans quelques chapitres) et servent aussi au BIOS. La portion réservée au BIOS, la BIOS Data Area, mémorise des informations en RAM. Elle commence à l'adresse 0040:0000h, a une taille de 255 octets, et est initialisée lors du démarrage de l'ordinateur.
  • Le reste de la mémoire conventionnelle est réservée au le système d'exploitation (MS-DOS, avant sa version 5.0) et au programme en cours d’exécution.

La mémoire haute est réservée aux ROM et aux périphériques, BIOS inclus :

  • Le bas de la mémoire haute est réservé pour communiquer avec les périphériques. On y trouve les BIOS des périphériques (dont celui de la carte vidéo, s'il existe) , qui sont nécessaires pour les initialiser et parfois pour communiquer avec eux. De plus, on y trouve la mémoire de la carte vidéo, et éventuellement la mémoire d'autres périphériques comme la carte son.
  • Le sommet de la mémoire haute est réservé au BIOS.
Organisation Mémoire des vieux PC, à l'époque du DOS.

Dans le détail, la mémoire en mode réel était composée de 16 blocs de 64 kibioctets. Le découpage de l'espace d'adressage en blocs de 64 kibioctets est une limitation que nous détaillerons dans le chapitre suivant, quand on parlerons de la segmentation mémoire. Pour simplifier, disons simplement que le processeur était un processeur 16 bits, qui gérait donc des adresses de 16 bits capables d'adresser 64 kibioctets de mémoire. Pour adresser de 1 mébioctet, il faut élargir les adresses pour qu'elles fassent 20 bits. Pour cela, le processeur contient un registre de 4 bits qui précise quel bloc de 64 kibioctet est couramment adressé. En somme, une sorte de commutation de banque intégrée au processeur. La réalité est plus complexe, mais cette explication simpliste suffira pour le moment.

Espace d'adressage en mode réel
Numéro du bloc Contenu du bloc
0 Low memory area, réservé au BIOS et à l'OS
1 Mémoire RAM pour les logiciels et l'OS
2
3
4
5
6
7
8
9
10 Mémoire vidéo des cartes EGA
11 Mémoire vidéo des cartes MDA ou CGA
12 ROM d'extension des périphériques (XT, EGA, 3270 PC)
13 Autre, non-réservé
14 Autre, non-réservé
15 ROM du BIOS

Vous remarquerez que les blocs 13 et 14 sont non-réservés. Ils sont en théorie utilisés pour mapper des périphériques en mémoire. mais aucun périphérique n'est mappé dedans, les blocs sont laissés libre. Et s'ils étaient libres, les OS n'hésitaient pas à les utiliser pour adresser de la RAM. De même, si l'ordinateur n'a pas de carte vidéo EGA, le bloc qui leur était réservé était aussi réutilisé comme mémoire RAM. La mémoire conventionnelle passait alors de 640 à 704 kibioctets de RAM disponibles.

Interlude : les technologies d'expanded memory

[modifier | modifier le wikicode]

Déjà à l'époque, 1 mébioctet était une limite assez faible, même si cela n'a pas empêché à un grand dirigeant de l'industrie informatique de dire que "640K ought to be enough for anybody". Aussi, diverses solutions matérielles ont vu le jour. Elles étaient peu utilisées et ont concrètement servi à des applications spécifiques. La principale est l'expanded memory (EMS), une solution utilisant une carte d'extension avec plusieurs modules de RAM installés dessus. Les modules étaient accédés via la technique de la commutation de banque.

L'espace d'adressage avec Expanded memory. La carte d'extension et le matériel requis ne sont pas représentés.

L'expanded memory demandait que les programmes soient codés pour utiliser cette fonctionnalité. Pour cela, ils devaient utiliser une technique de programmation nommée Overlay programming. L'idée est de découper le programme en plusieurs blocs séparés, appelés des overlays. Certains blocs sont en permanence en RAM, mais d'autres sont soit chargés en RAM, soit stockés ailleurs. Le ailleurs est souvent le disque dur, ou dans la RAM expanded memory si elle est disponible. Le va-et-vient des overlays entre RAM et disque dur était réalisé en logiciel, par le programme lui-même.

Overlay Programming.
Expanded memory, description. A gauche, la mémoire RAM de l'ordinateur. A droite, la mémoire installée sur la carte d'extension. La page de 64 kibioctets est en violet, vous voyez qu'elle est dans la mémoire haute.

Le terme expanded memory regroupe plusieurs technologies propriétaires semblables sur le principe mais différentes dans l'exécution. Les premières utilisaient des banques de 64 kibioctets, qui étaient mappées dans un bloc de 64 kibioctets placé dans la mémoire haute, à une position très précise. L'usage de banques de 64 kibioctets collait bien avec l'adressage particulier du mode réel, où la mémoire était gérée par blocs de 64 kibioctets, chose que nous détaillerons cela dans le chapitre suivant. Les technologies ultérieures utilisaient 2 à 4 pages de 16 kibioctets, qui pouvaient être placée n'importe où en mémoire conventionnelle.

L'utilisation de l'expanded memory utilisait l'interruption logicielle 67h, une interruption peu utilisée à l'époque, qui était disponible dans cette optique. La carte d'extension était utilisée à travers un pilote de périphérique dédié, qui interagissait avec les programmes via l'interruption 67h.

Carte d'extension Expanded memory de marque Emulex Persyst, de 4 mébioctets.

Le mode protégé : l'adressage sur 24 et 32 bits

[modifier | modifier le wikicode]

Par la suite, le mode réel a été remplacé par le mode protégé. Il a ce nom, car le mode protégé incorpore des techniques de protection mémoire et des facilités pour gérer plusieurs processus en même temps, comme nous le verrons dans les deux prochains chapitres. Il permettait aussi de dépasser la limite du mébioctet de mémoire. L'espace d'adressage est d'abord passé à 24 bits sur le CPU 286, puis à 32 bits sur le 386 et les CPU suivants.

Cependant, beaucoup de programmes conçus pour le mode réel ne pouvaient pas s'exécuter en mode protégé. Pour corriger cela, le 286 a introduit le mode 8086 virtuel. Il s'agit d'une technique de virtualisation qui permet à des programmes de s'exécuter en mode réel, alors que l'OS s'exécute en mode protégé.

Il faut noter que le DOS s'exécutait en mode réel, de même que les premières versions de Windows. Mais elles étaient cependant capables de profiter de la mémoire au-delà du mébioctet, en utilisant des bidouillages assez complexes. Les programmes DOS voyaient la mémoire conventionnelle et la mémoire haute normalement, mais ils avaient aussi conscience de la mémoire au-delà du premier mébioctet, appelée la mémoire étendue.

Par contre, les logiciels ne pouvaient pas accéder directement à la mémoire étendue. A la place, ils devaient faire bouger de place les données. Ils déplaçaient des données dans la mémoire étendue pour les garder au chaud, quand ils n'en avaient pas un besoin immédiat. Ils rapatriaient les données de la mémoire étendue vers la mémoire conventionnelle quand ils en avaient besoin. Pour faire ces échanges, ils devaient passer par un intermédiaire logiciel, appelé le Extended Memory Manager (EMM), qui est concrètement implémenté par un driver sur DOS (HIMEM.SYS). L'intermédiaire en question s'occupe d’échanger des données entre mémoire conventionnelle et mémoire étendue.

Il ne faut pas confondre mémoire étendue et expanded memory, les deux ne sont pas la même chose. L'expanded memory autoriser un va-et-vient entre une carte d'extension et une page de 64 kibioctets mappé en mémoire haute, géré par un système de commutation de banque. Elle fonctionne sans mode protégé. La mémoire étendue autorise un va-et-vient entre la mémoire conventionnelle et la mémoire étendue, mais ne gère pas de commutation de banque. Elle demande de switcher entre mode réel et protégé et demande donc l'existence de ce dernier.

Par contre, il est possible d'émuler l'expanded memory sans carte d'extension, en utilisant la mémoire étendue. Quelques chipsets intégraient des techniques pour que de la RAM soit traitée soit comme mémoire étendue, soit comme expanded memory. Une émulation logicielle était aussi possible. L'émulation logicielle se basait sur une réécriture de l'interruption 67h utilisée pour adresser la technologie expanded memory. Le système d'exploitation pouvait s'en charger, il avait juste à réécrire son allocateur de mémoire pour gérer cette interruption et quelques autres détails.

Le mode long : l'adressage 64 bits

[modifier | modifier le wikicode]

Par la suite, les processeurs sont passés au 64 bits. Pour cela, AMD, suivi par Intel, ont introduit le mode long, dans lequel les adresses font 64 bits. Le CPU en mode long a aussi un jeu d'instruction totalement différent, des registres en plus et bien d'autres fonctionnalités qui sont activées uniquement dans ce mode. Les programmes compilés pour le 64 bits, pour son jeu d'instruction, s'exécutent en mode 64 bits. Les programmes 32 et 16 bits s'exécutent eux dans un sous-mode de compatibilité dédié.

Sur les systèmes 64 bits, l'espace d'adressage est énorme : plusieurs millions de tera-octets. Mais le bus d'adresse ne fait pas 64 bits, afin d'économiser des interconnexions, de simplifier le bus d'adresse. En réalité, il fait 48 bits dans le cas général, même si quelques processeurs utilisent 57 bits. Prenons le cas avec 48 bits, le plus courant actuellement. Il manque donc 64 - 48 = 16 bits d'adresses, qui ne peuvent pas être utilisés pour adresser quoi que ce soit. Le fait de n'utiliser que des adresses réelles de 48 bits a des conséquences assez importantes.

Avec ce système, seules les 48 bits de poids faible codent une adresse, les autres bits sont gérés autrement. Sur les architectures 64 bits, la règle est que ces 16 bits doivent être tous égaux : soit ils valent tous 0, soient ils sont tous à 1. Impossible d'avoir un 0000 0100 1100 1100 dans les 16 bits de poids fort, seules les valeurs 1111 1111 1111 1111 et 0000 0000 0000 0000 sont autorisées. Les adresses qui respectent cette contrainte sont appelées des adresses canoniques. Le résultat est que l'espace d'adressage est coupé en trois sections, comme illustré ci-dessous.

  • Les adresses canoniques basses ont leurs 16 bits de poids fort à 0 et sont situées en bas de l'espace d'adressage, dans les premières adresses.
  • Les adresses canoniques hautes ont leurs 16 bits de poids fort à 1 et sont situées au sommet de l'espace d'adressage, dans les dernières adresses.
  • Entre les deux, se trouvent des adresses non-canoniques, qui ne sont pas accessibles. Y accéder déclenche la levée d'une exception matérielle.
Les futurs systèmes x86 devraient passer à des adresses de 57 bits, ce qui conservera la séparation en trois sections mais avec des frontières différentes.
Répartition des adresses entre noyau (jaune/orange) et programme (verte), sur les systèmes x86-64 bits, avec des adresses physiques de 48 bits.
Répartition des adresses entre noyau (jaune/orange) et programme (verte), sur les systèmes x86-64 bits, avec des adresses physiques de 57 bits.

Les adresses non-canoniques sont censées être inutilisables. Mais les programmeurs aimeraient bien pouvoir les utiliser pour des pointeurs tagués, à savoir des pointeurs/adresses associées à des informations. L'idée serait d'utiliser les 16 bits de poids fort pour stocker des informations liées au pointeur, seuls les 48 bits restant codant l'adresse. Les 16 bits peuvent être utilisés de manières très diverses.

Un exemple est la technique du memory tagging, qui consiste à créer une somme de contrôle au pointeur. La somme de contrôle est générée par un algorithme cryptographique, à partir de l'adresse du pointeur, et elle est vérifiée à chaque utilisation du pointeur. Si la somme de contrôle ne correspond pas au pointeur, alors une erreur est levée. L'intérêt est une question de sécurité. Si jamais un virus ou un code malveillant modifie un pointeur, il ne saura pas comment calculer la somme de contrôle. En cas de modification du pointeur, la somme de contrôle a énormément de chances d'être incorrecte.

Quelques fonctionnalités des processeurs visent à autoriser l'utilisation des adresses non-canoniques. L'idée est que les 16 bits de poids fort sont ignorées lors des accès mémoire, ce qui permet d'utiliser les 16 bits de poids fort à volonté. Sur ARM, il s'agit de la technique du TBI : Top Byte Ignore. Chez Intel et AMD, il s'agit des fonctionnalités UAI (Upper Address Ignore) d'AMD et de LAM (Linear Address Masking) d'Intel.