1 参数传递(默认调用约定)
用VC6.0新建一个空的控制台应用程序,新建源文件main.c,编写如下代码,注意用debug编译,不要用release,以免代码被VC优化,反汇编对应不上。
int AddInt(int a, int b)
{
int c = a+b;
return c;
}
int main()
{
int x = AddInt(1, 3);
return 0;
}
在main函数进入的大括号处下断,按F5运行,程序断下,这时按组合键“ALT+8”,则可以打开反汇编窗口,每条C语句的下面几行就是相应的汇编代码。
7: int main()
8: {
00401060 push ebp
00401061 mov ebp,esp
00401063 sub esp,44h
00401066 push ebx
00401067 push esi
00401068 push edi
00401069 lea edi,[ebp-44h]
0040106C mov ecx,11h
00401071 mov eax,0CCCCCCCCh
00401076 rep stos dword ptr [edi]
9: int x = AddInt(1, 3);
00401078 push 3
0040107A push 1
0040107C call @ILT+0(AddInt) (00401005)
00401081 add esp,8
00401084 mov dword ptr [ebp-4],eax
10: return 0;
00401087 xor eax,eax
11: }
00401089 pop edi
0040108A pop esi
0040108B pop ebx
0040108C add esp,44h
0040108F cmp ebp,esp
00401091 call __chkesp (004010b0)
00401096 mov esp,ebp
00401098 pop ebp
00401099 ret
其他内容暂时不考虑,我们看0040107C这一句call @ILT+0(AddInt) (00401005),正是调用AddInt这个函数。在调用前有两个关键语句:
00401078 push 3
0040107A push 1
可看出来,这里在默认的函数调用时,参数通过堆栈来传递,并且是从右向左依次入栈。
在调用后:
00401081 add esp,8
这句是为了平衡堆栈,因为刚才入栈的参数是两个整型数,栈顶移动了8个字节,所以这里ESP加上8,保持堆栈的平衡。
2 返回值的保存
在上一节的程序中AddInt函数处下断点:
F5运行断下后,按“ALT+F8”打开反汇编窗口
1: int AddInt(int a,int b)
2: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]
3: int c = a+b;
00401038 mov eax,dword ptr [ebp+8]
0040103B add eax,dword ptr [ebp+0Ch]
0040103E mov dword ptr [ebp-4],eax
4: return c;
00401041 mov eax,dword ptr [ebp-4]
5: }
00401044 pop edi
00401045 pop esi
00401046 pop ebx
00401047 mov esp,ebp
00401049 pop ebp
0040104A ret
我们看最后函数返回处的汇编代码:
4: return c;
00401041 mov eax,dword ptr [ebp-4]
这句就是,把本来存在[ebp-4]这个地址中的a+b的计算结果,再保存到寄存器EAX中。所以,我们可以知道函数的返回值保存在EAX中,基本上函数都是这样传递返回值的。