csapp 第三章 3.2.2 x86-64 函数调用约定:寄存器分工与c语言转汇编学习(未完成版)

问题引入

当我在学习汇编语言,c语言代码转化成汇编代码时,了解到汇编代码需要将变量储存到寄存器,而x86-64寄存器只有稀缺的16个,这16个寄存器需要分给无限层级的函数调用,不可避免遇到深层的函数使用相同的寄存器覆盖上层函数的寄存器值,导致函数回调时原先的值已经被破坏的情况。那么是怎么处理这个问题的呢?

具体代码如下图,

是关于计算两个数的相乘结果同时用传指针的方法来获取值的一个功能。

c语言代码

c 复制代码
long mult2(long x, long y) {
    return x * y;
}

// 把乘法结果存到指定地址
void multstore(long x, long y, long *dest) {
    long t = mult2(x, y);   // 调用mult2计算
    *dest = t;              // 结果存入dest指向的内存
}

int main() {
    long result = 0;        // 初始化为0
    multstore(3, 4, &result);  // 调用:3*4=12,存入result
    // result现在是12
    return 0;
}

对应汇编代码

汇编 复制代码
# mult2函数:计算x*y
mult2:
    movq    %rdi, %rax      # x从%rdi移到%rax
    imulq   %rsi, %rax      # %rax = x * y
    ret                     # 返回,结果在%rax

# multstore函数:调用mult2,结果存到*dest
multstore:
    pushq   %rbx            # 保存%rbx的旧值到栈(callee-saved)
    movq    %rdx, %rbx      # 把dest指针存到%rbx(安全转移)
    call    mult2           # 调用mult2(x, y)
    movq    %rax, (%rbx)    # 把mult2的返回值存到*dest
    popq    %rbx            # 恢复%rbx的旧值
    ret                     # 返回main

# main函数
main:
    subq    $16, %rsp       # 给result分配栈空间
    movq    $0, 8(%rsp)     # result = 0
    
    leaq    8(%rsp), %rdx   # &result → %rdx(第3个参数)
    movl    $4, %esi        # 4 → %esi(第2个参数y)
    movl    $3, %edi        # 3 → %edi(第1个参数x)
    call    multstore       # 调用multstore
    
    movq    8(%rsp), %rax   # result的值(可选)
    addq    $16, %rsp       # 恢复栈
    xorl    %eax, %eax      # return 0
    ret

ok,首先这里multstore中 pushq %rbx 和 popq %rbx 就体现了对应的寄存器值保存处理

发现问题

解决问题

这里用实际上是将寄存器分为 caller-saved(调用者保存) / callee-saved(被调用者保存) 两种,来避免这个问题

caller-saved / callee-saved

caller-saved寄存器,调用者保存,被调用者不负责保存,适合临时短期变量

具体例子说明

图一:

这里算平均值的例子中sum和count都是短期存一下得到一个短期结果,avg也是短期结果。在调用函数call printf中不会被用到,什么叫短期和长期使用变量呢。如下图

图二:

在图二场景中,(转换成汇编代码后)如果我将i赋给一个寄存器假如是&rbx,那么在while循环中会调用另一个函数do_something,那么这个do_something函数中可能也会将一个变量储存在&rbx中,那么i原本的值可能就被这个新变量的值覆盖了,当这个do_something函数结束后,i++的时候i的值已经被覆盖不是执行do_something前的数字,那么程序就出问题了。所以就需要保存调用函数之前那个i值。(挺像并发的,记住原来的模样后再切出去)

这里的i就是一个需要长期保存的值,长期变量(因为他有可能在后面调用函数时被改)

回过头来再看图一,方案A中就是一个短期变量了,

相关推荐
星辰徐哥1 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥1 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约1 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee1 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐1 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs1 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐1 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司1 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪2 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
追逐时光者2 小时前
一个基于 .NET 与 Avalonia 构建、面向 TrinityCore 的开源 WoW 数据库编辑器
后端·.net