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中就是一个短期变量了,

相关推荐
dinl_vin2 小时前
FastAPI 系列(一)· 初体验——从 Spring Boot 工程师视角认识 FastAPI
后端·python·fastapi
ping某2 小时前
Nginx 内嵌 CPython 3.5→3.8 升级实录
后端
vx-程序开发2 小时前
springboot课程管理系统-计算机毕业设计源码16731
spring boot·后端·课程设计
stark张宇2 小时前
支付宝 App 支付踩坑记:x509 证书不匹配 & 应用未上线问题解决
后端·支付宝
MacroZheng2 小时前
IDEA + 阿里 Qoder = 王炸!
java·人工智能·后端
鹏程十八少3 小时前
Android 无障碍服务失效,一次AccessibilityService“离奇死亡”的完整破案实录
前端·后端·面试
_Evan_Yao3 小时前
从 select 到 epoll,再到 Agent 循环:如何用 I/O 多路复用撑起千军万马?
java·数据库·人工智能·后端
长谷深风1113 小时前
SpringBoot开发秘籍【个人八股】
java·spring boot·后端·spring·八股
IT_陈寒3 小时前
SpringBoot这个事务回滚的坑我算是踩明白了
前端·人工智能·后端