1、函数参数的带入
- 参数带入顺序
以如下代码为例:
int fun(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int a = fun(10, 20);
return 0;
}
调试进入main函数栈帧,EBP = 0x006FFC4C(不固定),ESP = 0x006FFC00(不固定),edp作为栈底寄存器,esp作为栈顶寄存器,栈顶栈底唯一地标识一个函数调用栈。
以下是上段代码调用fun函数部分的汇编代码
int a = fun(10, 20);
0018141E push 14h
00181420 push 0Ah
00181422 call fun (01811D1h)
从上边汇编代码可以看出首先入栈的是20,然后是10,由此可以看出,参数入栈的顺序是从右向左依次入栈的。
- 参数小于等于8字节的参数带入
当参数大小为1字节的时候,以如下代码为例:
struct tmp
{
char a;
};
int fun(struct tmp a, struct tmp b)
{
return 0;
}
int main()
{
struct tmp tmp1;
tmp1.a = 10;
struct tmp tmp2;
tmp2.a = 20;
int a = fun(tmp1, tmp2);
return 0;
}
其调用fun函数部分的汇编代码如下:
int a = fun(tmp1, tmp2);
002F1A46 movzx eax,byte ptr [tmp2]
002F1A4A push eax
002F1A4B movzx ecx,byte ptr [tmp1]
002F1A4F push ecx
002F1A50 call fun (02F11E0h)
由以上汇编代码可以看出首先将tmp2的值取出存放在eax寄存器中,然后将eax push入栈,再取出tmp1的值存入ecx寄存器中,然后push入栈。由此可见一个字节的参数采用的是push入栈的方式将参数带入。
当参数大小为4字节的时候,以如下代码为例:
struct tmp
{
int a;
};
int fun(struct tmp a, struct tmp b)
{
return 0;
}
int main()
{
struct tmp tmp1;
tmp1.a = 10;
struct tmp tmp2;
tmp2.a = 20;
int a = fun(tmp1, tmp2);
return 0;
}
其调用fun函数部分的汇编代码如下:
int a = fun(tmp1, tmp2);
011F365C mov eax,dword ptr [tmp2]
011F365F push eax
011F3660 mov ecx,dword ptr [tmp1]
011F3663 push ecx
011F3664 call fun (011F11E0h)
其汇编代码和参数为1字节的时候汇编代码