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

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

  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 的清理策略依实现而定。
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值