一、结论
网上的文章有的说C语言调用函数参数使用栈传递,有的说使用寄存器传递。那么到底参数是使用栈还是寄存器呢?
先说结论:
- 32位程序使用栈传递
- 64位程序根据参数的个数而不同
- 参数1~6个,使用寄存器传递
- 参数大于6个,多出来的参数使用栈传递
二、验证
1. 32位程序
- 源代码:
// main.c
void fun(int a, int b)
{
a += 1;
b += 1;
}
int main(void)
{
fun(1, 2);
return 0;
}
- 生成32位的程序:
gcc -g -m32 main.c -o main32
- 使用gdb调试:
gdb main32
- 在gdb中,查看main函数反汇编代码(在gdb中输入
disassemble main
):
注意,我这里设置了gdb的汇编为Intel 汇编,如果没有设置,gdb默认使用AT&T汇编风格。
可以看出:
- 汇编代码先把0x2压栈,然后把0x1压栈
- 对应C源码中,就是参数从右到左入栈
2. 64位程序
64位C程序,参数个数不同,传参方式不同。
2.1 参数小于等于6个
- 源代码(还是上面的代码):
// main.c
void fun(int a, int b)
{
a += 1;
b += 1;
}
int main(void)
{
fun(1, 2);
return 0;
}
- 生成64位的可执行程序:
gcc -m64 -g main.c -o main64
我的gcc默认生成64位的,可以不用-64指定
- 使用gdb调试
gdb main64
- 在gdb中查看main函数的反汇编代码
如上图可以看出:
- 参数传入了寄存器esi和edi
2.2 参数大于6个
- 源代码
void fun(int a, int b, int c, int d, int e, int f, int g)
{
a += 1;
b += 1;
c += 1;
d += 1;
e += 1;
f += 1;
g += 1;
}
int main(void)
{
fun(1, 2, 3, 4, 5, 6, 7);
return 0;
}
- 生成64位程序
gcc -m64 -g main.c -o main64
- gdb调试
gdb main64
- 查看main函数汇编代码
可以看出:
- 传递了7个参数,一个是用栈,其他6个是用的寄存器