1.给函数传递参数
/****************************************************************/
#include<stdio.h> int Add(int x, int y) { int sum; sum = x + y ; return sum; } int main() { int z; z = Add(1, 2); printf( "z = %d\n", z); } /**************************************************************/ 013F182E 6A 02 push 2 013F1830 6A 01 push 1 013F1832 E8 20 FB FF FF call 013F1357 013F1837 83 C4 08 add esp,8 /***************************************************************/ c语言的参数传递是从右到左的
在执行 z = Add(1, 2);的时候
先push了2,esp = 0028F89C
然后push了1,esp = 0028F898
最后call了01341357 esp = 0028F894
0028F894 中保存的地址是函数的返回地址37 18 3f 01,也就是013f1837
01341357 是一个跳转地址,jmp 013F16D0
跳转至 函数的入口地址 013F16D0
2.函数获取参数
/**************************************************************/
#include<stdio.h> int Add(int x, int y) { int sum; sum = x + y ; return sum; } int main() { int z; z = Add(1, 2); printf( "z = %d\n", z); } /**************************************************************/
在函数执行之前,首先push了两个参数,
然后call到了跳转语句,每次esp-4
所以1的存储地址就是esp+4,2的存储地址就是esp+8
但是由于ESP随栈的变化而变化,所以为了计算简便,可以将该值存储到另一个寄存器,如EBP
那么刚才的两个地址就是EBP+4和EBP+8了
不过由于EBP本身是有值的,如果直接赋值修改它,那么当需要使用EBP的原值得时候,就没办法了
例如函数A调用后返回,如果不还原EBP,函数B用EBP作为基点就会出错,因此需要一个保存和灰度EBP值得过程,
下面的代码完成了这一过程,将EBP压栈,最后pop出来,赋值给ebp,从而还原
push ebp
...
pop ebp
所以在函数开始的地方存在如下代码:
push ebp //将ebp压栈
mov ebp,esp //将esp的值给ebp
因为在栈里又压入了ebp的缘故,所以esp将再减少4字节
此时再计算参数1和2的存储地址,存储1的地址是ebp+8,存储2的地址是ebp+0ch(12)
/**********************************************************************/
sum = x + y; 013F16EE 8B 45 08 mov eax,dword ptr [ebp+8] 013F16F1 03 45 0C add eax,dword ptr [ebp+0Ch] /**********************************************************************/ 注释: mov 将ebp + 8的值给eax,ebp + 8是1,也就是把1给eax 然后ebp + 0ch的值加上eax的值,ebp+0ch的值是2,eax的值是1,1+2 = 3,将结果保存在eax中
|