前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >函数战争(栈帧)之创建与销毁(c语言)(vs2022)

函数战争(栈帧)之创建与销毁(c语言)(vs2022)

作者头像
发布2024-04-30 21:09:16
940
发布2024-04-30 21:09:16
举报
文章被收录于专栏:转自CSDN转自CSDN

首先,什么是函数栈帧?

C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现过程函数调用的一种数据结构。

以问答的方式解释编译器与解释器-CSDN博客

https://blog.csdn.net/forccct/article/details/135349101?spm=1001.2014.3001.5501

函数栈帧的作用

函数栈帧是编译器用来实现函数调用的一种数据结构。在执行函数时,每个函数都会分配一个独立的栈帧,用于存储该函数的参数、局部变量、返回地址等信息。

栈帧的作用在于保存函数的运行环境,使得函数执行时可以随时访问其所需的参数和局部变量。当函数被调用时,其栈帧被推入栈中,成为当前活动的栈帧。当函数执行完毕后,其栈帧从栈中弹出,并释放相关的内存空间。

在C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。通过寄存器ebp和esp来维护当前的栈帧。

函数栈帧是编译器用来实现函数执行环境的一种数据结构,它保存了函数的参数、局部变量和返回地址等信息,使得函数可以正确地执行并保持其运行环境。

学习函数栈帧的目的

学习函数栈帧的目的在于深入理解程序的执行机制和编译器的工作原理。通过了解函数栈帧,程序员可以更好地理解函数调用时的内存布局、参数传递、局部变量管理以及异常处理等方面的知识。

此外,理解函数栈帧也有助于提高程序的性能和可维护性。例如,通过合理使用栈帧,可以避免不必要的内存分配和释放操作,提高程序的执行效率。同时,了解栈帧也有助于在调试和优化程序时更好地分析程序的运行状态和性能瓶颈。

学习函数栈帧可以帮助程序员更好地理解程序执行过程和编译器的工作原理,提高程序的性能和可维护性,并为解决复杂问题提供更有效的解决方案。

函数栈帧可以说是编程者的”内功“,修炼内功能更好的去理解和学习语

基础知识(相关的)

寄存器

eax

EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器

ebx

EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址

ecx

是计数器(counter), 是重复(rep)前缀指令和LOOP指令的内定计数器

edx

则总是被用来放整数除法产生的余数

ebp

寄存器存放当前线程的栈底指针

esp

寄存器存放当前线程的栈顶指针

  1. EAX (Accumulator Register):
    • 通常用于算术和逻辑运算。
    • 在函数调用中,它经常用来返回结果。
    • 在一些系统调用和指令中,eax 也用来传递参数。
  2. EBX (Base Register):
    • 通常用作指向数据的基址指针。
    • 在某些系统调用和指令中,ebx 也用来传递参数。
    • 在某些情况下,它也可以用作通用寄存器。
  3. ECX (Count Register):
    • 通常用作计数器,特别是在循环和字符串操作中。
    • 在某些系统调用和指令中,ecx 也用来传递参数。
  4. EDX (Data Register):
    • 通常与eax一起用于32位乘法和除法运算。
    • 在某些系统调用和指令中,edx 也用来传递参数或返回额外的结果信息。
  5. EBP (Base Pointer):
    • 在函数调用中,它通常用来指向当前函数的栈帧基址。
    • 通过ebp,函数可以方便地访问其参数和局部变量,即使栈顶指针(esp)在函数执行过程中发生变化。
  6. ESP (Stack Pointer):
    • 指向栈顶的指针。
    • 当数据被压入栈时,esp减小;当数据从栈中弹出时,esp增加(在x86体系结构中,栈是向下增长的)。
    • 通过修改esp,函数可以分配和释放栈空间。

详细见:寄存器的相关知识-CSDN博客”

https://blog.csdn.net/forccct/article/details/135316297?spm=1001.2014.3001.5501

汇编命令

汇编语言是一种低级语言,它直接与计算机的硬件和操作系统交互。汇编命令(或指令)是汇编语言中的基本单位,用于控制计算机执行特定的操作。以下是一些常见的汇编命令:

  1. 数据传送指令
    • MOV:将数据从一个位置移动到另一个位置。
    • PUSH:将数据压入栈中,同时更新栈顶指针。
    • POP:从栈顶弹出数据,同时更新栈顶指针。
  2. 算术运算指令
    • ADD:将两个数相加。
    • SUB:从第一个数中减去第二个数。
    • MULIMUL:无符号乘法和有符号乘法。
    • DIVIDIV:无符号除法和有符号除法。
  3. 逻辑运算指令
    • AND:按位与操作。
    • OR:按位或操作。
    • XOR:按位异或操作。
    • NOT:按位非操作。
  4. 控制流指令
    • JMP:无条件跳转到一个指定的地址。
    • Jcc(如 JZ, JNZ, JE, JNE 等):基于某个条件(如零标志位、符号标志位等)进行跳转。
    • CALL:调用一个子程序,保存返回地址。
    • RET:从子程序返回,恢复返回地址。
  5. 比较指令
    • CMP:比较两个操作数,设置相应的标志位。
  6. 堆栈操作指令(除了 PUSHPOP):
    • PUSHFPOPF:将标志寄存器压入栈中或从栈中弹出。
    • ENTERLEAVE:用于高级语言过程/函数的栈帧设置和清除。
  7. 输入输出指令(与硬件或操作系统交互):
    • INOUT:从端口读取数据或向端口写入数据。
  8. 其他指令
    • NOP:无操作,通常用于填充或微调代码时序。
    • HLT:停止执行并等待外部中断。
    • CLISTI:清除或设置中断标志。
    • 等等。

