Uninformed: Informative Information for the Uninformed

Vol 4» 2006.Jun


Parameters

The calling convention for functions on x64 dictates that the first four parameters are passed via register with any remaining parameters, starting with parameter five, spilling to the stack. Given that the fifth parameter is the first parameter passed by the stack, one would think that the fifth parameter would be the value immediately adjacent to the return address on the stack, but this is not the case. Instead, if a given function calls other functions, that function is required to allocate stack space for the parameters that are passed by register. This has the affect of making it such that the area of the stack immediately adjacent to the return address is 0x20 bytes of uninitialized storage for the parameters passed by register followed immediately by any parameters that spill to the stack (starting with parameter five). The area of storage allocated on the stack for the register parameters is known as the register parameter area whereas the area of the stack for parameters that spill onto the stack is known as the stack parameter area. The table below illustrates what the parameter portion of a stack frame would look like after making a call to a function:


\begin{tabular}{\vert c\vert}
\par
\hline
\par
Parameter 6 \\
\hline
Paramete...
...1 (\texttt{RCX} Home) \\
\hline
Return address \\
\par
\hline
\end{tabular}

To emphasize further, the register parameter area is always allocated, even if the function being called has fewer than four arguments. This area of the stack is effectively owned by the called function, and as such can be used for volatile storage during the course of the function call. In particular, this area is commonly used to persist the values of register parameters3.2. However, it can also be used to save non-volatile registers. To someone familiar with x86 it may seem slightly odd to see functions modifying areas of the stack beyond the return address. The key is to remember that the 0x20 bytes immediately adjacent to the return address are owned by the called function. One important side affect of this requirement is that if a function calls other functions, the calling function's minimum stack allocation will be 0x20 bytes. This accounts for the register parameter area that will be used by called functions.

The obvious question to ask at this point is why it's the caller's responsibility to allocate stack space for use by the called function. There are a few different reasons for this. Perhaps most importantly, it makes it possible for the called function to take the address of a parameter that's passed via a register. Furthermore, the address that is returned for the parameter must be at a location that is contiguous in relation to the other parameters. This is particularly necessary for variadic functions, which require a contiguous list of parameters, but may also be necessary for applications that make assumptions about being able to reference parameters in relation to one another by address. Invalidating this assumption would introduce source compatibility problems.

For more information on parameter passing, refer to the MSDN documentation[4,7].