原码如下:
#include <stdio.h>
#pragma warning (disable:(4996))
int Add(int x,int y)
{
int sum = 0;
sum = x+y;
return (sum);
}
int main()
{
int a = 2;
int b = 3;
int ret = 0;
ret = Add(a,b);
return 0;
}
基本的汇编指令:
esp:esp寄存器里存储的是在调用函数之后,栈的栈顶。并且始终指向栈顶。
ebp:ebp寄存器里存储的是是栈的栈底指针,通常叫栈基址,这个是一开始进行函数调用之前,由esp传递给ebp的。(在函数调用前你可以这么理解:esp存储的是栈顶地址,也是栈底地址。)
push:压入操作,把一个32位的操作数压入堆栈中,这个操作在32位机中会使得esp被减4(字节),esp通常是指向栈顶的,这里顶部是地址小的区域,那么,压入堆栈的数据越多,esp也就越来越小
mov:数据传送。第一个参数是目的操作数,第二个参数是源操作数,就是把源操作数拷贝到目的一份。
sub:创建空间。
lea:load effective address 加载有效地址。
rep stos:重复指令
转到反汇编之后:
1.当_tmainCRTStartup 还没有调用main函数时,esp,ebp共同维持并为_tmainCRTStartup开辟一个空间,
如下图所示:
2.开始调用main函数:
汇编代码如下:
(1)执行第一条指令: push ebq//压栈,将ebp放入栈顶,而esp始终指向栈顶,如下图所示:
(2)执行第二条指令:mov ebp,esp//将esp赋予ebp,ebp和esp指向同一位置,如下图所示:
(3)执行第三条指令:sub esp,0E4h //将esp减去0E4h,0E4h是十六进制数,由于开辟的栈空间由高到低,所以esp往上走0E4h,如下图所示:
(4)执行指令:push ebx
push esi
push edi//ebx,esi,edi三个寄存器进行压栈,main空间增大,如下图所示:
(5)执行指令:lea edi,[ebp-0E4h] //[ebp-0E4h]是ebx,将ebx的地址传到edi中
mov ecx,39h //将39h传到ecx寄存器中
mov eax,0CCCCCCCCh //将0CCCCCCCCh传到eax寄存器中
rep stos dword ptr es:[edi] //将栈上[ebp-0E4h]的位置开始向高地址的内存赋值0CCCCCCCCh,次数为0x39,0CCCCCCCCh代表未初始化。
如下图所示:
以上是main函数的调用。
以下是自己写的代码,转换成汇编代码:
指令 : mov dword ptr [a],2 /*dword 双字 就是四个字节ptr pointer缩写 即指针,[]里的数据是一个地址值,这个地址指向一个双字型数据。即将地址a指向的四字节数据2移动到ebp-4*/
指令:mov dword ptr [b],3 //与上指令功能相似
指令: mov dword ptr [ret],0 //与上指令功能相似
指令:mov eax,dword ptr [b] //将变量b的值赋给eax
push eax //将eax压栈
指令:mov ecx,dword ptr [a]
push ecx
指令:call @ILT+215(_Add) (0F810DCh) //call指令下一条指令的地址
指令效果如图所示:
Add函数汇编代码如下:
指令:
push ebp //ebp压栈
mov ebp,esp //将esp传给ebp
sub esp,0CCh //给add函数开辟空间
push ebx
push esi
push edi //将ebx,esi,edi三个寄存器压栈,add函数空间增大
lea edi,[ebp-0CCh]
mov ecx,33h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi] //将从[ebp=0CCh]的地址位置开始向高地址内存空间赋值0CCCCCCCCh ,次数为33h
mov dword ptr [sum],0 //给sum赋值0
mov eax,dword ptr [x] //将x处的值传给eax
add eax,dword ptr [y]
mov dword ptr [sum],eax //将eax的值传给sum
mov eax,dword ptr [sum] 将sum的值存在寄存器eax中
指令效果如图:
出栈汇编代码:
指令:
pop edi
pop esi
pop ebx //三个寄存器出栈
mov esp,ebp //将esp栈顶下移
pop ebp //将ebp出栈,此时下面还有一个ebp
ret //回到call指令的下一条指令
add esp,8//esp向下跳两格
mov dword ptr [ret],eax //将eax的值传给ret处。
xor eax,eax //异或运算,相同返回0,相反返回1;
指令效果如下:
函数的调用过程,栈帧的创建和销毁已经完成。