I am trying to understand how stack allocation and alignment works with pthreads on a Linux x86_64 system with gcc and what data the system stores on the stack. I know that you can configure the stack memory using pthread_attr_setstack. I’ve done this in a test program that does the following:
1) recursively calls itself and updates an uninitialized array that is allocated on the stack
2) prints out the value of the first array element, the last element, and rsp
From this I’ve been able to observe how rsp gets incremented (in my test program I noticed some of the recursive calls were inlined by the compiler). I’ve also been able to see that adding TLS memory (with __thread variables) causes the first value of rsp to be lower. So it looks like TLS variables are allocated on the top of the stack.
However, what I’m not sure about is what else is there. It looks to me like the first page of the stack is reserved for the system in some way because none of the stack variables that I allocate end up in that region. Even if I don’t use any __thread variables the variables that I do instantiate do not appear to be allocated in the first page (I set the stack memory so that it is page aligned).
So my question is: what else, if anything, is on the stack for a pthread besides TLS data and stack variables?
On Linux NPTL:
The very top of the stack contains the TCB. This is also known as
struct pthreadorpthread_t. It’s a bit hairy due to all the weird glibc system-specific defines, but basically it contains things like:pthread_cleanupand stack unwind informationpthread_setspecific– if you exceed this number, the rest are allocated on the heappthread_joinThis is mostly initialized in
pthread_create(__pthread_create_2_1innptl/pthread_create.cif you’re following along in the eglibc source), before the new thread actually starts running.Below the TCB is statically allocated
__threadvariables – or, at least, those the linker could identify at startup time. The dynamic linker initializes al_tls_offsetfield in the linker map to tell the NPTL code how much space to reserve. Note that libraries loaded after program startup won’t be part of this – see the__threadABI spec for details.Below the
__threadvariables is the stack. The top of this stack is thestart_thread()code, so it’ll still be a ways before it actually executes user code (but not too much further).