X86-64 体系结构上 C语言的函数参数的传递
函数参数的传递用的是通用寄存器或堆栈,是可以由编译器来决定的,不过一般都会遵守特定规则,以GCC为例,看一下其在X86和X64上是什么情况
测试代码:
int test6(int p1, int p2, int p3, int p4, int p5, int p6) { return p1+p2+p3+p4+p5+p6; } int test7(int p1, int p2, int p3, int p4, int p5, int p6, int p7) { return p1+p2+p3+p4+p5+p6+p7; } int main() { test6(301,302,303,304,305,306); test7(301,302,303,304,305,306,307); }
在X64平台上,生成的部分汇编文件:
main: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $306, %r9d movl $305, %r8d movl $304, %ecx movl $303, %edx movl $302, %esi movl $301, %edi call test6 pushq $307 movl $306, %r9d movl $305, %r8d movl $304, %ecx movl $303, %edx movl $302, %esi movl $301, %edi call test7 addq $8, %rsp movl $0, %eax leave .cfi_def_cfa 7, 8 ret
可以看到,对于六个参数的函数,依次用了edi, esi, edx, ecx, r8d, r9d六个寄存器实现参数传递。而对于七个参数的函数,最后一个参数用栈来传递。
在32位结构上,情况却不太相同:
main: .LFB2: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax pushl $306 pushl $305 pushl $304 pushl $303 pushl $302 pushl $301 call test6 addl $24, %esp pushl $307 pushl $306 pushl $305 pushl $304 pushl $303 pushl $302 pushl $301 call test7 addl $28, %esp movl $0, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret
所有的参数都用栈来传递。
了解函数参数的传递方式,对于程序调试和bug的分析,可以提供一定帮助。