Hai detto che erano interessati a questo il motivo per cui, in modo da:
in modalità reale, un segmento è una "finestra" 64K di memoria fisica e queste finestre sono distanziate di 16 byte. In modalità protetta, un segmento è una finestra per la memoria fisica o virtuale, le cui dimensioni e posizione sono determinate dal sistema operativo e ha molte altre proprietà, tra cui il livello di privilegi che un processo deve avere per accedervi.
Da qui in poi, tutto ciò che dico si riferisce alla modalità protetta.
C'è una tabella in memoria chiamata tabella dei descrittori globali (GDT), che è dove vengono conservate le informazioni su queste dimensioni e posizioni delle finestre e altre proprietà. Potrebbero esserci anche tabelle di descrittori locali su una base per processo e funzionano in modo simile, quindi mi concentrerò solo sul GDT.
Il valore caricato in un registro segmenti è noto come selettore segmento . È un indice nel GDT o nel LDT, con un po 'di informazioni di sicurezza extra. Naturalmente se un programma tenta di caricare un descrittore che è fuori dai limiti del GDT, si verifica un'eccezione. Inoltre, se il processo non ha privilegi sufficienti per accedere al segmento, o qualcos'altro non è valido, si verifica un'eccezione.
Quando si verifica un'eccezione, il kernel lo gestisce. Questo tipo di eccezione verrebbe probabilmente classificato come un errore di segmentazione. Quindi il sistema operativo uccide il tuo programma.
C'è un'ultima avvertenza: nel set di istruzioni x86, non è possibile caricare i valori immediati nei registri di segmento. È necessario utilizzare un registro intermedio o un operando di memoria o POP nel registro dei segmenti.
MOV DS, 160 ;INVALID - won't assemble
MOV AX, 160 ;VALID - assembles, but will probably result in an
MOV DS, AX ;exception, and thus the death of your program
Penso che si debba sottolineare che l'architettura consente cumuli di segmenti. Ma per quanto ne so, quando si tratta di principali sistemi operativi x86, registri di segmento servono solo un paio di scopi:
- meccanismi di sicurezza, come il mantenimento processi dello spazio utente di danneggiare l'altro o il sistema operativo
- affrontare con più/processori multi-core
- Memorizzazione locale dei thread: come ottimizzazione, alcuni sistemi operativi (incluso Linux e Windows) utilizzano i registri di segmento per lo storage locale thread (TLS). Poiché i thread condividono lo stesso spazio di indirizzamento, è difficile per un thread "sapere" dove si trova la sua regione TLS senza utilizzare una chiamata di sistema o sprecare un registro ... ma poiché i registri di segmento sono praticamente inutili, non c'è nulla di male nello "sprecare" per il veloce TLS. Si noti che durante l'impostazione, un sistema operativo può saltare i registri dei segmenti e scrivere direttamente nei registri della cache dei descrittori, che sono registri "nascosti" usati per memorizzare nella cache le ricerche GDT/LDT innescate dai riferimenti ai registri dei segmenti, nel qual caso se si prova per leggere dai registri dei segmenti non lo vedrai.
Oltre a un segmento per thread per TLS, vengono utilizzati solo pochi segmenti (moltiplicato il numero di processori) e solo dal sistema operativo. I programmi applicativi possono completamente ignorare i registri di segmento.
Ciò è dovuto al design del sistema operativo, non a eventuali limitazioni tecniche. Ci possono essere sistemi operativi incorporati che richiedono programmi di spazio utente per lavorare con i registri di segmento, anche se non ne conosco nessuno.
Qual è l'errore? – Blorgbeard
Sotto un SO o indipendente? 16 modalità protetta reale o 32 bit? Quale codice non è stato compilato? Esempio a 16 bit minimo con effetti osservabili: https://github.com/cirosantilli/x86-bare-metal-examples/blob/d4aae6183b98564819107b44a77641979c35d2c3/segment_registers.S –