函数调用和栈的内存分配过程分析

时间:2021-02-18 01:08:06

学习程序到底怎么调用的和内存怎样分配的,其实了解函数的调用和堆栈的内存管理是很有必要的。

程序的代码是存放在代码区的,一般代码区为只读的,不可修改的,道理很简单就是程序的安全性。其他的常量什么的也有自己的内存区域, 

栈的调用过程一般是内存地址向下分配的。

首先来看一个简单的例子:VC6.0测试

函数调用和栈的内存分配过程分析// struct.cpp : Defines the entry point for the console application.
函数调用和栈的内存分配过程分析
//
函数调用和栈的内存分配过程分析

函数调用和栈的内存分配过程分析#include 
"stdafx.h"
函数调用和栈的内存分配过程分析#include 
<string.h>
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析
int compare(int a)
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
{
函数调用和栈的内存分配过程分析    
int c = 0;
函数调用和栈的内存分配过程分析    c 
= 20;
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析    
if(a>c)
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析    
{
函数调用和栈的内存分配过程分析        
return a;
函数调用和栈的内存分配过程分析    }

函数调用和栈的内存分配过程分析    
else
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析    
{
函数调用和栈的内存分配过程分析        
return c;
函数调用和栈的内存分配过程分析    }

函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析}

函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析
int main(int argc, char* argv[])
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
{
函数调用和栈的内存分配过程分析    
int i = 2;
函数调用和栈的内存分配过程分析    
函数调用和栈的内存分配过程分析    
int c = compare(i);
函数调用和栈的内存分配过程分析    printf(
"%d  ",c);
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析    
return 0;
函数调用和栈的内存分配过程分析}

函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析

 

汇编代码如下:

函数调用和栈的内存分配过程分析25:   int main(int argc, char* argv[])
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
26:   {
函数调用和栈的内存分配过程分析
00401080   push        ebp
函数调用和栈的内存分配过程分析
00401081   mov         ebp,esp
函数调用和栈的内存分配过程分析
00401083   sub         esp,48h
函数调用和栈的内存分配过程分析
00401086   push        ebx
函数调用和栈的内存分配过程分析
00401087   push        esi
函数调用和栈的内存分配过程分析
00401088   push        edi
函数调用和栈的内存分配过程分析
00401089   lea         edi,[ebp-48h]
函数调用和栈的内存分配过程分析0040108C   mov         ecx,12h
函数调用和栈的内存分配过程分析
00401091   mov         eax,0CCCCCCCCh
函数调用和栈的内存分配过程分析
00401096   rep stos    dword ptr [edi]
函数调用和栈的内存分配过程分析
27:       int i = 2;
函数调用和栈的内存分配过程分析
00401098   mov         dword ptr [ebp-4],2
函数调用和栈的内存分配过程分析
28:
函数调用和栈的内存分配过程分析
29:       int c = compare(i);
函数调用和栈的内存分配过程分析0040109F   mov         eax,dword ptr [ebp
-4]
函数调用和栈的内存分配过程分析004010A2   push        eax
函数调用和栈的内存分配过程分析004010A3   call        @ILT
+20(swap) (00401019)
函数调用和栈的内存分配过程分析004010A8   add         esp,
4
函数调用和栈的内存分配过程分析004010AB   mov         dword ptr [ebp
-8],eax
函数调用和栈的内存分配过程分析
30:       printf("%d  ",c);
函数调用和栈的内存分配过程分析004010AE   mov         ecx,dword ptr [ebp
-8]
函数调用和栈的内存分配过程分析004010B1   push        ecx
函数调用和栈的内存分配过程分析004010B2   push        offset 
string "%d  " (0042001c)
函数调用和栈的内存分配过程分析004010B7   call        printf (
00401190)
函数调用和栈的内存分配过程分析004010BC   add         esp,
8
函数调用和栈的内存分配过程分析
31:
函数调用和栈的内存分配过程分析
32:       return 0;
函数调用和栈的内存分配过程分析004010BF   xor         eax,eax
函数调用和栈的内存分配过程分析
33:   }

