L’adresse de chargement est-elle commune à tous les programmes C sous Linux?

Disons que j’ai un prog1.c qui est construit en tant que prog1.out. Dans prog1.out, il existe une information sur l’éditeur de liens qui indiquera où l’elfe sera chargé. Ces adresses seront des adresses virtuelles. Le chargeur cherchera ces informations et les lancera en tant que processus. Chaque section comme DS, BSS sera chargée sur l’adresse virtuelle comme indiqué dans l’éditeur de liens. Par exemple, j’ai prog2.out qui a également la même adresse de chargeur, BSS, DS, etc. Cela sera-t-il en conflit? Je sais que cela n’entrera pas en conflit, mais qu’il y aura un problème de performance. Puisque les deux processus ont la même adresse virtuelle mais qu’ils mappent vers des adresses physiques différentes? Je suis confus, comment il peut protéger les deux processus ayant les mêmes adresses virtuelles.

Le fait est que lorsqu’un processus utilise une adresse mémoire, il parle d’une adresse virtuelle, qui peut être différente de la même adresse physique. Cela signifie que deux processus peuvent faire référence à la même adresse et ne pas mélanger leurs données, car elles se trouveront dans deux emplacements physiques différents.

Ci-dessous, je décris comment l’adresse virtuelle est convertie en une adresse physique sur des ordinateurs classiques (cela varie un peu sur d’autres architectures, mais c’est la même idée)

Compréhension du processus de traduction de la mémoire sur l’architecture Intel x86 (pagination à 3 niveaux)

Donc, dans une main, vous avez une adresse de mémoire virtuelle et vous voulez obtenir une adresse de mémoire physique (c.-à-d. L’adresse actuelle sur la RAM), le stream de travail est principalement le suivant:

Adresse virtuelle -> [Unité de segmentation] -> [Unité de radiomessagerie] -> Adresse physique

Chaque système d’exploitation peut définir le fonctionnement de l’unité de segmentation et de la pagination. Linux, par exemple, utilise un modèle de segmentation à plat , ce qui signifie qu’il est ignoré. Nous allons donc en faire autant maintenant.

Maintenant, notre adresse virtuelle passe par quelque chose appelé Unité de paging, et est convertie en une adresse physique en quelque sorte. Voici comment.

La mémoire est divisée en blocs d’une certaine taille . En Intel, cette taille peut être de 4 Ko ou 4 Mo.

Chaque processus définit un ensemble de tables en mémoire afin que l’ordinateur sache comment traduire les adresses en mémoire. Ces tables sont organisées de manière hiérarchique et l’adresse de mémoire à laquelle vous souhaitez accéder est décomposée en index pour ces tables.

Je sais, cela semble déroutant, mais restz avec moi pour quelques phrases de plus. Vous pouvez suivre mon écriture avec cette image:

pagination 32 bits x86 (de wikipedia)

Il existe un registre de CPU interne appelé CR3 qui stocke l’adresse de base de la première table (nous appellerons cette page Page Directory et chacune de ses entrées s’appelle Page Directory Entry). Lorsqu’un processus est en cours d’exécution, son CR3 est chargé (entre autres).

Donc, maintenant vous voulez accéder à, disons, l’adresse mémoire 0x00C30404 ,

L’unité de radiomessagerie dit “Ok, récupérons la base de répertoires de pages”, examine le registre CR3 et sait où se trouve la base du répertoire de pages, appelons cette adresse PDB (Base de répertoires de pages).

Maintenant, vous voulez savoir quelle entrée de répertoire vous devez utiliser .. Comme je l’ai dit précédemment, l’adresse est décomposée en un tas d’index. Les 10 bits les plus significatifs (bits 22 à 31) correspondent à l’index du répertoire de pages. Dans ce cas, 0x00C30404 vaut 0000 1100 0011 0000 0100 0000 0100 en binary et ses 10 bits les plus significatifs sont: 0000 0000 11 qui est 0x3 . Cela signifie que nous voulons rechercher l’entrée de répertoire de la 3ème page.

Qu’est-ce qu’on fait maintenant?

Rappelez-vous que ces tables sont hiérarchiques: chaque entrée du répertoire de pages contient, entre autres, l’adresse de la table suivante, appelée table de page . (Ce tableau peut être différent pour chaque entrée de répertoire de page ).

