news 2026/4/14 15:07:00

过程调用的代码流程涉及多个关键步骤,确保程序能正确传递参数、执行被调用函数并安全返回

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
过程调用的代码流程涉及多个关键步骤,确保程序能正确传递参数、执行被调用函数并安全返回

过程调用的代码流程涉及多个关键步骤,确保程序能正确传递参数、执行被调用函数并安全返回。其典型流程如下:

  1. 参数传递与调用准备(Caller 侧)

    • 计算并压入实际参数到运行时栈。
    • 保存当前栈指针(SP),用于维护调用者栈帧。
    • 记录参数个数(某些语言或调用约定中需要)。
    • 将返回地址(当前指令的下一条)压栈或存入特定寄存器。
    • 执行JSR(Jump to Subroutine)指令跳转到被调用过程。
  2. 进入被调用过程(Callee 侧)

    • 保存旧的栈基址指针(通常称为 FP 或 BP)。
    • 建立新的栈帧:设置新的 SP 和 FP,构成活动记录(Activation Record)。
    • 分配局部变量所需空间。
    • 可选:保存某些寄存器内容(如临时变量使用的寄存器)。
  3. 执行过程体

    • 执行函数内部语句,可能包括表达式计算、控制流、递归调用等。
    • 使用中间代码(如四元式)进行表示和优化。
  4. 过程返回(Return)

    • 将返回值(如有)存入约定位置(寄存器或栈)。
    • 恢复调用者的栈指针 SP 和基址指针 FP。
    • 获取返回地址并跳转回调用点。
    • 清理栈中参数(由调用者或被调用者完成,取决于调用约定)。

在编译过程中,中间代码优化目标代码生成是后端的关键阶段:

  • 中间代码优化

    • 输入是中间表示(如四元式(op, arg1, arg2, result))。
    • 进行等价变换以提升效率,例如常量折叠、公共子表达式消除、循环不变代码外提、死代码删除等。
    • 目标是在不改变程序语义的前提下减少运行时间和空间开销。
  • 目标代码生成

    • 由代码生成器将优化后的中间代码转换为具体机器的汇编或机器码。
    • 需处理寄存器分配、指令选择、寻址模式匹配等问题。
    • 四元式结构因其接近三地址码,便于映射到目标指令。
      常见的过程调用约定(Calling Convention)定义了函数调用时参数如何传递、栈由谁清理、哪些寄存器需保存等规则。不同平台和编译器使用不同的调用约定,尤其在C/C++中较为显著。以下是几种典型的调用约定及其在参数清理寄存器使用上的主要区别:

1.cdecl(C Declaration)

  • 平台/语言:x86 架构下 GCC 和 MSVC 默认的 C 语言调用约定。
  • 参数传递顺序:从右到左压入栈。
  • 栈清理方调用者(Caller)负责清理栈空间。
  • 寄存器使用
    • EAX,ECX,EDX:调用者保存(caller-saved),被调用函数可自由使用。
    • 其他通用寄存器(如EBX,ESI,EDI)为被调用者保存(callee-saved),若使用需先压栈。
  • 用途:支持可变参数函数(如printf),因为只有调用者知道传了多少参数。

2.stdcall(Standard Call)

  • 平台:Windows API 常用。
  • 参数传递顺序:从右到左压栈。
  • 栈清理方被调用者(Callee)ret n指令中自动弹出参数。
  • 寄存器使用
    • 类似 cdecl,EAX,ECX,EDX为 caller-saved。
    • 其余为 callee-saved。
  • 限制:不适用于变参函数(被调用者无法预知参数个数)。

3.fastcall

  • 目的:提高性能,尽可能通过寄存器传参。
  • 参数传递方式
    • 前两个双字(DWORD)大小的参数通过寄存器传递(通常是ECXEDX)。
    • 剩余参数从右到左压栈。
  • 栈清理方被调用者(Callee)清理栈上参数部分。
  • 寄存器使用
    • ECX,EDX用于传参,属于 callee-saved 的一部分。
    • EAX,EDX也常用于返回值(EAX返回整型,EDX:EAX返回64位值)。
  • 优点:减少内存访问,提升速度。

4.thiscall(C++ 成员函数专用)

  • 平台:Microsoft Visual C++ 使用。
  • 隐含参数this:通过寄存器(ECX)传递。
  • 参数传递:其余参数从右到左压栈。
  • 栈清理方:对于固定参数,由被调用者清理;变参则由调用者清理。
  • 仅用于类成员函数调用

5.System V AMD64 ABI(Unix-like 系统 x86-64)

  • 主流标准:Linux、macOS 等 64 位系统默认。
  • 参数传递
    • 前六个整型/指针参数依次使用寄存器:RDI,RSI,RDX,RCX,R8,R9
    • 前八个浮点参数使用XMM0–XMM7
    • 超出部分通过栈传递。
  • 栈清理方调用者清理栈。
  • 寄存器分类
    • caller-saved:RAX,RCX,RDX,R8–R11
    • callee-saved:RBX,RBP,R12–R15,RSP

总结对比表:

调用约定参数传递顺序栈清理方寄存器传参支持变参典型用途
cdecl右→左CallerC 函数(x86)
stdcall右→左CalleeWindows API
fastcall右→左 + 寄存器Callee是(前两个)性能敏感函数
thiscall右→左Callee*ECX (this)否/是C++ 非静态成员函数
System V x64寄存器优先Caller是(最多6个整型)Linux/macOS 64位程序

*注:thiscall 的清理策略依实现而定。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 5:48:25

嵌入式知识---74LS138

1. 一句话概括它是什么74LS138 是一个“3线-8线译码器”。 它的核心功能是:根据你输入的3位二进制地址码,在8个输出通道中,选通唯一的一个。简单比喻:它就像一个 “智能的8路选线开关”。你告诉它一个0到7的编号(比如“…

作者头像 李华
网站建设 2026/4/15 7:19:58

Git下载大文件仓库失败?配置LFS解决PyTorch数据集问题

Git下载大文件仓库失败?配置LFS解决PyTorch数据集问题 在深度学习项目开发中,你是否曾遇到这样的场景:满怀期待地执行 git clone https://github.com/someuser/pytorch-models.git,结果几分钟后终端报错——“fatal: the remote e…

作者头像 李华
网站建设 2026/4/10 0:15:34

Comsol与Matlab联合计算PPLN铌酸锂波导倍频效率转换——大信号模型探索

Comsol和matlab联合计算PPLN铌酸锂波导倍频效率转换。 大信号模型。最近在研究PPLN铌酸锂波导倍频效率转换的问题,发现使用Comsol和Matlab联合计算是个很不错的方法,尤其是基于大信号模型来开展工作。下面就来跟大家分享一下我在这个过程中的一些经验和心…

作者头像 李华
网站建设 2026/4/15 7:19:33

探索增强型 PLC:国产芯片带来的全新体验

增强型PLC采用国产芯片,解决了进口芯片短缺价格高的问题,性能上比原装效果好,支持以太网的各种应用,总线控制伺服电机,模拟量采集,10路高速脉冲每轴200k频率,称重功能,RS232和RS485&…

作者头像 李华
网站建设 2026/4/15 7:19:04

YOLOv11与其他版本对比:速度与精度权衡分析

YOLOv11与其他版本对比:速度与精度权衡分析 在智能监控、自动驾驶和工业质检等现实场景中,目标检测的“快”与“准”始终是一对难以调和的矛盾。既要实时响应——比如每秒处理数十帧视频流,又要精准识别小尺寸目标,如远处的行人或…

作者头像 李华