x86_64-linux-gnu环境下栈指针为何执行减法操作?64位机栈空间疑问
嘿,这个问题我太熟了——在x86_64-linux-gnu环境下,栈指针的减法操作往往会比你计算的变量所需空间多,主要是这几个关键因素在起作用:
16字节栈对齐强制要求
x86_64的System V调用约定明确规定:在调用任何函数之前,栈指针rsp必须是16字节的整数倍。当函数开始执行时,call指令已经把8字节的返回地址压入栈,此时rsp的地址是原rsp - 8,不再满足16对齐。所以编译器会额外让栈指针减去若干字节,确保最终的栈空间起始地址符合对齐要求。哪怕你的buffer1和buffer2加起来只需要24字节(3个8字节),也可能因为对齐需求多减几个字节凑齐16的倍数。栈金丝雀(Stack Canary)保护机制
绝大多数编译器默认开启了栈溢出保护(比如GCC的-fstack-protector选项),会在栈帧里插入一个随机生成的“金丝雀”值,用来检测是否发生栈溢出。这个值占8字节,会被计入栈空间分配的总量里,自然会让栈指针的减法数值变大。调用者保存寄存器的栈空间
如果你的函数用到了x86_64调用约定中要求调用者保存的寄存器(比如rbx、rbp、r12-r15这类),编译器会先把这些寄存器的值压入栈中保存,每个寄存器占8字节,这部分空间也会被算在栈指针的减法操作里。编译器的预留优化空间
有时候编译器会为了优化内存访问效率(比如把变量对齐到32字节的边界),或者预留一些临时空间供函数内部的中间操作使用,也会主动多分配一些栈空间,导致栈指针的减法数值超出你预期的变量总大小。
我之前调试代码时也踩过这个坑,一开始盯着变量大小算空间,结果看汇编里栈指针减的数总多出来,查了调用约定和编译器选项才搞清楚是这些原因在影响。
内容的提问来源于stack exchange,提问作者rgarci0959

