Note: This question is about x86_64 architecture and Linux ABI.
When the program is launched, some space is allocated for stack. Later on, during program execution the stack area can get resized (when more space is required) up to some maximum specified by OS.
Let's take for instance simple program:
int main() {
char bytes[7 * 1024 * 1024];
}
Let's run it under gdb and set breakpoints: before main and after declaring an array.
gdb> b *main
gdb> b main
gdb> r
gdb> info proc mapping // breakpoint before pushing stack
Start Addr End Addr Size Offset objfile
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
gdb> c
gdb> info proc mapping // breakpoint after pushing stack
Start Addr End Addr Size Offset objfile
0x7fffff8fe000 0x7ffffffff000 0x701000 0x0 [stack]
So we can see the stack actually got resized.
The question is how does the OS know when the stack has to be resized?. Some internet resources say OS handles page fault exception
and if the accessed address is within possible stack address range, it gets resized.
But when I was debugging the program step by step, it turned out, the stack got resized just after following instruction:
0x40129d <main+4> sub rsp, 0x700010
So (as far as I know), there is no page fault
yet since we are not accessing the addresses actually. We only change rsp
register. So how is it possible OS handles it? Or maybe there is a page fault exception
after changing rsp
?
The memory needs to be contiguous for an array. So, though stack grows downward, for arrays the stack grows up. In addition if you want to check whether stack grows upward or downward. Declare a local variable in main function.
The MIPS stack — The stack grows downward in terms of memory addresses. — The address of the top element of the stack is stored (by convention) in the “stack pointer” register, $sp. MIPS does not provide “push” and “pop” instructions. Instead, they must be done explicitly by the programmer.
This stack grows downward from its origin. The stack pointer points to the current topmost datum on the stack. A push operation decrements the pointer and copies the data to the stack; a pop operation copies data from the stack and then increments the pointer.
But when I was debugging the program step by step, it turned out, the stack got resized just after following instruction:
0x40129d <main+4> sub rsp, 0x700010
That's not correct. If you step the program you have shown (even if compiled without optimizations), there is no increase in the mapping at all since there are no writes to the stack pages.
But even if you step a less trivial program, you will also see the mapping does not change on the sub
instruction, but rather on every ever-increasing access to the stack.
For instance, if you do:
bytes[0] = 42;
you will see it increases by 0x70000, since you are writing into the top. But if you instead do something like:
bytes[3 * 1024 * 1024] = 42;
You will see it increases up only by 0x40000.
Note that you may be getting confused if you are hitting an instruction that happens to push into the stack, like a call
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With