Page 1 of 1

GDT during runtime

Posted: Thu Mar 21, 2013 1:37 pm
by greyOne
I'm wondering, how practical, plausible and effective modifying the GDT is during program runtime; every time I spawn a new process, I valloc() it a new stack, and I want to give the stack its own GDT entry. Likewise, every time a process dies, the stack is deallocated and zeroed out, so I'd want to remove said GDT entry.

That said, it might mean I'd be changing the GDT as often as once a minute, perhaps more depending on system load. Furthermore, since threads also have their own stack, they'd need entries as well, which might mean I'd end up with a huge number of them.
Is this at all a practical way to go about this all of this? I haven't really found anything to reference in theory relating to this.

I was wondering if somehow jamming all the stacks together into one bounded area of the memory would be a better solution and just having an entry for that, but then I'd have to somehow manually prevent the stacks from writing over each other, and I'd have a hard cap on how many threads and process can concurrently exist.

EDIT:
Hmm. I just found a reference to LDT, but there doesn't seem to be anything about it on the Wiki...
Maybe Wikipedia...

EDIT:
According to Wikipedia, modern OSes make use of the LDT very little. Paging has replaced it in most cases.

Re: GDT during runtime

Posted: Thu Mar 21, 2013 1:50 pm
by FallenAvatar
Are you in protected mode? if yes, you can use virtual memory for the stack and have all stacks at the same location in memory, but none of the stacks would mess with each other because said virtual memory.

If you are in real mode, you can do what you are saying, but I don't have the experience to even guess at performance, or "realistic" consequences due to this.

- Monk

EDIT: Yes, virtual memory/paging generally replaces the GDT/LDT in terms of inter-process protection as well as forcing a "fixed" address space, and overcoming the limitations of said GDT and LDT.

Re: GDT during runtime

Posted: Fri Mar 22, 2013 2:16 am
by Brendan
Hi,
greyOne wrote:I'm wondering, how practical, plausible and effective modifying the GDT is during program runtime; every time I spawn a new process, I valloc() it a new stack, and I want to give the stack its own GDT entry. Likewise, every time a process dies, the stack is deallocated and zeroed out, so I'd want to remove said GDT entry.
It would be easy for the kernel to change a GDT entry (e.g. an "expand down" CPL=3 stack limit), and because SS gets loaded when you return to CPL=3 anyway it won't really effect performance.

However...

For multi-CPU systems different processes/threads will be running on different CPUs and therefore you'd need one GDT entry per CPU. For example, with 16 CPUs you'd need 16 GDT entries for CPL=3 stacks (plus another 16 entries for TSSs). Of course this is a very minor problem.

The big problem is compilers. Consider this code:

Code: Select all

int variableInDataSection = 1234;

void foo(void) {
    int variableOnStack = 3456;

    bar(&variableInDataSection);
    bar(&variableOnStack);
}

void bar(int *pointerToValue) {
    *pointerToValue = *pointerToValue + 1;
}
In this case, the compiler can't know if "pointerToValue" refers to something on the stack or something in the data section; and can't know whether to use DS or SS to access the value. The only real way around this problem is to make the segment part of the pointer (e.g. 48-bit pointers that contain a 16-bit segment plus a 32-bit offset). This means that accessing anything via. pointers involves segment register loads, and "accessing things via. pointers" happens relatively frequently. Segment register loads are slow. You do not want to be doing slow segment register loads frequently.

Nobody else wanted to do slow segment register loads frequently either; which means that modern compilers for 80x86 don't support it - they just assume that DS = ES = SS and that segmentation can be ignored. There are/were some ancient old compilers (mostly intended for DOS) that do support segmentation, but they suck because they're old (e.g. don't support more recent CPU features like SSE4 or AVX) and would make the performance problem worse.


Cheers,

Brendan

Re: GDT during runtime

Posted: Fri Mar 22, 2013 7:00 pm
by linguofreak
Brendan wrote: In this case, the compiler can't know if "pointerToValue" refers to something on the stack or something in the data section; and can't know whether to use DS or SS to access the value. The only real way around this problem is to make the segment part of the pointer (e.g. 48-bit pointers that contain a 16-bit segment plus a 32-bit offset). This means that accessing anything via. pointers involves segment register loads, and "accessing things via. pointers" happens relatively frequently. Segment register loads are slow. You do not want to be doing slow segment register loads frequently.
What you could do, (though it would have the restriction that all pointers used in a given function call must belong to the same segment) is use FS or GS as the base segment for all pointers passed as parameters to functions (then you just need an FS or GS override instead of a segment load inside the function). It would be set to a default value (say, such that FS = DS), and any code that wanted to pass a pointer in a different segment as a parameter to a function would load the parameter segment register before making the function call and restore the default afterwards.

Re: GDT during runtime

Posted: Fri Mar 22, 2013 8:19 pm
by Owen
... thereby breaking any global data/constant/miscellaneous other internal compiler generated references inside that function..