I'm studying the ELF specification (http://www.skyfree.org/linux/references/ELF_Format.pdf), and one point that is not clear to me about the program loading process is how the stack is initialized, and what the initial page size is. Here's the test (on Ubuntu x86-64):
$ cat test.s .text .global _start _start: mov $0x3c,%eax mov $0,%edi syscall $ as test.s -o test.o && ld test.o $ gdb a.out -q Reading symbols from a.out...(no debugging symbols found)...done. (gdb) b _start Breakpoint 1 at 0x400078 (gdb) run Starting program: ~/a.out Breakpoint 1, 0x0000000000400078 in _start () (gdb) print $sp $1 = (void *) 0x7fffffffdf00 (gdb) info proc map process 20062 Mapped address spaces: Start Addr End Addr Size Offset objfile 0x400000 0x401000 0x1000 0x0 ~/a.out 0x7ffff7ffa000 0x7ffff7ffd000 0x3000 0x0 [vvar] 0x7ffff7ffd000 0x7ffff7fff000 0x2000 0x0 [vdso] 0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack] 0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
The ELF specification has very little to say about how or why this stack page exists in the first place, but I can find references that say that the stack should be initialized with SP pointing to argc, with argv, envp and the auxiliary vector just above that, and I have confirmed this. But how much space is available below SP? On my system there are
0x1FF00 bytes mapped below SP, but presumably this is counting down from the top of the stack at
0x7ffffffff000, and there are
0x21000 bytes in the full mapping. What influences this number?
I am aware that the page just below the stack is a "guard page" that automatically becomes writable and "grows down the stack" if I write to it (presumably so that naive stack handling "just works"), but if I allocate a huge stack frame then I could overshoot the guard page and segfault, so I want to determine how much space is already properly allocated to me right at process start.
EDIT: Some more data makes me even more unsure what's going on. The test is the following:
.text .global _start _start: subq $0x7fe000,%rsp movq $1,(%rsp) mov $0x3c,%eax mov $0,%edi syscall
I played with different values of the constant
0x7fe000 here to see what happens, and for this value it is nondeterministic whether I get a segfault or not. According to GDB, the
subq instruction on its own will expand the size of the mmap, which is mysterious to me (how does linux know what's in my register?), but this program will usually crash GDB on exit for some reason. It can't be ASLR causing the nondeterminism because I'm not using a GOT or any PLT section; the executable is always loaded at the same locations in virtual memory every time. So is this some randomness of the PID or physical memory bleeding through? All in all I'm very confused as to how much stack is actually legally available for random access, and how much is requested on changing RSP or on writing to areas "just out of range" of legal memory.