函数调用和栈的内存分配过程分析004010C1   pop         edi
函数调用和栈的内存分配过程分析004010C2   pop         esi
函数调用和栈的内存分配过程分析004010C3   pop         ebx
函数调用和栈的内存分配过程分析004010C4   add         esp,48h
函数调用和栈的内存分配过程分析004010C7   cmp         ebp,esp
函数调用和栈的内存分配过程分析004010C9   call        __chkesp (
00401210)
函数调用和栈的内存分配过程分析004010CE   mov         esp,ebp
函数调用和栈的内存分配过程分析004010D0   pop         ebp
函数调用和栈的内存分配过程分析004010D1   ret
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析
-----------------------------------------------------------------
函数调用和栈的内存分配过程分析
00401019   jmp         compare (00401030)
函数调用和栈的内存分配过程分析
-----------------------------------------------------------------
函数调用和栈的内存分配过程分析
函数调用和栈的内存分配过程分析   
int compare(int a)
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
8:    {
函数调用和栈的内存分配过程分析
00401030   push        ebp
函数调用和栈的内存分配过程分析
00401031   mov         ebp,esp
函数调用和栈的内存分配过程分析
00401033   sub         esp,44h
函数调用和栈的内存分配过程分析
00401036   push        ebx
函数调用和栈的内存分配过程分析
00401037   push        esi
函数调用和栈的内存分配过程分析
00401038   push        edi
函数调用和栈的内存分配过程分析
00401039   lea         edi,[ebp-44h]
函数调用和栈的内存分配过程分析0040103C   mov         ecx,11h
函数调用和栈的内存分配过程分析
00401041   mov         eax,0CCCCCCCCh
函数调用和栈的内存分配过程分析
00401046   rep stos    dword ptr [edi]
函数调用和栈的内存分配过程分析
9:        int c = 0;
函数调用和栈的内存分配过程分析
00401048   mov         dword ptr [ebp-4],0
函数调用和栈的内存分配过程分析
10:       c = 20;
函数调用和栈的内存分配过程分析0040104F   mov         dword ptr [ebp
-4],14h
函数调用和栈的内存分配过程分析
11:
函数调用和栈的内存分配过程分析
12:       if(a>c)
函数调用和栈的内存分配过程分析
00401056   mov         eax,dword ptr [ebp+8]
函数调用和栈的内存分配过程分析
00401059   cmp         eax,dword ptr [ebp-4]
函数调用和栈的内存分配过程分析0040105C   jle         compare
+33h (00401063)
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
13:       {
函数调用和栈的内存分配过程分析
14:           return a;
函数调用和栈的内存分配过程分析0040105E   mov         eax,dword ptr [ebp
+8]
函数调用和栈的内存分配过程分析
00401061   jmp         compare+36h (00401066)
函数调用和栈的内存分配过程分析
15:       }

函数调用和栈的内存分配过程分析
16:       else
函数调用和栈的内存分配过程分析函数调用和栈的内存分配过程分析
17:       {
函数调用和栈的内存分配过程分析
18:           return c;
函数调用和栈的内存分配过程分析
00401063   mov         eax,dword ptr [ebp-4]
函数调用和栈的内存分配过程分析
19:       }

函数调用和栈的内存分配过程分析
20:
函数调用和栈的内存分配过程分析
21:   }

函数调用和栈的内存分配过程分析
00401066   pop         edi
函数调用和栈的内存分配过程分析
00401067   pop         esi
函数调用和栈的内存分配过程分析
00401068   pop         ebx
函数调用和栈的内存分配过程分析
00401069   mov         esp,ebp
函数调用和栈的内存分配过程分析0040106B   pop         ebp
函数调用和栈的内存分配过程分析0040106C   ret
函数调用和栈的内存分配过程分析

 

个人总结部分如下:

1 函数返回值一般在调用函数时已经分配指向该返回值的内存地址或寄存器;

2 函数调用的栈部分是连续的,通过esp,ebp相互赋值实现。创建新函数首先会将新的esp作为新函数的ebp;(因为该原因,所以可以被利用来作缓冲区溢出)

3 函数调用需要保存此前的CPU寄存器的值,通过新创建的栈空间来保存push(value)。

4 函数调用结束前会pop(value)返回前面函数时的cpu环境,从而实现了函数的调用。

5 函数内的变量是在ebp的基础上进行内存分配的。(如果分配的内存不够用,就会出现缓冲区溢出问题)

运行时栈的转换过程截图如下:(下面的就是0x0012ff80和0x0012ff20两个函数的ebp,compare函数的最后pop就是返回前函数的ebp值)

函数调用和栈的内存分配过程分析

分析过程大家调试即可: