线索栏

  1. 核心指令:过程调用中,哪两条指令专门负责“控制转移”?call和 ret指令各自完成了什么核心操作?
  2. 返回地址:什么是“返回地址”?它被存储在何处?为什么必须保存它?
  3. 调用类型:call指令的目标地址有哪两种指定方式?(直接与间接)
  4. 执行追踪:如何追踪一个嵌套过程调用(如 main -> top -> leaf)中,控制流的完整路径以及栈和寄存器的状态变化?
  5. 栈的作用:为什么说栈的“后进先出”(LIFO)特性天然适用于管理过程调用链?

笔记栏

1. 控制转移的核心指令

为了实现过程调用,x86-64提供了 call和 ret指令:

call指令

1)行为

将返回地址(即紧随该 call指令之后的下一条指令的地址)压入栈,然后将程序计数器 (PC/%rip) 设置为目标过程的起始地址,从而跳转到被调用过程。

2)格式

(1)call Label(直接调用,目标为标号)
(2)call *Operand(间接调用,目标为寄存器或内存中的地址)

ret指令

行为:从栈顶弹出返回地址,并将程序计数器 (PC) 设置为此地址,从而返回到调用者。

2. 图示解析:call与 ret的协作(图3-26)

在这里插入图片描述

以 main函数调用 multstore为例:
(1)调用前:%rsp指向栈顶,%rip指向 main中的 call指令。
(2)执行 call:返回地址 (0x400568) 被压栈,%rip跳转到 multstore的起始地址 (0x400540)。%rsp减小(栈增长)。
(3)执行过程:multstore函数执行。
(4)执行 ret:从栈顶弹出地址 (0x400568) 到 %rip,控制流返回 main函数。%rsp增加(栈收缩)。

3. 嵌套调用示例详解(图3-27,函数 leaf, top, main)

在这里插入图片描述
在这里插入图片描述

此例清晰地展示了控制流和栈状态在嵌套调用中的变化。

1)C语言逻辑

main调用 top(100),top内部调用 leaf(95)。leaf返回 97,top返回 194。

2)汇编执行追踪(结合表格)

标号 PC 指令 关键状态与行为
M1 0x40055b callq top 调用 top。将返回地址 0x400560压栈。栈指针 %rsp从 0x7fffffffe820减至 0x7fffffffe818。
T1 0x400545 sub $0x5, %rdi 进入 top,计算 x-5(100-5=95)。
T2 0x400549 callq leaf 调用 leaf。将返回地址 0x40054e压栈。%rsp减至 0x7fffffffe810。
L1 0x400540 lea 0x2(%rdi),%rax 进入 leaf,计算返回值 95+2=97存于 %rax。
L2 0x400544 retq 从 leaf返回。从栈顶弹出 0x40054e到 PC。%rsp增至 0x7fffffffe818。控制流回到 top的 T3。
T3 0x40054e add %rax,%rax 继续 top,计算 97 * 2=194存于 %rax。
T4 0x400551 retq 从 top返回。从栈顶弹出 0x400560到 PC。%rsp增至 0x7fffffffe820。控制流回到 main的 M2。
M2 0x400560 mov %rax,%rdx 继续 main,使用返回值。

4. 练习题3.32 解答(first与 last函数)

在这里插入图片描述

C逻辑:main调用 first(10),first内部调用 last(x-1, x+1)即 last(9, 11)。last返回 9 * 11=99,first返回 99。
在这里插入图片描述


总结栏

本节深入剖析了过程调用中“控制转移”的底层硬件机制,揭示了 call和 ret指令与运行时栈的精妙配合。

  1. 核心机制:call指令执行“压栈地址+跳转”,ret指令执行“弹栈地址+跳转”。这一压一弹,完美实现了“跳走后还能记得回来”。
  2. 栈的关键角色:运行时栈是存储返回地址的“记事本”。其后进先出 (LIFO)​特性保证了在嵌套调用中,返回顺序与调用顺序严格相反,总能回到正确的位置。
  3. 状态追踪:理解过程调用的核心是追踪两个状态:
    (1)控制流 (PC/%rip):通过 call和 ret在代码段中跳转。
    (2)栈指针 (%rsp):通过压栈和弹栈在栈空间中上下移动,管理返回地址链。
  4. 从抽象到具体:高级语言中简单的函数调用,在机器级被分解为精确的指令序列和状态变化。通过分析具体例子(如图3-27和练习题3.32)中的每一步,可以彻底理解这一转换过程。

最终启示:call/ret与栈的配合,是计算机系统实现“过程”这一强大抽象的基础。它不仅解决了控制转移问题,其建立的栈框架还为后续解决“数据传递”和“内存分配”问题提供了舞台。这是理解后续章节(如栈帧、局部变量)的基石。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