目录

函数的创建和销毁

函数的创建

寄存器


在编程中,函数的创建和销毁涉及函数在内存中的生命周期管理。这包括函数被定义、调用时内存的分配(创建),以及函数执行完毕后内存的回收(销毁)。理解这一过程有助于优化程序性能和避免资源泄漏。下面我将逐步解释这一概念,并提供示例。


函数的创建和销毁

注在vs编译器中越简单我们越容易观察理解  我们这里使用vs2013编译器

函数的创建和初始化

  • 栈帧的分配:每个函数调用会创建一个栈帧(Stack Frame),用于存储局部变量、参数和返回地址。栈帧的大小取决于函数内部定义的变量和参数数量。
  • 内存分配公式:设函数参数和局部变量总大小为 $s$ 字节,栈指针 $sp$ 的移动可表示为: $$sp \leftarrow sp - s$$ 这表示栈指针向下移动以分配空间。

#include<stdio.h>
#include<windows.h>
int Add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int c = 0;
    c = Add(a, b);
printf("%d", c);
system("pause");
    return 0;
}

寄存器

函数有寄存器储存 

  • eax:通常用来执行加法,函数调用的返回值一般也放在这里面
  • ebx:数据存取
  • ecx:通常用作计数器,比如for循环
  • edx:暂不清楚
  • esp:栈顶指针,指向栈的顶部
  • ebp:栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
  • edi:字符串操作时,用于存放数据源的地址
  • esi:字符串操作时,用于存放目的地址的,和edi两个经常搭配一起使用,执行字符串的复制等操作

专用词介绍

esp为栈顶指针

ebp为栈底指针

push   压栈  往栈顶放值

mov   交换

lea   加载 

sub 减法

call  调用下一条指令地址

pop 弹出指令

add  加法

打开反编代码  内存  监视调控  工具

一开始 创建的空间  esp在栈顶    ebp在栈底

push  ebp

  往esp栈顶加一个esp 栈中地址是由高地址向低地址使用

mov    ebp,esp   

把ebp移动到esp的位置  两个地址相同

sub  esp,0E4h   

把esp减0E4h 向上

  push        ebx  
   push        esi  

  push        edi

把三个寄存器往esp-0E4h压栈从而esp地址指向不断减低

lea         edi,[ebp+FFFFFF1Ch]     

把 [ebp+FFFFFF1Ch] 加载到ebp里

 mov         ecx,39h         

mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]

从edi把main空间初始化cccccccc

从 edi 开始初始化ccccccc

数值的寄存

mov         dword ptr [ebp-8],0Ah 

把0Ah放在epb-8的位置

而一个a等于10  一个int4个字节  

epb-8 往上两个字节

dword ptr [ebp-14h],14h  

dword ptr [ebp-20h],0

同理


 mov         eax,dword ptr [ebp-14h]  
push        eax  
 mov         ecx,dword ptr [ebp-8]  
 push        ecx

把[ebp-14h][ebp-8]    寄存到 eax ecx里 

 [ebp-14h] =b [ebp-8]=a

 call        008910E6  
 add         esp,8  
 mov         dword ptr [ebp-20h],eax 

call  调用下一条指令 按两次 F11进入自定义函数

此时   esp  ebp  为Add函数维护空间

 push        ebp

压栈   此时ebp压的是main函数的ebp 为的自定义函数返回时找到ebp的位置 

 push        ebp  
 mov         ebp,esp  
sub         esp,0CCh  
 push        ebx  
push        esi  
push        edi  
 lea         edi,[ebp+FFFFFF34h]  
 mov         ecx,33h  
mov         eax,0CCCCCCCCh  
 rep stos    dword ptr es:[edi]

同理   上述和main函数相同  都是为了函数初始化  而我们在用vs中烫烫就是这么出现的

mov         dword ptr [ebp-8],0 

把  0也就是z存在ebp-8里

mov         eax,dword ptr [ebp+8]

把ebp+8的值=b=20放eax里

add         eax,dword ptr [ebp+0Ch]

[ebp+0Ch]=a=20放eax里相加=30

mov         eax,dword ptr [ebp-8]

把[ebp-8]寄存到eax里  局部函数结束生命周期销毁时数值也不会被销毁 

 pop         edi  
 pop         esi  
 pop         ebx  

pop弹出  把edi esi ebx 弹出  进行回值操作
  mov         esp,ebp

 把esp的位置移动到esp来   返回有一步ebp存的地址   ebp  main


pop         ebp  

弹出  esp  ebp  z  的值此时 自定义函数 销毁生命周期结束
  ret   

返回call存下的的地址也就下一步指令  完成了函数的返回值

  mov         dword ptr [ebp-20h],eax  

把eax=20放在[ebp-20h],也就是此时值就返回了  可以打印出来

函数的销毁

销毁确保内存不被浪费,防止栈溢出或内存泄漏。在支持垃圾回收的语言中,销毁过程可能延迟,但栈帧通常是立即回收的。

在编程中,函数的创建和销毁涉及函数在内存中的生命周期管理。这包括函数被定义、调用时内存的分配(创建),以及函数执行完毕后内存的回收(销毁)。理解这一过程有助于优化程序性能和避免资源泄漏

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