-
Vous devez avoir lu de très vieux livres car personne ne programme en mode réel plus;-) En mode réel , vous pouvez obtenir l'adresse physique d'un accès mémoire avec
phyical address = segment register * 0x10 + offset
, le décalage étant une valeur à l'intérieur de l'un des registres à usage général. Parce que ces registres ont une largeur de 16 bits, un segment aura une longueur de 64 Ko et vous ne pouvez rien faire à propos de sa taille, simplement parce qu'il n'y a pas d'attribut ! Avec le* 0x10
multiplication, 1 Mo de mémoire devient disponible, mais il y a des combinaisons qui se chevauchent en fonction de ce que vous mettez dans les registres de segment et le registre d'adresses . Je n'ai compilé aucun code pour le mode réel , mais je pense que c'est au système d'exploitation de configurer les registres de segment pendant le chargement du binaire, tout comme un chargeur allouerait certaines pages lors du chargement d'un binaire ELF. Cependant, j'ai compilé du code noyau nu et j'ai dû configurer ces registres moi-même. -
Quatre segments sont obligatoires dans le modèle plat en raison de contraintes d'architecture. En mode protégé les registres de segment ne contient plus l'adresse de base du segment, mais un sélecteur de segment qui est essentiellement un décalage dans le GDT. En fonction de la valeur du sélecteur de segment , le CPU sera dans un niveau de privilège donné, c'est le CPL (Current Privilege Level). Le sélecteur de segment pointe vers un descripteur de segment qui a un DPL (Descriptor Privilege Level), qui est éventuellement le CPL si le registre de segment est rempli avec ce sélecteur (au moins vrai pour le sélecteur de segment de code). Par conséquent, vous avez besoin d'au moins une paire de sélecteur de segment pour différencier le noyau de l'espace utilisateur. De plus, les segments sont soit des segments de code, soit des segments de données, de sorte que vous vous retrouvez finalement avec quatre descripteurs de segment dans le GDT.
-
Je n'ai aucun exemple de système d'exploitation sérieux qui utilise la segmentation, simplement parce que la segmentation est toujours présente pour la rétroconformité. L'approche du modèle plat n'est rien d'autre qu'un moyen de s'en débarrasser. Quoi qu'il en soit, vous avez raison, la pagination est bien plus efficace et polyvalente, et disponible sur presque toutes les architectures (du moins les concepts). Je ne peux pas expliquer ici les composants internes de la pagination, mais toutes les informations que vous devez connaître se trouvent dans l'excellent homme d'Intel :Intel® 64 et IA-32 ArchitecturesSoftware Developer's ManualVolume 3A :System Programming Guide, Part 1
Développant la réponse de Benoit à la question 3...
La division des programmes en parties logiques telles que le code, les données constantes, les données modifiables et la pile est effectuée par différents agents à différents moments.
Tout d'abord, votre compilateur (et éditeur de liens) crée des fichiers exécutables où cette division est spécifiée. Si vous regardez un certain nombre de formats de fichiers exécutables (PE, ELF, etc.), vous verrez qu'ils prennent en charge une sorte de sections ou de segments ou tout ce que vous voulez appeler. Outre les adresses, les tailles et les emplacements dans le fichier, ces sections portent des attributs indiquant au système d'exploitation le but de ces sections, par ex. cette section contient du code (et voici le point d'entrée), ceci - des données constantes initialisées, cela - des données non initialisées (généralement ne prenant pas d'espace dans le fichier), voici quelque chose à propos de la pile, il y a la liste des dépendances (par exemple, les DLL), etc.
Ensuite, lorsque le système d'exploitation commence à exécuter le programme, il analyse le fichier pour voir la quantité de mémoire dont le programme a besoin, où et quelle protection de la mémoire est nécessaire pour chaque section. Ce dernier est généralement effectué via des tableaux de pages. Les pages de code sont marquées comme exécutables et en lecture seule, les pages de données constantes sont marquées comme non exécutables et en lecture seule, les autres pages de données (y compris celles de la pile) sont marquées comme non exécutables et en lecture-écriture. C'est comme ça que ça devrait être normalement.
Souvent, les programmes ont besoin de lecture-écriture et, en même temps, de régions exécutables pour le code généré dynamiquement ou simplement pour pouvoir modifier le code existant. L'accès RWX combiné peut être spécifié dans le fichier exécutable ou demandé au moment de l'exécution.
Il peut y avoir d'autres pages spéciales telles que des pages de garde pour l'expansion dynamique de la pile, elles sont placées à côté des pages de la pile. Par exemple, votre programme démarre avec suffisamment de pages allouées pour une pile de 64 Ko, puis lorsque le programme tente d'accéder au-delà de ce point, le système d'exploitation intercepte l'accès à ces pages de garde, alloue plus de pages pour la pile (jusqu'à la taille maximale prise en charge) et déplace les pages de garde plus loin. Ces pages n'ont pas besoin d'être spécifiées dans le fichier exécutable, le système d'exploitation peut les gérer lui-même. Le fichier ne doit spécifier que la ou les tailles de pile et peut-être l'emplacement.
S'il n'y a pas de matériel ou de code dans le système d'exploitation pour distinguer la mémoire de code de la mémoire de données ou pour appliquer les droits d'accès à la mémoire, la division est très formelle. Les programmes DOS en mode réel 16 bits (COM et EXE) n'avaient pas de segments de code, de données et de pile marqués d'une manière spéciale. Les programmes COM avaient tout dans un segment commun de 64 Ko et ils commençaient avec IP=0x100 et SP=0xFFxx et l'ordre du code et des données pouvait être arbitraire à l'intérieur, ils pouvaient s'entrelacer pratiquement librement. Les fichiers DOS EXE ne spécifiaient que les emplacements CS:IP et SS:SP de départ et au-delà, les segments de code, de données et de pile étaient indiscernables pour DOS. Tout ce qu'il avait à faire était de charger le fichier, d'effectuer la relocalisation (pour les EXE uniquement), de configurer le PSP (Program Segment Prefix, contenant le paramètre de ligne de commande et d'autres informations de contrôle), de charger SS:SP et CS:IP. Il n'a pas pu protéger la mémoire car la protection de la mémoire n'est pas disponible en mode d'adresse réelle, et donc les formats exécutables DOS 16 bits étaient très simples.