一、汇编分为两种:
- inter x86 ==> window环境下(我们这次主要考虑此环境下)
- AT&T ==> linux环境下
二、汇编指令
想要看懂汇编,我们首先要了解这几个简单的指令
1.mov 赋值
例如:mov, dword ptr[ebp(栈底指针)-4(偏移量)] (位置), 0ah(值);
2.lea 移地址
例如:lea,eax ,[ebp-4];
3.push 压栈
例如:push 0ah;
4.pop 出栈 将栈顶元素的值放入eax寄存器中;
例如:pop eax==> eax = pop();
5.add +=
例如:add eax ,0ah ==> eax+=0ah;
6.sub -=
例如: sub eax,0ah==> eax-=0ah;
7.call 调用函数的指令
(1)压入下一行指令地址
(2)jmp到被调用方函数;
8.ret 返回值指令
三、寄存器
- eax ebx ecx edx 存数据
- ebp 栈底指针寄存器 (存放调用方栈底指针地址)
- esp 栈顶指针寄存器
- pc 下一条指令寄存器
四、函数堆栈调用的步骤
- 形参初始化;
- 压入下一行指令地址;
- 压入调用方栈底指针寄存器的值;
- 移动ebp到被调用方栈底;
- 开辟局部变量所要的栈帧并初始化为cccccccc;
五、函数调用约定
1、定义:
函数的调用方和被调用方对于函数如何调用需要有一个明确的约定,只用双方都遵守同样的约定,函数才能被正确的调用,这样的约定称为调用约定也叫调用惯例;
2.约定内容
- 函数符号的生成
- 形参的入栈顺序,(从右向左)
- 形参的开辟和清理方式;
3.常见的调用约定
1. _cdecl C标准的调用约定
作用:调用方开辟形参并清理
生成的函数符号为:?函数名@@YA返回值类型 参数类型 参数类型@Z
2._stdcall Windows的调用约定
作用:形参由调用方开辟,被调用方清理
生成的函数符号为:?函数名@@YG返回值类型 参数类型 参数类型@Z
3._fastcall 快速调用约定
作用:最多使用两个寄存器来带入实参,其他参数和--stdcall的处理方式一样
生成的函数符号为:?函数名@@YI返回值类型 参数类型 参数类型 @Z
4._thiscall 成员方法的调用约定
六、函数的返回值
- 非类类型(例如:long、int、double等)
- 0 < x <= 4 一个寄存器带出
- 4 < x <= 8 两个寄存器(比如说eax和edx)
- x > 8 临时量带出来的
- 类类型 (例如:class) 由临时对象将值带出来,在内存中存放。
ps:不要返回局部变量的地址,清栈后数据还存在,只不过告诉系统此区域可以再次被分配。
七、大家知道这5个问题的答案吗?
1.形参开辟内存吗?谁开辟?
答: 开辟;由调用方(常见的如main)。
2.形参的入栈顺序是什么?
答:自右向左;实参与形参匹配是从左向右。
3.返回值是谁带出来的?
答:寄存器(只能存放4位)带出来的。
4.被调用方被调用后,咱们怎么知道回归到哪里?
答:调用栈底指针的地址保存到被调用方栈底指针。
5.函数调用完,它的下一条指令是怎么拿出来的?
答:调用时,将下一行指令的地址进行压栈处理,清栈过程中又放在了下一行指令寄存器中了。
最后用代码简单给大家看一下这个过程:
#include <stdio.h>
int sum(int a,int b)
{
int tmp;
tmp = a + b;
return tmp;
}
int main()
{
printf("%d\n",sum(10,20));
return 0;
}
反汇编结果如下:
{
00131A20 push ebp
00131A21 mov ebp,esp
00131A23 sub esp,0C0h
00131A29 push ebx
00131A2A push esi
00131A2B push edi
00131A2C lea edi,[ebp-0C0h]
00131A32 mov ecx,30h
int main()
{
00131A37 mov eax,0CCCCCCCCh
00131A3C rep stos dword ptr es:[edi]
printf("%d\n",sum(10,20));
00131A3E push 14h
00131A40 push 0Ah
00131A42 call sum (013105Fh)
00131A47 add esp,8
00131A4A mov esi,esp
00131A4C push eax
00131A4D push 1358A8h
00131A52 call dword ptr ds:[1392B8h]
00131A58 add esp,8
00131A5B cmp esi,esp
00131A5D call __RTC_CheckEsp (013113Bh)
return 0;
00131A62 xor eax,eax
}
00131A64 pop edi
00131A65 pop esi
00131A66 pop ebx
00131A67 add esp,0C0h
00131A6D cmp ebp,esp
00131A6F call __RTC_CheckEsp (013113Bh)
00131A74 mov esp,ebp
00131A76 pop ebp
00131A77 ret