5 c++函数堆栈调用

本文详细讨论了C++函数调用的过程,包括形参内存的分配、函数调用的回退、返回值的传递方式,以及不同调用约定的规则。重点解释了实参的自右向左入栈顺序,以支持可变参数,并阐述了调用方和被调用方在内存管理和栈操作上的责任。此外,还介绍了函数返回值的处理和内存回收机制。
摘要由CSDN通过智能技术生成
#include<stdio.h>

int Sum(int left,int right)
{
    int tmp = 0;
    tmp = left + right
    return tmp;
}

int main()
{
    int a = 10;
    int b = 20;
    int rt;
    rt = Sum(a,b);
    printf("rt:%d\n",rt);
    return 0;
}

问题:函数和函数调用过程中

1.形参开不开辟内存?如果开辟,是调用方开辟,还是被调用方开辟?

​ 实参的传递过程中,形参开辟内存,是由调用方开辟的

2.函数调用完成,怎么回退到调用方?

3.函数调用完成,怎么接着调用方继续指令?

4.函数返回值怎么返回到调用方的?

问题:函数调动第一步做什么事?

​ 实参传递(自右向左传递)

ret:

1.pop 下一行指令寄存器

​ 下一行指令寄存器 = 0040109A

问题:实参的入栈顺序为什么是自右向左?

如果自右向左的入栈,是能支持可变参参数

如果自左向右的入栈,不能支持可变参参数

因为c、c++语言是能够支持可变参参数的,所以入栈顺序都是自右向左的

问题:下一行指令地址入栈的目的是什么?

主要是为了保证调用方调用被调用方函数,被调用方函数清栈完成后能沿着调用方的下一行指令继续执行

问题:开栈的过程

1.压入实参,开辟形参并赋值

2.压入下一行指令地址,方便被调用方函数处理完能沿着调用方下一行指令继续执行

3.压入调用方栈底地址,方便被调用方函数处理完成能回退到调用方

4.预留被调用方函数的活动空间并作cccc cccc的初始化

问题:清栈的过程

1.清理被调用方函数预留的活动空间

2.出栈 ebp

​ ebp回退到被调用方栈帧上

3.出栈 下一行指令寄存器

​ 函数调用完成,能沿着下一行指令继续执行

4.清理形参

函数返回值(前提 : 非类类型的返回值规则)

(<=4) eax

(<=8 && >4) eax edx

(>8) 临时量带出 eax保存临时量的地址

函数返回值 不能返回局部变量的地址

#include<stdio.h>

int* getValue()
{
    int tmp = 100;
    return &tmp;
}

void fun()
{}

int main()
{
    int *p = NULL;
    p = getValue();
    printf("*p:%d\n",*p);
    return 0;
}

内存的回收 该内存可以被重新分配

当函数调用完成 栈帧清理 局部变量也会被清理

1.调用约定

_cdecl c标准调用约定

_stdcall window标准调用约定

_fastcall 快速调用约定

符号解析

​ 符号引用的地方找到同名符号定义的地方

不同的调用约定

1.函数符号的生成规则

2.实参的入栈顺序 自右向左

3.形参的开辟和清理

_cdecl 形参 调用方开辟 调用方清理

_stdcall 调用方开辟 被调用方清理

_fastcall 形参 前两个 寄存器直接带入 没有形参开辟

​ 后面 处理方式和_stdcall一样

总结

1.虚拟地址空间 高

2.编译链接运行原理 高

3.函数堆栈调用 低

4.函数返回值 + 类类型返回值 中

1.虚拟地址空间 高

2.编译链接运行原理 高

3.函数堆栈调用 低

4.函数返回值 + 类类型返回值 中

5.调用约定 低

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值