C++函数有参调用有几种传参方式: 函数
一.传值 编码
二.传指针(地址) spa
三.传引用 指针
其中参数可被const修饰,也能够有默认值。下面分状况讨论: code
为了简洁,省略main函数的汇编码而直接给出func函数的汇编码。 ip
一.传值调用 内存
有源代码: class
void func(int a,char b){ int c; c=a+b; } int main(int argc,char *argv[]) { //call func func(10,'a'); return 0; }下面看看汇编码:
调用发生时: 变量
//call func func(10,'a'); //进行参数压栈操做,首先是'a'压入栈,而后是10压栈,而后call跳转表,再由调转表call函数 00F1141E push 61h 00F11420 push 0Ah 00F11422 call 00F1113B //函数调用完成后,栈减少8字节,两个dword,由于CPU对栈的操做都是双字操做,这里两个参数就是两个双字 00F11427 add esp,8具体内存中的表现是这样的(先让func把栈初始化):
显然不在func的stack内,注意两个参数前面还有两个DWORD, 引用
一个是00f1 1427,另外一个是00dd f794;这两个DWORD的产生应该是在PUSH两个参数以后,
又有的两个PUSH,显然,第一个PUSH 00f1 1427是在call 时将ip压栈致使的:
这个ip是当前这条call 指令的下一条指令(add)的地址,请参考上面的main函数。
第二个PUSH是在 func函数中完成的,能够参考func函数的汇编码:
void func(int a,char b){ 00F113D0 push ebp //这里第二个PUSH,压入ebp,显然这个ebp的值能够在main函数里面看到, //有两条: //## 00F11401 mov ebp,esp //## 00F11403 sub esp,0C0h //那么ebp就是main的栈底 00F113D1 mov ebp,esp 00F113D3 sub esp,0CCh 00F113D9 push ebx 00F113DA push esi 00F113DB push edi 00F113DC lea edi,[ebp+FFFFFF34h] 00F113E2 mov ecx,33h 00F113E7 mov eax,0CCCCCCCCh 00F113EC rep stos dword ptr es:[edi] int c; c=a+b; 00F113EE movsx eax,byte ptr [ebp+0Ch] 00F113F2 add eax,dword ptr [ebp+8] 00F113F5 mov dword ptr [ebp-8],eax } 00F113F8 pop edi 00F113F9 pop esi 00F113FA pop ebx 00F113FB mov esp,ebp 00F113FD pop ebp 00F113FE ret调用发生时,压入两个参数后,必须再保存下一条指令的位置,所以有一个压栈操做,这个操做是有call指令来完成的。 其次,func函数将ebp压栈是为了为恢复堆栈作准备。由于CPU只有两个寄存器用于堆栈操做:SS:SP,为了调用func函数完成时能进入main的堆栈,必须先保存(push ebp)再恢复(pop ebp),这一点从func函数末尾也看得出。
此外,更直观一点,从内存中看得出:第二个push 00ddf794和func的stack靠的很近:
刚好是指向了main的栈底。
再来看看func里面:
int c; c=a+b; 00F113EE movsx eax,byte ptr [ebp+0Ch] 00F113F2 add eax,dword ptr [ebp+8] 00F113F5 mov dword ptr [ebp-8],eax //通过分析能够知道: //&b = ebp+0ch //&a = ebp+8 //&c = ebp-8 //在上面的分析中咱们知道这个ebp是指向栈底的,局部变量c在栈内,参数a 和 b 是以前push进来的通过上述分析,能够得出一些结论:
有参函数调用发生时:
1.先将参数从右向左依次压栈
2.将下一条指令的地址压栈
3.被调函数将主调函数的栈底位置压栈
4.被调函数初始化本身的栈
5.取出参数进行运算(并非pop)
6.恢复栈指针
7.执行ret恢复(pop)ip,此时程序转到call的下一条add esp
8.向下移动栈顶指针sp,所谓的释放局部变量。
能够看到局部变量的"释放"实际上是在主调函数中完成的,而不是在被调用函数末尾。
"释放"不是清除内存,而是修改栈指针使局部变量不能访问。