You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust调用&dyn Fn的底层原理:汇编偏移40的由来

Rust中dyn Fn()调用时汇编偏移量40的由来

问题背景

给定Rust函数:

pub fn abc(x: &dyn Fn()) {
    x()
}

使用Rust 1.63.0编译为x86-64汇编后得到:

example::abc:
        push    rax
        call    qword ptr [rsi + 40]
        pop     rax
        ret

疑问:汇编中的偏移量40是如何产生的?

核心解释

偏移量40来自Rust对trait对象(这里是dyn Fn())的底层实现机制:

  1. 胖指针的结构
    &dyn Fn()是一个胖指针,在x86-64架构下占用16字节,拆分为两个8字节部分:

    • 第一部分(对应汇编中的rdi寄存器):指向 trait 对象的数据实例
    • 第二部分(对应汇编中的rsi寄存器):指向该 trait 的虚表(vtable)
  2. vtable的布局
    Rust的vtable是包含元数据和方法指针的结构体,针对Fn() trait的vtable在1.63.0版本中的布局(按字节偏移)如下:

    • 0-7: 类型的大小(usize)
    • 8-15: 类型的对齐要求(usize)
    • 16-23: 析构函数(drop)的指针
    • 24-31: FnOnce::call_once方法的指针(因Fn继承自FnMut,FnMut继承自FnOnce,父trait方法排在前面)
    • 32-39: FnMut::call_mut方法的指针
    • 40-47: Fn::call方法的指针(也就是调用x()时实际执行的函数)
  3. 汇编中的偏移计算
    rsi指向vtable的起始地址,[rsi + 40]就是直接取vtable中偏移40字节处的Fn::call方法指针,再通过call指令执行该方法。

另外,汇编里的push rax和pop rax是为了满足x86-64 System V调用约定的栈对齐要求(调用函数前栈指针需为16字节对齐),和偏移量无直接关联。

内容的提问来源于stack exchange,提问作者radong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:09:33