根据https://learn.microsoft.com/en-us/cpp/build/stack-usage?view=msvc-170 ,调用者必须始终为 4 个寄存器参数分配足够的空间,即使被调用者没有那么多参数。始终为寄存器参数分配空间,即使参数本身从未驻留在堆栈中。
这4个寄存器参数的影子空间有什么用?
我反汇编了一些VS和G++编译的程序,发现被调用者一开始就将寄存器参数保存在影子空间中。例如,WinMain(HINSTANCE *hInstance, HINSTANCE *hPrevInstance, char *lpCmdLine, int nCmdShow)
函数在其开头执行以下推送:
mov [rsp+arg_18], r9d
mov [rsp+arg_10], r8
mov [rsp+arg_8], rdx
mov [rsp+arg_0], rcx
为什么被调用者将寄存器参数保存在影子空间中?
如果被调用者必须将寄存器参数保存在堆栈中,为什么他们使用寄存器来传递参数而不是直接通过堆栈传递所有参数?
最佳答案
被调用者可能需要也可能不需要保存它们,这完全取决于情况。例如,仅返回参数总和的函数可能不需要保存它们。在这种情况下,使用寄存器可以保存存储和加载,而在其他情况下不会产生任何开销(存储只是从调用者移动到被调用者)。
如果您与调用者中的局部变量一起分配影子空间,那么分配影子空间实际上是免费的,并且具有以下优点:如果被调用者需要保存参数,则生成的 block 将与已存在的其余参数连续在堆栈上。
关于assembly - x64 调用约定中前 4 个参数的影子空间的用途是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26959372/