Du brauchst nicht für jede Anwendung Segmente in der GDT/LDT, zumindest wenn du ein flaches Speichermodell benutzt.
Meine GDT sieht so aus:
1. Null Descriptor
2. Kernel Code
3. Kernel Daten
4. User Code
5. User Daten
6. TSS
Die Programme werden so geladen:
1. Eine struct die Informationen über einen Prozess enthällt wird erstellt und in eine linked list geschrieben.
2. In den neuen Prozess werden (bei mir entweder von einem JIT-Compiler, oder von einem sonstigen Programmloader) die Code/Daten/BSS Segmente gemappt. (die z.B. aus einer ELF File ausgelesen werden)
3. Dann wird eine Sturktur für eine Thread erstellt und in eine linked list geschrieben. Sie enthällt einen Stack für den Thread, der dann so aussieht, wie wenn gerade ein interrupt ausgelöst wurde, und danach alle anderen wichtigen Register gepusht wurden.
Das Programmwechseln sieht nun so aus:
1. Der Timer Interrupt wird aufgerufen.
2. Alle wichtigen Register werden gepushed (EAX, EBX, ECX, EDX, ESI, EDI, EBP, sowie die Segmentregister, wobei man das evt. sich sparen könnte, da sie Segmentregister sich ja nicht verändern. (EFLAGS, der Userlevel ESP, CS und EIP werden durch den Aufruf des Interrupts gepushed)
3. Der aktuelle Stack wird in die thread-struct geschrieben
4. Der scheduler sucht einen Thread, das alls nächstes ausgeführt wird.
5. Eventuell wird ein neues Pagedirectory geladen
6. Der neue Stack wird aus der thread-struct des neuen Threads gelesen.
7. Es werden alle wichtigen Register gepoppt.
8. IRET wird ausgeführt, um in das Programm zu springen.