rbpf虚拟机-call指令

简介: 本文重点介绍 RBPF(eBPF 的一种变体)虚拟机中 `call` 指令的作用与使用方式。学习 RBPF 虚拟机的目的在于理解 Solana 合约的执行方式,因为 Solana 所使用的 RBPF 是在该虚拟机的基础上进行了功能扩展。

Welcome to Code Block's blog

本篇文章主要介绍了
[rbpf虚拟机-call指令]
❤博主广交技术好友,喜欢我的文章的可以关注一下❤

一、概述

本文重点介绍 RBPF(eBPF 的一种变体)虚拟机中 call 指令的作用与使用方式。

学习 RBPF 虚拟机的目的在于理解 Solana 合约的执行方式,因为 Solana 所使用的 RBPF 是在该虚拟机的基础上进行了功能扩展。

背景知识

在虚拟机的机器指令执行过程中,某些复杂功能(如获取当前时间、生成随机数等)无法通过基础计算功能实现,这时就需要调用自定义的辅助函数来拓展虚拟机的功能。

call 指令的格式如下:

call <key>

二、call 指令的主要方法

2.1 注册辅助函数

要使用辅助函数,首先需要对其进行注册。注册的过程是向 helpers 中添加辅助函数的实现,代码如下:

pub fn register_helper(&mut self, key: u32, function: Helper) -> Result<(), Error> {
     
    self.helpers.insert(key, function); // 将辅助函数以 `key-value` 的形式存入 `helpers`
    Ok(())
}

说明

  1. 方法会在实际使用前进行注册。
  2. 辅助函数的名称(或标识)会通过 key 被存储,并在执行 execute_program 方法时通过 key 被调用。

2.2 执行辅助函数

在虚拟机的 execute_program 方法中,当遇到 call 指令时,会调用如下处理逻辑:

ebpf::CALL => {
     
    if let Some(function) = helpers.get(&(insn.imm as u32)) {
      
        // 根据指令中的 `key` (`insn.imm`) 查找对应的辅助函数
        reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]); 
        // 调用辅助函数,并将寄存器 r1 - r5 的值作为参数传入,
        // 将返回值存入寄存器 r0
    } else {
     
        Err(Error::new(
            ErrorKind::Other,
            format!("Error: unknown helper function (id: {:#x})", insn.imm as u32),
        ))?;
    }
}

说明

  1. 如果找到与 key 匹配的辅助函数,则会传入 r1r5 五个寄存器的值作为参数进行调用。
  2. 调用结果会存储在 r0寄存器中。
  3. 如果未找到对应的辅助函数,则会返回错误提示。

三、完整代码示例与详解

3.1 示例辅助函数

以下是一个辅助函数 memfrob 的实现,功能是将指针指向的内存中每位与 0b101010 做异或运算:

#[allow(unused_variables)]
pub fn memfrob(ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
     
    for i in 0..len {
     
        unsafe {
     
            let p = (ptr + i) as *mut u8; // 将指针偏移至当前操作地址
            *p ^= 0b101010; // 按位异或操作
        }
    }
    0 // 返回固定值(实际业务逻辑可能不同)
}

3.2 测试虚拟机的 call 指令

以下是一段测试代码,验证带有 call 指令的程序在 RBPF 虚拟机中的执行效果:

测试代码

#[test]
fn test_vm_call_memfrob() {
     
    // 汇编程序中有 call 指令,编号为 1
    let prog = assemble(
        "
        mov r6, r1
        add r1, 2
        mov r2, 4
        call 1       // 调用编号为 1 的辅助函数
        ldxdw r0, [r6]
        be64 r0
        exit
        ",
    )
    .unwrap();

    // 定义测试时使用的内存
    let mem = &mut [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];

    // 创建虚拟机并加载程序
    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();

    // 注册辅助函数,辅助函数 key 为 1,指向 memfrob
    vm.register_helper(1, helpers::memfrob).unwrap();

    // 执行虚拟机程序,并验证返回结果
    assert_eq!(vm.execute_program(mem).unwrap(), 0x102292e2f2c0708);
}

代码解析

  1. 汇编程序解析
    mov r6, r1:将 r1 的值移动到 r6
    add r1, 2:将寄存器 r1 的值加 2。
    mov r2, 4:将值 4 写入寄存器 r2
    call 1:调用编号为 1 的辅助函数(即 memfrob)。
    ldxdw r0, [r6]:从 r6 指向的内存地址加载 64 位数据到 r0
    be64 r0:执行特定操作(分支或跳转),依赖于架构实现。
    exit:退出程序。

  2. 关键步骤
    vm.register_helper(1, helpers::memfrob):将 memfrob 函数注册到虚拟机,编号为 1,以供汇编程序中的 call 1 调用。
    vm.execute_program(mem):加载并执行虚拟机程序。
    assert_eq!(...):验证虚拟机程序的执行结果是否符合预期。


