Because there is only one user mode execute segment descriptor
OK. I don't know anything about programming really.
But, you're saying that if in assembly I try to use the .code or .text (depending on the assembler being used) marker in more than one place, the assembler throws an error?
That is, you're not allowed to give a program more than one code segment?
and you don't have GDT access?
Why not?
What's stopping me from coding:
jmp "segment selector":"offset"
where segment selector is some 16 bit value that reaches into the GDT and grabs a code segment?
Why can't I do that?
As long as the dpl for the called upon descriptor is the same or greater than the cpl I don't see a problem.
The only time a far call, aka a CS code selector load, is used is to change privilege level on x86 and you are never doing that in an application in a protected multitasking OS.
What does the OS have to do with anything?
Doesn't the hardware stop this from happening by looking at the pertinent privilege levels?
Any OS restrictions should just be icing on the cake, right?
So, if you want to change privilege levels, you need to pass through a gate.
But what about frameworks and dynamically linked libraries?
Why can't I write some code that expects there to exist, already in the computer's memory, some preexisting code that my code calls out to?
Why can't I call out to some preexisting library at run-time (I believe this is called dynamic linking) that is at the same privilege level as my code?
Also, why can't I call out to some code segment whose privilege level is the same as mine but belongs to another process?
I guess my question here is the same as the one above: why can't I reach into the GDT and grab segments if I'm executing at cpl 3?
I haven't read in Intel's manual yet that there is hardware support for this restriction.
Is it done at the OS level?
If so, then a more permissive OS should allow me to reach into the GDT and grab segments, right?
Your only 2 code/execute descriptors valid for CS are going to be identical except one is DPL0 (selected by 0x0008) and one is DPL3 (selected by 0x001B) (in 32 bit versions both Windows and Linux I believe).
Why does the OS make two identical code segments for a newly loaded process?
Any as every mainstream OS only typically defines the two execute segment descriptors, any attempt to use anything but those two defined selectors for CS values will result in accessing a invalid or null descriptor and also cause a GPF.
OK, so you're kind of confirming my hunch from above that this restriction on grabbing code segments from the GDT is software enforced by the OS and not hardware enforced, assuming of course that the privilege levels work out.
But again, what about calling out to pre-existing executable framework code that is at the same privilege level as the running process?
Why is this not allowed?
Must a gate be used here?
The segmentation feature of descriptors has basically long been disabled and ignored by having base 0 limit max on all descriptors. In addition there is universal R/W/X enabled in descriptors for the entire memory limit and finer granularity over RWX is now deferred to the page tables post DEP/AMD64 improvements.
There is effectively one global RWX segment and the only thing really left that the selector controls at that point is setting CPL 0 or 3 when switching between kernel mode and user mode, so it's easy to see that the idea of far calls from a application or normal programmer perspective in pmode/lmode essentially don't exist.
How do you keep segments from just running into each other and everything getting mashed together?
There is however an OS called Multics that exists...
The forerunner of UNIX?