x86-64栈传递多余参数大小及int参数8字节占用疑问
技术问询
- 栈传递的多余参数的大小是多少?
C代码
int f(int a, int b, int c, int d, int e, int f, int g, int h, int i) {f = 8; g = 3; h=9; i = 12; return g;} int main() { f(1,2,3,4,5,6,7,8,9); return 0; }
编译后的x86-64汇编(Intel语法)
该代码通过gcc -S -masm=intel sth.c编译为如下汇编:
.file "passord.c" .intel_syntax noprefix .text .globl f .type f, @function f: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 mov DWORD PTR -4[rbp], edi mov DWORD PTR -8[rbp], esi mov DWORD PTR -12[rbp], edx mov DWORD PTR -16[rbp], ecx mov DWORD PTR -20[rbp], r8d mov DWORD PTR -24[rbp], r9d mov DWORD PTR -24[rbp], 8 mov DWORD PTR 16[rbp], 3 ; HERE mov DWORD PTR 24[rbp], 9 ; HERE mov DWORD PTR 32[rbp], 12 mov eax, DWORD PTR 16[rbp] pop rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size f, .-f .globl main .type main, @function main: .LFB1: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 push 9 push 8 push 7 mov r9d, 6 mov r8d, 5 mov ecx, 4 mov edx, 3 mov esi, 2 mov edi, 1 call f add rsp, 24 mov eax, 0 leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE1: .size main, .-main .ident "GCC: (Debian 12.2.0-14) 12.2.0" .section .note.GNU-stack,"",@progbits
疑问聚焦
关注如下汇编片段:
mov DWORD PTR 16[rbp], 3 mov DWORD PTR 24[rbp], 9
第7个参数与第8个参数的地址差为8字节,而由寄存器传递的参数存入局部内存时为4字节值,但所有参数均为int类型。为何栈传递的参数使用8字节空间?目前已查阅《System V ABI》第17页,但仍不确定原因,特此问询。
解答
栈传递的每个参数占用8字节空间,这是x86-64 System V ABI的强制规定,核心原因有两点:
维护栈对齐要求
x86-64 System V ABI明确规定,调用函数前栈指针rsp必须保持16字节对齐。执行call指令会压入8字节的返回地址,进入函数后rsp变为16n-8;再执行push rbp后,rsp变为16n-16,此时rbp指向的栈帧基址是16字节对齐的。栈参数从rbp+16开始分配,每个参数占8字节,确保后续所有栈操作始终符合对齐规范,避免因对齐错误导致的性能问题或硬件异常。简化栈操作逻辑
统一使用8字节的参数槽位,不管参数本身的大小(哪怕是4字节的int),可以让调用者和被调用者的栈偏移计算更简单,无需根据参数类型调整分配空间,降低了编译和运行时的复杂度。
结合你的代码验证:
main函数中传递3个栈参数后,用add rsp,24恢复栈指针,24字节正好对应3个8字节的参数槽位;- 函数
f中第7个参数g的地址是rbp+16,第8个参数h是rbp+24,间隔8字节,完全符合ABI规定的栈参数布局。
内容的提问来源于stack exchange,提问作者fgh
相关产品推荐
相关产品推荐