四、总结

  1. call 指令的作用
    call 指令用于在程序中调用注册过的辅助函数,拓展虚拟机的功能。
    • 这使得虚拟机能够处理复杂逻辑,如内存操作、时间获取、随机数生成等。

  2. 注册与调用过程
    • 辅助函数需提前通过 register_helper 方法注册,并与唯一的 key(通常为 u32)绑定。
    • 在汇编程序中,通过 call <key> 指令调用辅助函数,虚拟机会根据 key 查找对应的函数并执行。

  3. 代码结构
    register_helper:用于注册辅助函数。
    execute_program:虚拟机程序执行的核心,包含 call 指令的分发逻辑。
    • 示例程序展示了虚拟机如何使用注册的辅助函数,以及如何验证执行结果。

代码来源:rbpf虚拟机
鸣谢: qmonnet 提供的开源代码.

当然,我也会将带有中文注释和自己理解的一些代码上传的我的github页面,感兴趣的朋友可以进行clone查看.

我的GitHub:forked


感谢您的点赞、关注、收藏!

目录
相关文章
|
安全 Java Go
Java vs. Go:并发之争
【4月更文挑战第20天】
984 1
|
7月前
|
人工智能 供应链 搜索推荐
AI+电商API:智能推荐、动态定价与自动化运营的未来
在电商竞争日益激烈的今天,AI与电商API的深度融合正重塑行业格局。通过智能推荐、动态定价与自动化运营,AI+电商API助力企业精准洞察用户需求、优化价格策略、提升运营效率,推动个性化、高效能的智慧电商发展,为企业打开未来增长新空间。
|
7月前
|
区块链 数据安全/隐私保护 Python
小试牛刀-区块链WalletConnect协议数据解密
最近在学习如何使用Wallet Connect,查阅官方文档后,发现并没有太多的中文参考资料,英文直译读起来也有一些偏差,所以这边直接采用网页Demo的方式,对WC协议有了一定了解.在此进行记录,同时希望帮助到有实现相关功能的朋友.
605 4
|
8月前
|
JSON API 数据格式
深入研究:淘宝天猫关键词搜索接口详解
淘宝和天猫提供关键词搜索商品的API接口,支持开发者按关键词获取商品列表及相关数据。功能包括通过搜索关键词(q)返回商品基本信息,如ID、标题、价格、图片、销量等。支持排序(sort)、分页(page_no/page_size)、价格区间筛选(start_price/end_price)及分类搜索(cat)。返回JSON格式数据,含商品ID、标题、价格、图片链接、详情页链接和销量等字段。
|
8月前
|
XML 前端开发 JavaScript
2025 年最新 CSS 面试题 100 道及详细答案解析
本文整理了100道CSS面试题及答案,涵盖基础概念、选择器与特性、布局(如Flexbox和Grid)、动画与过渡、响应式设计等核心内容。从CSS的基础知识如盒模型、`box-sizing`属性,到高级应用如伪类选择器(LVHA、CSS3新增伪类)和视觉格式化模型(BFC),帮助开发者系统掌握CSS技能。此外,还涉及浏览器兼容性、CSS优化及预处理器等内容,为前端工程师提供全面的学习资源。资源可从[此链接](https://pan.quark.cn/s/50438c9ee7c0)获取。
656 5
|
7月前
|
存储 算法 fastjson
火点监测:Nasa高分卫星接入
NASA(美国国家航空航天局)是美国联邦政府的一个独立机构,负责国家的航空航天研究和探索任务。NASA成立于1958年,其使命是探索太空并推动科学技术的发展。NASA的主要任务包括研究地球和太空的物理特性、开发和测试航空航天技术、进行太空探索和科学研究,以及促进航空航天技术的应用和技术转移。这里使用其开发的系统firms(火灾资源管理系统),通过Http请求获取数据来实现火点的监测,帮助需要实现相关功能,有类似开发任务的朋友。
218 6
|
7月前
|
关系型数据库 MySQL 索引
mysql中的索引和分区
在MySQL中,索引和分区是提高查询效率的关键技术。通过创建合适的索引,可以显著提升数据检索速度。而分区可以作为作为进一步提高查询效率的方式,在较大数据量时通常可以使用这两个结合的方式优化查询速度,所以这边将这两个进行整理,巩固个人知识,同时也希望帮助到有需要的朋友。
169 2
|
7月前
|
存储 Rust 安全
Rocket框架JWT鉴权实战:保护Rust Web API的安全方案​
本篇文章是基于rust语言和rocket依赖实现网页JWT认证和鉴权,完成简单的JWT token的验证和鉴权处理,使用cargo做依赖的导入和测试。
321 1
|
7月前
|
区块链
小试牛刀-区块链Solana多签账户
在 Solana 区块链中,多签账户(Multisig Account)是一种智能合约账户,允许多个签名者共同管理和控制账户上的资产或操作。这种机制增强了账户的安全性和灵活性,特别适用于需要多个权限共同批准的操作场景,如资产管理、资金转移、或项目治理。
382 1
|
搜索推荐 关系型数据库 MySQL
MySQL 模糊查询新纪元:超越 LIKE+% 的高效探索
在数据库的日常操作中,模糊查询是一项不可或缺的功能,它允许我们根据不完全匹配的关键字来检索数据。传统上,MySQL 使用 LIKE 关键字配合 % 通配符来实现这一功能,虽然灵活但性能上往往不尽如人意,尤其是在处理大型数据集时。今天,我们将一起探索几种超越 LIKE+% 的模糊查询技术,以提升查询效率与用户体验。
810 2