Anatomy of a Program in Memory (2009)(manybutfinite.com) |
Anatomy of a Program in Memory (2009)(manybutfinite.com) |
(or click "past" under the title, also helpful to check when you submit a link)
I say all of this in the past tesnse, since Meltdown makes it possible to read all that kernel memory. Kernels now keep most of the kernel memory unmapped when user mode is executing.
Can you elaborate on what you mean be x86 requires that the kernel stack always be mapped into a process address space in order for system calls?
The kernel always knows where a process's kernel stack is located as there is a pointer to it in the user process's task_struct. It is only in kernel mode that the kernel switches the CPU's stack pointer to use that that processes kernel stack.
>It is also possible to create an anonymous memory mapping that does not correspond to any files, being used instead for program data."
This isn't strictly true though is it? It was my understanding even mmap() MAP_ANONYMOUS used a file interface, and that the way the kernel creates anonymous maps is by creating an instance of /dev/zero in tmpfs. Although I believe the file descriptor might be ignored however.
You're totally right though, that threads complicated the traditional "stack grows down heap grows up" view of a Unix user address space.
- If a process has many threads, their stacks are all located within a single virtual address space corresponding to the user process?
- If one thread grows down and is about to overwrite the top of another thread's stack, does the OS detect this automatically and do some sort of reallocation procedure?
That's right there together with the city states of Greece and other ancient memories. Meltdown and Specter happened.
Yep!
> If one thread grows down and is about to overwrite the top of another thread's stack, does the OS detect this automatically and do some sort of reallocation procedure?
The kernel reserves a 8MB region for each stack and that's it (even the initial stack). So you wouldn't get overlapping stacks per se; the regions are preallocated. The kernel does try to detect stack overflow/underflow with guard pages, but that's just a best attempt kind of thing, and of you underflow by more than page you can just end up just corrupting memory.
And all of this is for C's sort of standard model. 'Split stacks' is a scheme closer to your second question, but there's a lot of overhead of that model, and not a lot of runtimes use it.
I've also even more rarely seen a model that allocates stack frames on the heap and links them together in a linked list.
But like I said, these schemes are very in practice.
OK, in the context of 'why can't you cleanly have the kernel in a different address space from user processes on x86', the same reasons apply. It's a chicken/egg thing, as a syscall instruction executes and touches the kernel stack before you have a chance to change mmu mappings.
There are versions of Darwin for x86 (but no released versions of full OSX AFAIK) that separate the address spaces, but they reserve a (albeit much smaller) piece of virtual address space at the top for the kernel in all address spaces in order to facilitate the transition to the full kernel address space.
Thanks for the clarification.