3.1
传参
把[ebp-14h]这个地址的值赋给eax
把eax放到栈顶
把[ebp-8]这个空间的值赋给ecx
把ecx放到栈顶
3.2
调用add函数:
call 00C210E1
按F11,在进入函数的同时
在栈顶存储00C21450
call指令会在存储call指令下一条指令的地址
目的是在执行完call指令后能返回继续执行下一条指令
4.
进入add函数
a.
为add函数申请内存空间
把main函数的ebp放在栈顶
把esp的值赋给ebp
把esp减去0CCh,使得esp地址向上移
b.
与2.步骤相同
初始化成CCCCCCCCh
c.
此处的[ebp+8]就是ecx,即3.1传参传进来的a,值为10
[ebp+0Ch]就是[ebp+12]就是b
line 4:
把ecx的值赋给eax
line 5:
把eax和[ebp+0Ch]的值相加
line 6:
把eax的值赋给[ebp-8],即z
由此可知,3.1这一步在调用之前就进行传参,将形参b、a通过压栈传到栈顶的目的了
即:
形参不是在add函数内部创建的(并没有另外在add函数内部存储参数,而是直接利用了之前传入的参数)
这很好地解释了:
形参是实参的一份临时拷贝
以及
在传值调用时,改变形参不会影响实参
5.
返回z
line 8:
把[ebp-8]的值赋给eax
注意:eax为寄存器,不会随着函数的结束而销毁
6.1
初步清理:
pop edi
pop:弹出
意思是:把栈顶的元素弹出,然后存入edi这个寄存器中
这样栈中的元素就少了一个,esp的位置也向下移动一位
pop esi
pop ebx
同样是弹出栈顶的元素,分别存入esi、edi这两个寄存器中
6.2回收add函数的内存空间
a.
mov esp,ebp
把ebp赋给esp
b.
pop ebp
此时栈顶是main 函数的ebp
这一步是为了找到main函数的栈低
esp同时向下移动一位
这样就回到了原来的main函数
c.
此时的栈顶是call指令下一条指令的地址
ret
ret 指令执行后就回到了call指令的下一条指令处
7.
line 7:
esp+8
目的是将esp向下移动两位
将形参所占空间释放掉
line 8:
把寄存器eax的值(此时eax中寄存着add函数的返回值)赋给[ebp-20h],即c
line 9:
打印c
8.
回收main函数的内存空间
与6.2相同
不再进行解释
结语:
不由得同时感叹编程的复杂和有趣。