需要注意的是,具体的指令集依赖于特定的处理器架构(如 x86, ARM, MIPS 等),不同的架构有不同的指令集和寻址模式。上述指令主要基于 x86 架构,其他架构的指令可能会有所不同。

我们主要用到了

mov push pop sub add call jump ret

栈和栈帧

堆栈(stack)又称为堆叠,是计算机科学里最重要且最基础的数据结构之一,它按照FILO(First In Last Out,后进先出)的原则存储数据。(引用)

但是我们为了简单理解函数栈帧,我们不需要很深入的了解,就只需要明白栈帧在内存中的存在形式...

理解这个图.

下面是高地址,上面是高地址,可以理解函数栈帧中,汇编命令从高地址向低地址访问改变和操控.

这个栈,或者说这些值和其地址以这种形式存在于内存中,你访问就是内存.

推荐可以看一眼

汇编语言(不是很有必要学习,提供一个大佬的文章)

汇编语言入门教程 - 阮一峰的网络日志 (ruanyifeng.com)

https://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html

正式内容

我们以vs2022为例子

使用代码部分

int add(int x, int y) { int n = 0; n = x + y; return n; } int main() { int a = 1; int b = 2; int c = 5; c = add(a, b); printf("%d", c); return 0; }

然后是打开反汇编

寄存器部分

首先是

00007FF79D985BB0 push rbp 00007FF79D985BB2 push rdi

这两个命令是 rbp 和 rdi 入栈

00007FF79D985BB3 sub rsp,148h

申请148h字节内存

00007FF79D985BBA lea rbp,[rsp+20h] 00007FF79D985BBF lea rcx,[__0C5A5099_121@c (07FF79D992008h)]

把rsp+20h的值塞入lea中,也就是为add申请20h字节的内存

int a = 1; 00007FF79D985BCB mov dword ptr [rbp+4],1 int b = 2; 00007FF79D985BD2 mov dword ptr [rbp+24h],2 int c = 5; 00007FF79D985BD9 mov dword ptr [rbp+44h],5

分别为每个内存申请一个空间和带入数字

此时

00007FF79D985BE0 mov edx,dword ptr [rbp+24h] 00007FF79D985BE3 mov ecx,dword ptr [rbp+4] 00007FF79D985BE6 call 00007FF79D9813E3 00007FF79D985BEB mov dword ptr [rbp+44h],eax

rbp+4 是a的地址 rbp+24h是b的地址 rbp+44h是c的地址 他们并不是连续存在的

上面的寄存器edx ecx 分别记录了a的值 c的值 并且记录在上面

现在是这个情况

然后是

00007FF79D981DE0 mov qword ptr [rsp+8],rcx 00007FF79D981DE5 sub rsp,38h

录入rcx 向上推rsp 现在理解 edx就是x的值 ecx就是y的值 这里的供add使用

这里是把rcx的值放到rsp上面+8地址内 rsp再向上移动38h个字节

00007FF79D981DE9 mov rax,qword ptr [rsp+40h] 00007FF79D981DEE mov qword ptr [rsp+20h],rax

把rax移动到rsp+40h 把 rsp+20h移动到rax

00007FF79D981DE0 mov qword ptr [rsp+8],rcx 00007FF79D981DE5 sub rsp,38h unsigned char *__DebuggerLocalJMCFlag = JMC_flag; 00007FF79D981DE9 mov rax,qword ptr [rsp+40h] 00007FF79D981DEE mov qword ptr [rsp+20h],rax if (*JMC_flag && __DebuggerCurrentSteppingThreadId != 0 && __DebuggerCurrentSteppingThreadId == GetCurrentThreadId()) { 00007FF79D981DF3 mov rax,qword ptr [rsp+40h] 00007FF79D981DF8 movzx eax,byte ptr [rax] 00007FF79D981DFB test eax,eax 00007FF79D981DFD je 00007FF79D981E17 00007FF79D981DFF cmp dword ptr [00007FF79D98D94Ch],0 00007FF79D981E06 je 00007FF79D981E17 00007FF79D981E08 call qword ptr [00007FF79D991088h] 00007FF79D981E0E cmp dword ptr [00007FF79D98D94Ch],eax 00007FF79D981E14 jne 00007FF79D981E17 NopLabel: __nop(); 00007FF79D981E16 nop } } 00007FF79D981E17 add rsp,38h

经过上列过程开辟新函数的内容

00007FF79D985BE0 mov edx,dword ptr [rbp+24h] 00007FF79D985BE3 mov ecx,dword ptr [rbp+4 00007FF79D985BE6 call 00007FF79D9813E3 00007FF79D985BEB mov dword ptr [rbp+44h],eax

其中

00007FF79D985BE6 call 00007FF79D9813E3

利用call调用add函数,把rbp+24h(edx) 和 rbp+4(ecx)的值在add中调用的返回值放入到eax中

然后把eax的值放入 rbp+44h(也就是c的地址) 完成了c的赋值

00007FF79D985BFD xor eax,eax } 00007FF79D985BFF lea rsp,[rbp+0000000000000128h] 00007FF79D985C06 pop rdi 00007FF79D985C07 pop rbp 00007FF79D985C08 ret

这里是return 0;后面的

大致计算销毁占用的内存 然后返回系统

然后结束

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 首先,什么是函数栈帧?
    • 函数栈帧的作用
      • 学习函数栈帧的目的
      • 基础知识(相关的)
        • 寄存器
          • 汇编命令
            • 栈和栈帧
              • 汇编语言(不是很有必要学习,提供一个大佬的文章)
              • 正式内容
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
              http://www.vxiaotou.com