Chaque région du diagramme est-elle un segment?
Ce sont 2 utilisations presque totalement différentes du mot "segment"
- Segmentation x86 / registres de segments: les systèmes d'exploitation x86 modernes utilisent un modèle de mémoire plate où tous les segments ont la même base = 0 et la limite = max en mode 32 bits, le même que le matériel l'impose en mode 64 bits , ce qui rend la segmentation un peu vestigiale . (Sauf pour FS ou GS, utilisé pour le stockage local des threads même en mode 64 bits.)
- Sections / segments de l'éditeur de liens / programme. ( Quelle est la différence de section et de segment au format de fichier ELF )
Les usages ont une origine commune: si vous avez utilisé un modèle de mémoire segmentée ( en particulier sans mémoire paginée virtuel), vous pouvez avoir les données et les adresses du SRS être relatif à la base de segment DS, la pile par rapport à la base de SS et le code par rapport à la Adresse de base CS.
Ainsi, plusieurs programmes différents pourraient être chargés vers différentes adresses linéaires, ou même déplacés après le démarrage, sans modifier les décalages 16 ou 32 bits par rapport aux bases de segments.
Mais alors vous devez savoir à quel segment un pointeur est relatif, vous avez donc des "pointeurs éloignés" et ainsi de suite. (Les programmes x86 16 bits réels n'avaient souvent pas besoin d'accéder à leur code en tant que données, ils pouvaient donc utiliser un segment de code 64k quelque part, et peut-être un autre bloc 64k avec DS = SS, la pile passant de décalages élevés et les données à ou un minuscule modèle de code avec toutes les bases de segments égales).
Comment la segmentation x86 interagit avec la pagination
Le mappage d'adresses en mode 32/64 bits est:
- segment: offset (base de segment impliquée par le registre contenant l'offset, ou remplacée par un préfixe d'instruction)
- Adresse virtuelle linéaire 32 ou 64 bits = base + décalage. (Dans un modèle de mémoire plate comme Linux, les pointeurs / décalages = adresses linéaires aussi. Sauf lors de l'accès à TLS par rapport à FS ou GS.)
les tables de pages (mises en cache par TLB) sont mappées linéairement à 32 (mode hérité), 36 (hérité PAE) ou 52-bit (x86-64) adresse physique. ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Cette étape est facultative: la pagination doit être activée lors du démarrage en définissant un bit dans un registre de contrôle. Sans pagination, les adresses linéaires sont des adresses physiques.
Notez que la segmentation ne vous permet pas d'utiliser plus de 32 ou 64 bits d'espace d'adressage virtuel dans un seul processus (ou thread) , car l'espace d'adressage plat (linéaire) dans lequel tout est mappé n'a que le même nombre de bits que les décalages eux-mêmes. (Ce n'était pas le cas pour le x86 16 bits, où la segmentation était en fait utile pour utiliser plus de 64 Ko de mémoire avec principalement des registres et des décalages 16 bits.)
Le CPU met en cache les descripteurs de segment chargés à partir du GDT (ou LDT), y compris la base du segment. Lorsque vous déréférencer un pointeur, selon le registre dans lequel il se trouve, il est par défaut DS ou SS comme segment. La valeur de registre (pointeur) est traitée comme un décalage par rapport à la base du segment.
Étant donné que la base de segment est normalement nulle, les processeurs font un cas spécial. Ou d'un autre point de vue, si vous n'avez une base de segment non-zéro, les charges ont une latence supplémentaire parce que le « spécial » (normal) cas de contournement d' ajouter l'adresse de base ne s'applique pas.
Comment Linux configure les registres de segments x86:
La base et la limite de CS / DS / ES / SS sont toutes 0 / -1 en mode 32 et 64 bits. C'est ce qu'on appelle un modèle de mémoire plate car tous les pointeurs pointent vers le même espace d'adressage.
(Les architectes du processeur AMD ont neutralisé la segmentation en appliquant un modèle de mémoire plate pour le mode 64 bits parce que les systèmes d'exploitation traditionnels ne l'utilisaient pas de toute façon, à l'exception de la protection sans exécutable qui était fournie d'une bien meilleure manière en paginant avec le PAE ou x86- Format de table de 64 pages.)
TLS (Thread Local Storage): FS et GS ne sont pas fixes à base = 0 en mode long. (Ils étaient nouveaux avec 386, et n'étaient utilisés implicitement par aucune instruction, pas même les rep
instructions -string qui utilisent ES). x86-64 Linux définit l'adresse de base FS pour chaque thread sur l'adresse du bloc TLS.
Par exemple, mov eax, [fs: 16]
charge une valeur 32 bits de 16 octets dans le bloc TLS pour ce thread.
le descripteur de segment CS choisit le mode dans lequel se trouve la CPU (mode protégé 16/32/64 bits / mode long). Linux utilise une seule entrée GDT pour tous les processus de l'espace utilisateur 64 bits et une autre entrée GDT pour tous les processus de l'espace utilisateur 32 bits. (Pour que le CPU fonctionne correctement, DS / ES doit également être défini sur des entrées valides, tout comme SS). Il choisit également le niveau de privilège (noyau (anneau 0) par rapport à l'utilisateur (anneau 3)), donc même lorsqu'il revient à l'espace utilisateur 64 bits, le noyau doit toujours s'arranger pour que CS change, en utilisant iret
ou à la sysret
place d'un normal instruction jump ou ret.
Dans x86-64, le syscall
point d'entrée utilise swapgs
pour basculer GS de GS de l'espace utilisateur vers le noyau, qu'il utilise pour trouver la pile de noyau pour ce thread. (Un cas spécialisé de stockage local par thread). L' syscall
instruction ne modifie pas le pointeur de pile pour pointer vers la pile du noyau; il pointe toujours vers la pile utilisateur lorsque le noyau atteint le point d'entrée 1 .
DS / ES / SS doivent également être définis sur des descripteurs de segment valides pour que le processeur fonctionne en mode protégé / mode long, même si la base / limite de ces descripteurs est ignorée en mode long.
Donc, fondamentalement, la segmentation x86 est utilisée pour TLS, et pour les tâches osdev x86 obligatoires que le matériel vous oblige à faire.
Note de bas de page 1: histoire amusante: il existe des archives de listes de diffusion de messages entre les développeurs du noyau et les architectes AMD datant de quelques années avant la sortie du silicium AMD64, ce qui a entraîné des modifications de la conception de syscall
sorte qu'il était utilisable. Voir les liens dans cette réponse pour plus de détails.