Nous avons donc maintenant une autre table. Les 10 bits suivants de notre adresse nous diront à quel index de cette table nous allons accéder (appelons-les entrées de table de page).

00 0011 0000 sont les 10 prochains bits, et ils sont le nombre: 0x30 . Cela signifie que nous devons accéder à la 30e entrée de table de pages .

Et enfin, cette entrée de table de pages conserve le décalage de la PAGE FRAME souhaitée (rappelez-vous que la mémoire est divisée en blocs de 4k). Enfin, les 12 bits les moins significatifs de notre adresse représentent le décalage de mémoire de cette image de page . Notez que l’image de page est une adresse de mémoire physique réelle.

C’est ce qu’on appelle la pagination à 3 niveaux. Sur 64 bits (ou avec PAE), c’est très similaire, mais il y a un niveau de pagination de plus.

Vous pensez peut-être que l’obtention de tous ces access à la mémoire est une véritable déception, rien que pour aller chercher une variable .. Et c’est vrai. Il existe des mécanismes dans l’ordinateur pour éviter toutes ces étapes. Le TLB (Table Lookaside Buffer) en est un, il stocke un cache de toutes les traductions effectuées, ce qui permet de récupérer facilement de la mémoire.

En outre, chaque entrée de ces structures possède des propriétés concernant les permissions, telles que “cette page est-elle accessible en écriture?” “cette page est-elle exécutable?”.

Alors, maintenant que vous comprenez le fonctionnement de la pagination en mémoire, il est facile de comprendre comment Linux gère la mémoire:

  • Chaque processus a son propre CR3 et lorsque son exécution est planifiée, le registre cr3 est chargé.
  • Chaque processus a son propre espace virtuel (les tables peuvent ne pas être pleines, un processus peut commencer avec, par exemple, une seule page de 4 Ko).
  • Chaque processus a mappé d’autres pages (mémoire du système d’exploitation). Ainsi, lorsqu’il est interrompu, le gestionnaire d’interruptions démarre sur la même tâche et gère l’interruption au sein de cette tâche, en exécutant le code nécessaire.

Quelques motivations pour ce genre de projets

  • Vous n’avez pas besoin de disposer de la mémoire de tous les processus en même temps, vous pouvez en stocker sur disque.
  • Vous pouvez isoler en toute sécurité chaque mémoire de processus et lui atsortingbuer également des permissions.
  • Un processus peut utiliser 10 Mo de RAM, mais il n’est pas nécessaire qu’ils soient contigus dans la mémoire physique.

(Avez-vous aimé mon explication?, Je suis un assistant à un cours d’organisation informatique et aimerais recevoir vos commentaires: P)

Chaque processus “pense” qu’il s’exécute seul sur l’ordinateur et ne connaît que ses adresses virtuelles. L’unité de gestion de la mémoire (MMU) traduit ensuite l’adresse virtuelle en une adresse physique. La MMU doit bien sûr s’assurer que deux adresses virtuelles ne sont pas mappées sur la même adresse physique. Le mappage est très rapide car la CPU dispose (la plupart du temps) d’un support matériel dédié à la MMU.

La MMU doit également déterminer exactement où aller chercher les données, par exemple, la mémoire principale (peut-être le cas typique), le cache de niveau 1, le cache de niveau 2, un fichier d’échange à partir d’un disque, etc. cela, il “pense” que cela fonctionne sur un fichier de mémoire à plat et ne doit pas s’inquiéter des collisions.

Il n’y a pas de relation entre les adresses virtuelles et les adresses physiques (dans les machines courantes). Le mappage a toujours lieu – cela fait partie de ce à quoi servent les adresses virtuelles.

Les “problèmes de performances” sont présents, voire inexistants, à l’intérieur du matériel. S’il y a eu une collision réelle (si ces adresses avaient été physiques) ou non.

Comment cela peut-il protéger les deux processus ayant les mêmes adresses virtuelles?

Vous n’avez pas et n’a pas besoin de. Le contenu de la mémoire pour chaque processus est indépendant de tous les autres, et c’est le travail du système d’exploitation et du matériel de le garantir. Vous pouvez penser au terme “mémoire virtuelle” en tant que “mémoire propre à un processus”.

Notez que toute cette discussion a vraiment peu à voir avec le contenu du code d’object ou du processus de liaison / chargement – vous pouvez faire référence à n’importe quelle adresse au moment de l’exécution, sans que l’éditeur de liens / le chargeur en soit informé.