J'étudie les systèmes d'exploitation et l'architecture x86. Pendant que je lisais des informations sur la segmentation et la pagination, j'étais naturellement curieux de voir comment les systèmes d'exploitation modernes gèrent la gestion de la mémoire. D'après ce que j'ai trouvé, Linux et la plupart des autres systèmes d'exploitation évitent essentiellement la segmentation au profit de la pagination. Certaines des raisons pour lesquelles j'ai trouvé que je trouvais étaient la simplicité et la portabilité.
Quelles sont les utilisations pratiques de la segmentation (x86 ou autre) et verrons-nous l’utilisation de systèmes d’exploitation robustes ou continueront-ils à privilégier un système basé sur la pagination?
Maintenant, je sais que la question est complexe, mais je suis curieux de savoir comment la segmentation serait traitée avec les systèmes d’exploitation nouvellement développés. Est-il tellement logique de favoriser la pagination que personne ne songe à adopter une approche plus «segmentée»? Si oui, pourquoi?
Et lorsque je parle de «segmentation», je sous-entends que Linux ne l'utilise que dans la mesure nécessaire. Seulement 4 segments pour les segments utilisateur et de code / données du noyau. En lisant la documentation d'Intel, j'ai eu le sentiment que la segmentation avait été conçue avec des solutions plus robustes. Là encore, on m'a souvent dit à quel point le x86 peut être compliqué.
J'ai trouvé cette anecdote intéressante après avoir été liée à "l'annonce" originale de Torvald pour Linux. Il a dit ceci quelques messages plus tard:
Simplement, je dirais que le portage est impossible. C'est principalement en C, mais la plupart des gens n'appelleraient pas ce que j'écris C. Il utilise toutes les fonctionnalités imaginables du 386 que j'ai pu trouver, car c'était aussi un projet pour m'instruire sur le 386. Comme déjà mentionné, il utilise un MMU , pour la pagination (pas encore sur le disque) et la segmentation. C’est la segmentation qui le rend VRAIMENT 386 (chaque tâche a un segment de 64 Mo pour le code et les données - 64 tâches au maximum en 4 Go. Quiconque a besoin de plus de 64 Mo / tâche - cookies difficiles).
Je suppose que mes propres expériences avec x86 m'ont amené à poser cette question. Linus n'avait pas StackOverflow, il l'a donc simplement mis en place pour l'essayer.
la source
Réponses:
Avec la segmentation, il serait par exemple possible de placer chaque objet alloué dynamiquement (malloc) dans son propre segment de mémoire. Le matériel vérifierait automatiquement les limites de segment, et toute la classe de bogues de sécurité (dépassements de mémoire tampon) serait éliminée.
De plus, comme tous les décalages de segment commencent à zéro, tout le code compilé sera automatiquement indépendant de la position. L'appel dans une autre DLL se résumerait à un appel éloigné avec un décalage constant (en fonction de la fonction appelée). Cela simplifierait grandement les lieurs et les chargeurs.
Avec 4 anneaux de protection, il est possible de concevoir un contrôle d'accès plus détaillé (avec la pagination, vous ne disposez que de 2 niveaux de protection: utilisateur et superviseur) et des noyaux de système d'exploitation plus robustes. Par exemple, seul l'anneau 0 a un accès complet au matériel. En séparant le noyau du système d'exploitation et les pilotes de périphérique en anneaux 0 et 1, vous pouvez créer un système d'exploitation microkernel plus robuste et plus rapide dans lequel la plupart des vérifications d'accès pertinentes seront effectuées par HW. (Les pilotes de périphérique peuvent accéder au matériel via le bitmap d’accès aux E / S dans le TSS.)
Cependant .. x86 est un peu limité. Il n'a que 4 registres de segments de données "libres"; leur rechargement est assez coûteux, et il est possible d'accéder simultanément à 8192 segments. (En supposant que vous souhaitiez maximiser le nombre d'objets accessibles, le GDT ne contient que des descripteurs système et des descripteurs LDT.)
Désormais, en mode 64 bits, la segmentation est décrite comme "héritée" et les vérifications des limites matérielles ne sont effectuées que dans des circonstances limitées. IMHO, une grosse erreur. En fait, je ne blâme pas Intel, je blâme surtout les développeurs, la majorité d'entre eux pensant que la segmentation était "trop compliquée" et attendait depuis longtemps un espace d'adressage plat. Je blâme aussi les auteurs de systèmes d’exploitation qui manquaient d’imagination pour tirer parti de la segmentation. (Autant que je sache, OS / 2 était le seul système d'exploitation à utiliser pleinement les fonctions de segmentation.)
la source
La réponse courte est que la segmentation est un hack, utilisé pour faire en sorte qu'un processeur ayant une capacité limitée d'adresser de la mémoire dépasse ces limites.
Dans le cas du 8086, il y avait 20 lignes d’adresse sur la puce, ce qui signifie qu’elle pouvait accéder physiquement à 1 Mo de mémoire. Cependant, l’architecture interne reposait sur un adressage sur 16 bits, probablement du fait de la volonté de conserver une cohérence avec le 8080. Le jeu d’instructions comprenait donc des registres de segments qui seraient combinés aux index sur 16 bits pour permettre l’adressage de 1 Mo de mémoire totale. . Le 80286 a étendu ce modèle avec une véritable MMU afin de prendre en charge la protection par segment et l'adressage de davantage de mémoire (iirc, 16 Mo).
Dans le cas du PDP-11, les modèles ultérieurs du processeur prévoyaient une segmentation en espaces d'instruction et de données, afin de prendre en charge les limitations d'un espace d'adressage de 16 bits.
Le problème de la segmentation est simple: votre programme doit explicitement contourner les limites de l’architecture. Dans le cas du 8086, cela signifiait que le plus grand bloc de mémoire contigu auquel vous pouviez accéder était 64k. si vous aviez besoin d'accéder à plus que cela, vous devriez changer vos registres de segments. Ce qui signifiait, pour un programmeur C, que vous deviez indiquer au compilateur C quel type de pointeurs il devait générer.
Il était beaucoup plus facile de programmer le MC68k, doté d'une architecture interne à 32 bits et d'un espace d'adressage physique de 24 bits.
la source
Pour 80x86, il y a 4 options - "rien", segmentation uniquement, pagination uniquement, et segmentation et pagination.
Pour "rien" (pas de segmentation ni de pagination), vous ne disposez d'aucun moyen simple de protéger un processus de lui-même, d'aucun moyen simple de protéger les processus les uns des autres, d'aucun moyen de gérer des tâches telles que la fragmentation de l'espace d'adressage physique, d'aucun moyen d'éviter la position code indépendant, etc. Malgré tous ces problèmes, il pourrait (en théorie) être utile dans certaines situations (par exemple, un périphérique embarqué qui n'exécute qu'une seule application; ou peut-être quelque chose qui utilise JIT et qui tout virtualise de toute façon).
Pour la segmentation seulement; il résout presque le problème de "protéger un processus de lui-même", mais il faut beaucoup de solutions pour le rendre utilisable lorsqu'un processus souhaite utiliser plus de 8192 segments (en supposant un LDT par processus), ce qui le rend quasiment cassé. Vous résolvez presque le problème de "protéger les processus les uns des autres"; mais différents logiciels s'exécutant au même niveau de privilège peuvent charger / utiliser leurs segments respectifs (il existe des moyens de contourner ce problème - modifier les entrées GDT lors des transferts de contrôle et / ou à l'aide des LDT). Cela résout aussi principalement le problème du "code indépendant de la position" (cela peut causer un problème du "code dépendant du segment" mais c'est beaucoup moins important). Cela ne fait rien pour le problème de "fragmentation de l'espace d'adressage physique".
Pour la pagination seulement; cela ne résout pas beaucoup le problème de "protéger un processus de lui-même" (mais soyons honnêtes ici, il ne s'agit que d'un problème de débogage / test de code écrit dans des langages non sécurisés, et il existe de toute façon des outils beaucoup plus puissants comme valgrind). Il résout complètement le problème de "protection des processus les uns contre les autres", résout complètement le problème de "code indépendant de la position" et résout complètement le problème de "fragmentation de l'espace d'adressage physique". En prime, cela ouvre des techniques très puissantes qui sont loin d'être aussi pratiques sans pagination; y compris des éléments tels que «copie à l'écriture», fichiers mappés en mémoire, gestion efficace de l'espace de permutation, etc.
Maintenant, vous penseriez que l'utilisation de la segmentation et de la pagination vous apporterait les avantages des deux; et théoriquement, cela est possible, sauf que le seul avantage que vous tirez de la segmentation (que la pagination ne permet pas mieux de résoudre) est une solution au problème de la "protection d'un processus contre lui-même", dont personne ne se soucie vraiment. En pratique, ce que vous obtenez est la complexité des deux et leurs frais généraux, pour un bénéfice minime.
C’est pourquoi la quasi-totalité des systèmes d’exploitation conçus pour le format 80x86 n’utilisent pas la segmentation pour la gestion de la mémoire (ils l’utilisent pour des tâches telles que le stockage par processeur et par tâche) des choses).
Bien sûr, les fabricants de processeurs ne sont pas stupides - ils ne vont pas dépenser temps et argent pour optimiser quelque chose qu'ils savent que personne n'utilise (ils vont optimiser quelque chose que presque tout le monde utilise à la place). Pour cette raison, les fabricants de CPU n'optimisent pas la segmentation, ce qui rend la segmentation plus lente qu'elle ne pourrait l'être, ce qui incite les développeurs de systèmes d'exploitation à l'éviter encore plus. La plupart du temps, ils ne conservaient que la segmentation pour des raisons de compatibilité ascendante (ce qui est important).
Finalement, AMD a conçu le mode long. Il n'y avait pas de code 64 bits ancien / existant à craindre, donc (pour le code 64 bits), AMD s'est débarrassé de la segmentation autant que possible. Cela donnait aux développeurs de systèmes d’exploitation une autre raison (continuer à éviter le code de port conçu pour la segmentation au format 64 bits) pour continuer à éviter la segmentation.
la source
Je suis plutôt étonné que, depuis que cette question a été posée, personne n’a mentionné les origines des architectures de mémoire segmentées et le véritable pouvoir qu’elles peuvent se permettre.
Le système original qui a inventé ou affiné de manière utile toutes les fonctions entourant la conception et l'utilisation de systèmes de mémoire virtuelle paginée segmentés (ainsi que de systèmes de fichiers multitraitement et hiérarchiques symétriques) était Multics (et également le site Multicians ). La mémoire segmentée permet à Multics d’indiquer à l’utilisateur que tout est dans la mémoire (virtuelle) et permet le partage ultime de tout.sous forme directe (c'est-à-dire directement adressable en mémoire). Le système de fichiers devient simplement une carte de tous les segments en mémoire. Lorsqu'elle est correctement utilisée de manière systématique (comme dans Multics), la mémoire segmentée libère l'utilisateur des nombreuses tâches liées à la gestion du stockage secondaire, au partage de données et aux communications inter-processus. D’autres réponses ont fait l’affirmation selon laquelle la mémoire segmentée est plus difficile à utiliser, mais ce n’est tout simplement pas vrai, et Multics l’a prouvé avec un succès retentissant il y a plusieurs décennies.
Intel a créé une version tronquée de la mémoire segmentée, la 80286, qui, bien qu’elle soit assez puissante, n’a pu être utilisée à des fins utiles. Le 80386 a amélioré ces limitations, mais les forces du marché à l'époque ont pratiquement empêché le succès de tout système pouvant réellement tirer parti de ces améliorations. Dans les années qui ont suivi, il semble que trop de gens aient appris à ignorer les leçons du passé.
Intel a également essayé très tôt de créer un super-micro plus puissant appelé iAPX 432, qui aurait surpassé de loin tout ce qu’il avait à l’époque. Il possédait une architecture de mémoire segmentée et d’autres fonctionnalités fortement orientées vers la programmation orientée objet. L'implémentation initiale était cependant trop lente et aucune autre tentative n'a été faite pour y remédier.
Vous trouverez une discussion plus détaillée sur la segmentation et la pagination utilisées par Multics dans l'article de Paul Green, Multics Virtual Memory - Tutorial and Reflections.
la source
La segmentation était une solution de contournement permettant de traiter jusqu'à 1 Mo de mémoire par un processeur 16 bits - normalement, seulement 64 Ko de mémoire auraient été accessibles.
Lorsque les processeurs 32 bits arrivaient, vous pouviez adresser jusqu'à 4 Go de mémoire avec un modèle de mémoire à plat et il n'y avait plus besoin de segmentation. avoir le mode protégé 16 bits).
De plus, un mode de mémoire à plat est beaucoup plus pratique pour les compilateurs - vous pouvez écrire des programmes segmentés de 16 bits en C , mais c'est un peu fastidieux. Un modèle de mémoire à plat simplifie tout.
la source
Certaines architectures (comme ARM) ne supportent pas du tout les segments de mémoire. Si Linux avait été dépendant de la source sur des segments, il n'aurait pas pu être facilement porté sur ces architectures.
Dans l’ensemble, l’échec des segments de mémoire est lié à la popularité croissante de l’arithmétique de C et de pointeur. Le développement en C est plus pratique sur une architecture à mémoire plate; et si vous voulez une mémoire à plat, vous choisissez la pagination en mémoire.
Il fut un temps, au tournant des années 80, quand Intel, en tant qu’organisation, anticipait la popularité future d’Ada et d’autres langages de programmation de niveau supérieur. C’est d’où proviennent certains de leurs échecs les plus spectaculaires, tels que la terrible segmentation de la mémoire APX432 et 286,. Avec les 386, ils ont capitulé devant des programmeurs à mémoire plate; paging et un TLB ont été ajoutés et les segments ont été rendus redimensionnables à 4 Go. Et puis, AMD a essentiellement supprimé les segments avec x86_64 en faisant en sorte que la base reg soit un type ne-care / implied-0 (sauf pour fs? Pour TLS, je pense?)
Cela dit, les avantages des segments de mémoire sont évidents: changer d’espace d’adresse sans devoir repeupler un TLB. Peut-être qu'un jour un processeur performant prenant en charge la segmentation sera créé, nous pourrons programmer un système d'exploitation orienté segmentation et les programmeurs pourront créer Ada / Pascal / D / Rust / un autre langage qui ne nécessite pas de plat. programmes de mémoire pour cela.
la source
La segmentation est un lourd fardeau pour les développeurs d'applications. C’est de là que vient la grande pression pour éliminer la segmentation.
Fait intéressant, je me demande souvent à quel point i86 pourrait être meilleur si Intel supprimait tout le support existant pour ces anciens modes. Ici, mieux impliquerait une puissance inférieure et peut-être un fonctionnement plus rapide.
J'imagine que l'on pourrait soutenir qu'Intel a acheté du lait avec des segments de 16 bits conduisant à une révolte des développeurs. Mais avouons-le, un espace d'adressage de 64 Ko n'est rien, surtout quand on regarde une application moderne. En fin de compte, ils ont dû faire quelque chose parce que la concurrence pouvait et avait effectivement marché contre les problèmes d'espace d'adressage de i86.
la source
La segmentation ralentit les conversions et les conversions de pages
Pour ces raisons, la segmentation a été en grande partie abandonnée sur x86-64.
La principale différence entre eux est que:
Bien qu'il puisse sembler plus intelligent de disposer de largeurs de segment configurables, à mesure que vous augmentez la taille de la mémoire d'un processus, la fragmentation est inévitable, par exemple:
deviendra éventuellement comme le processus 1 se développe:
jusqu'à ce qu'une scission soit inévitable:
À ce point:
Avec des pages de taille fixe cependant:
Des morceaux de mémoire de taille fixe sont tout simplement plus faciles à gérer et ont dominé la conception actuelle des systèmes d'exploitation.
Voir aussi: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work
la source