从汇编的角度出发
int Add(int x,int y)
{
int sum = 0;
sum = x + y;
return sum;
}
int main ()
{
int a = 10;
int b = 12;
int ret = 0;
ret = Add(a,b);
return 0;
}
我们写了一段简单的函数来分析栈的调用,首先在我们从汇编代码入手来观察之前,我们先要了解一些简单的汇编指令和寄存器的意思
-
esp ,栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
-
ebp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部
-
eax 是”累加器”(accumulator), 它是很多加法乘法指令的缺省寄存器。
-
ebx 是”基地址”(base)寄存器, 在内存寻址时存放基地址
-
ecx 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器
-
**edx **则总是被用来放整数除法产生的余数。
-
esi/edi分别叫做”源/目标索引寄存器”(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.
简单的汇编指令:
mov:数据传送指令,也是最基本的编程指令,用于将一个数据从源地址传送到目标地址
sub:减法指令
lea:取偏移地址
push:实现压入操作的指令是PUSH指令
pop:实现弹出操作的指令
call:用于保存当前指令的下一条指令并跳转到目标函数
内存布局
这里我画了一张内存布局图,看出栈是从高地址向低地址走向,空间大小有限,这里不多做说明
汇编代码
main的反汇编代码
int main()
{
00271400 push ebp
00271401 mov ebp,esp
00271403 sub esp,0E4h
00271409 push ebx
0027140A push esi
0027140B push edi
0027140C lea edi,[ebp-0E4h]
00271412 mov ecx,39h
00271417 mov eax,0CCCCCCCCh
0027141C rep stos dword ptr es:[edi]
int a = 10;
0027141E mov dword ptr [a],0Ah
int b = 20;
00271425 mov dword ptr [b],14h
int sum = Add(a, b);
0027142C mov eax,dword ptr [b]
0027142F push eax
00271430 mov ecx,dword ptr [a]
00271433 push ecx
00271434 call Add (02711DBh)
00271439 add esp,8
0027143C mov dword ptr [sum],eax
return 0;
0027143F xor eax,eax
}
00271441 pop edi
00271442 pop esi
00271443 pop ebx
00271444 add esp,0E4h
0027144A cmp ebp,esp
0027144C call __RTC_CheckEsp (0271136h)
00271451 mov esp,ebp
00271453 pop ebp
00271454 ret
Add的反汇编代码
int Add(int x, int y)
{
002713C0 push ebp
002713C1 mov ebp,esp
002713C3 sub esp,0CCh
002713C9 push ebx
002713CA push esi
002713CB push edi
002713CC lea edi,[ebp-0CCh]
002713D2 mov ecx,33h
002713D7 mov eax,0CCCCCCCCh
002713DC rep stos dword ptr es:[edi]
int sum = 0;
002713DE mov dword ptr [sum],0
sum = x + y;
002713E5 mov eax,dword ptr [x]
002713E8 add eax,dword ptr [y]
002713EB mov dword ptr [sum],eax
return sum;
002713EE mov eax,dword ptr [sum]
}
002713F1 pop edi
002713F2 pop esi
002713F3 pop ebx
002713F4 mov esp,ebp
002713F6 pop ebp
002713F7 ret
画图分析
总结
形参由调用方在栈上开辟,入栈顺序为从右至左
被调用方返回值的带出(非类类型):
0-4字节:eax寄存器
4-8字节:edx、eax寄存器
8字节以上:临时量带出来
被调用方保存着调用方的栈底地址,因此调用完成后可以回到调用前
形参压栈完成后,保存着下一行指令的地址,因此可以沿着调用点继续往下执行