II. LA MEMOIRE VIVE
1. La segmentation de la mémoire
Votre PC est conçu pour gérer 1 Mo (soit 220 octets)
de mémoire vive en mode réel. Il faut donc 20 bits au
minimum pour adresser toute la mémoire. Or en mode réel
les bus d'adresses n’ont que 16 bits. Ils permettent donc d'adresser
216 = 65536 octets = 64 Ko, ce qui est
insuffisant !
Afin de pallier ce manque, on utilise deux nombres pour adresser un octet
quelconque de la RAM. Le premier est appelé adresse
de segment, le second adresse
d'offset. Ils seront stockés séparément.
La mémoire est découpée en segments
de 64 Ko chacun. Un segment est donc en quelque sorte un gros bloc de
mémoire auquel on peut accéder grâce à une
adresse de segment qui désigne son numéro. Par
exemple, le premier segment est le segment 0000 (en hexa), le
deuxième est le 0001, le quarante-deuxième est le 0029,
etc... Chaque numéro est codé sur 16 bits, c’est-à-dire
4 chiffres hexa.
Pour accéder à un octet particulier dans un segment, il
suffit de compter le décalage de cet octet par rapport
au début du segment. Ce décalage est obligatoirement
inférieur ou égal à 65535 : il tient bien sur 16
bits lui aussi. On appelle ce décalage
« offset ».
L'adresse d'un octet se note XXXX:YYYY où XXXX est l'adresse de segment
et YYYY est l'offset (tous deux en notation hexadécimale, bien
sûr).
Par exemple, le dix-septième octet de la RAM (le numéro 16)
est situé à l'adresse 0000:0010. De même, l’octet
0000:0100 est l'octet numéro 256. Nous en arrivons à la
petite subtilité qu’il convient de bien saisir, sous
peine de ne rien comprendre à certains programmes en assembleur.
On pourrait penser que l’octet qui se trouve à l’adresse
0001:0000 est le numéro 65536. Il n’en est rien. C'est
l'octet numéro 16.
Eh oui ! Les segments ne sont pas situés gentiment les uns à
la suite des autres. Ils sont fort mal élevés et
n'attendent pas que les segments qui les précédent
soient terminés avant de commencer ! Ils se marchent donc
sur les pieds.
Autrement dit, le deuxième segment ne démarre pas à
l'octet 65536 comme il devrait le faire s'il était bien sage,
mais à l'octet 16 ! Le troisième démarre à
l'octet 32 et ainsi de suite…
La notion de segment n’est pas tant physique que mathématique :
elle sert à se repérer dans la RAM.
La conséquence immédiate de tout cela est qu'un
octet n'a pas une adresse unique.
Par exemple, l'octet numéro 66 peut être adressé par
0000:0042, mais aussi par 0001:0032, par 0002:0022, par 0003:0012 ou encore
par 0004:0002. Toutes ces adresses sont équivalentes.
Voilà pour la subtilité. Si vous avez compris, vous devriez être
capable de trouver facilement comment on calcule l'adresse effective
d'un octet, c'est à dire sa position absolue dans la RAM.
Allez, un petit effort !
Voici la solution : si l'adresse de l'octet est A17C:022E, alors son
adresse effective est A17C x 16 + 022E, soit A17C0 + 022E
= A19EE. On a multiplié par 16, car le segment A17C
débute à l’octet A17C x 16, puis on a
simplement ajouté le décalage.
Au final, on a bien une adresse sur 20 bits puisqu'on obtient 5 chiffres hexa. Chaque
petit bloc de 16 octets s’appelle un paragraphe.
Remarque importante : Il est souvent plus simple de considérer
qu’un segment est un bloc de taille quelconque qui
débute à une adresse effective multiple de 16 et qui
permet, à l’aide de son adresse de segment et
d’un offset, d’adresser le bloc entier (64 Ko au
maximum). Cette définition est à notre avis celle qui a
le plus de sens, et nous l'utiliserons tout au long de ce cours.
2. Structure d’un programme en mémoire
Lorsque l’utilisateur exécute un programme, celui-ci est d’abord
chargé en mémoire par le système. Le DOS
distingue deux modèles de programmes exécutables :
les fichiers COM et les fichiers EXE.
La différence fondamentale est que les programmes COM ne peuvent
pas utiliser plus d’un segment dans la mémoire. Leur
taille est ainsi limitée à 64 Ko. Les programmes EXE ne
sont quant à eux limités que par la mémoire
disponible dans l’ordinateur.
a) les fichiers COM
Lorsqu’il charge un fichier COM, le DOS lui alloue toute la mémoire
disponible. Si celle-ci est insuffisante, il le signale à
l’utilisateur par un message et annule toute la procédure
d’exécution. Dans le cas contraire, il crée le
PSP du programme au début
du bloc de mémoire réservé, et copie le programme
à charger à la suite.
Mais qu’est-ce donc qu’un PSP ?
Pour simplifier, le PSP (« Program Segment Prefix »)
est une zone de 256 (= 100h) octets qui contient des
informations diverses au sujet du programme. C’est dans le PSP
que se trouve la ligne de commande tapée par l’utilisateur.
Par exemple, le PSP d’un programme appelé MONPROG,
exécuté avec la commande “MONPROG monfic.txt
/S /H”, contiendra la chaîne de caractères
suivante : “ monfic.txt /S /H”. Le
programmeur a ainsi la possibilité d’accéder aux
paramètres.
Voici à titre indicatif la structure simplifiée du PSP (ne
vous souciez pas de ce que vous ne comprenez pas : pour
l'instant, seules les deux dernières lignes nous intéressent
vraiment) :
Offset
|
Description
|
Taille (octets)
|
00h
|
Appel de l'int 20h
|
2
|
02h
|
Adresse du 1er segment qui se trouve au delà du prog.
|
2
|
04h
|
Réservé
|
1
|
05h
|
Far call de l'int 21h (inutilisé)
|
5
|
0Ah
|
Vecteur de l'int 22h
|
4
|
0Eh
|
Vecteur de l'int 23h
|
4
|
12h
|
Vecteur de l'int 24h
|
4
|
16h
|
Réservé
|
22
|
2Ch
|
Segment du bloc d'environnement
|
2
|
2Eh
|
Réservé
|
82
|
80h
|
Nombre de caractères
dans la ligne de commande sans compter le code ASCII 13 (retour chariot)
|
1
|
81h
|
Ligne de commande (à
partir du caractère espace qui suit le nom du programme) + code ASCII 13
|
127
|
A présent que nous connaissons l’existence du PSP, il nous
faut revenir sur un point important. Comme nous l’avons dit, un
programme COM ne peut comporter qu’un seul segment, bien que le
DOS lui réserve la totalité de la mémoire
disponible. Ceci a deux conséquences. La première est
que les adresses de segment sont inutiles dans le programme :
les offsets seuls permettent d’adresser n’importe quel
octet du segment. La seconde est que le PSP fait
partie de ce segment, ce qui limite à
64 Ko – 256 octets la taille maximale d’un
fichier COM. Cela implique également que le
programme lui-même débute à l’offset 100h
et non à l’offset 0h.
b) les fichiers EXE
« Pour un fichier EXE, tout est toujours un peu plus compliqué. »
(Devise du programmeur débutant en assembleur)
Bien qu’il soit possible de n’utiliser qu’un seul
segment à tout faire, la plupart des programmes EXE ont un
segment réservé au code
(c’est ainsi qu’on appelle les instructions du langage
machine), un ou deux autres aux données,
et un dernier à la pile.
La pile est une mémoire très spéciale qui sert
comme son nom l’indique à empiler des données
de 16 bits de façon temporaire. On peut ensuite retrouver ces
données en les dépilant. Le « dépilage »
se fait toujours dans l’ordre inverse de l’empilage.
Le PSP a lui aussi son propre segment. Le programme commence donc à
l’offset 0h du segment de code et non à l’offset
100h.
Afin que le programme puisse être chargé et exécuté correctement, il faut que le
système sache où commence et où s'arrête chacun de ces segments.
A cet effet, les compilateurs créent un en-tête (ou
« header »)
au début de chaque fichier EXE. Ce
header ne sera pas copié en mémoire. Son
rôle est simplement d’indiquer au DOS (lors du chargement)
la position relative de chaque segment dans le fichier.
3. Les cycles de lecture-écriture
Le code et les variables d’un programme se trouvent dans la
mémoire vive. Pour accéder à une donnée
en mémoire, le processeur place son adresse dans un bus
d’adresse. Un cycle
de lecture se met alors en place. Il consiste à
retourner la donnée lue au processeur via le bus
de données.
Pour l’écriture, l’adresse de la destination est
transmise dans le bus d’adresse et la donnée à
écrire est placée dans le bus de données.
Ouf !…
Nous aurons l’occasion de revenir sur la mémoire vive dans
les autres chapitres pour apporter quelques précisions. Vous
devriez mieux comprendre toutes ces notions en lisant la suite, car
jusqu’ici nous n’avons pas encore parlé de la
façon dont l’ordinateur se sert des adresses pour
accéder à des données ou pour exécuter du
code. C’est là qu’intervient le microprocesseur...
Sommaire
Suite
|