返回

函数调用栈:理解幕后机制

IOS

函数调用是程序执行的关键部分,它允许代码模块化的重用和组织。理解函数调用栈对于深入了解程序执行的幕后机制至关重要。在本文中,我们将探讨 ARM64 架构下函数调用栈的运作方式,重点关注 LR(链接寄存器)、FP(帧指针)和栈指针的关键作用。

函数调用栈概览

函数调用栈是一个数据结构,它记录了当前正在执行的函数及其调用关系。每个函数调用都会在栈上创建一个新的栈帧,其中包含该函数的局部变量、参数和返回地址。当函数返回时,其栈帧将被弹出,返回地址将被用来恢复调用函数的执行。

关键寄存器

在 ARM64 架构中,以下寄存器在函数调用栈的管理中扮演着至关重要的角色:

  • LR(链接寄存器): 存储着当前函数返回后的指令地址。
  • FP(帧指针): 指向当前函数栈帧的基地址。
  • 栈指针: 指向栈顶的地址。

函数调用过程

当一个函数被调用时,以下步骤将按顺序执行:

  1. 压栈参数和局部变量: 调用函数的参数和局部变量被压入栈中。
  2. 更新栈指针: 栈指针被减小以指向栈的新顶部。
  3. 保存 FP: 当前 FP 值被压入栈中。
  4. 更新 FP: FP 被更新为指向当前栈帧基地址。
  5. 保存 LR: 当前 LR 值被压入栈中。
  6. 更新 LR: LR 被更新为指向调用函数的返回地址。
  7. 跳转到目标函数: 程序跳转到目标函数的入口点。

函数返回过程

当函数返回时,以下步骤将按顺序执行:

  1. 恢复 LR: 栈顶的值被弹出并存储在 LR 中。
  2. 恢复 FP: 栈顶的值被弹出并存储在 FP 中。
  3. 恢复栈指针: 栈指针被增加以指向调用函数的栈帧。
  4. 跳转到返回地址: 程序跳转到 LR 中指定的返回地址。

示例

考虑以下函数调用示例:

void func1() {
  int a = 10;
  func2();
}

void func2() {
  int b = 20;
}

func1() 被调用时,以下栈帧将被创建:

| FP -> | func1() 的局部变量和参数 |
|   | LR -> | func1() 返回后的指令地址 |

func2() 被调用时,以下栈帧将被创建:

| FP -> | func2() 的局部变量和参数 |
|   | LR -> | func2() 返回后的指令地址 |

func2() 返回时,func1() 的栈帧将被恢复,func1() 将从其返回地址继续执行。

结论

理解函数调用栈是理解程序执行机制的关键。通过掌握关键寄存器 LR、FP 和栈指针的作用,您可以深入了解函数调用和返回过程背后的幕后机制。无论您是经验丰富的开发者还是初学者,掌握函数调用栈的知识将使您对程序执行有更全面的了解。