rbpf虚拟机-汇编和反汇编器

news2025/4/1 3:28:35

文章目录

  • 一、概述
  • 二、主要功能
  • 三、关键函数解析
    • 3.1 汇编器
      • 3.1.1 `parse` -转换为Instruction列表
      • 3.1.2 `assemble_internal`-转换为Insn
    • 3.2 反汇编器
      • 3.2.1 `to_insn_vec`-转换为机器指令
  • 四、总结

Welcome to Code Block's blog

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


一、概述

该篇文章是rbpf汇编器和反汇编器代码块功能的整理。

(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)

汇编器的作用是将机器指令转换为二进制操作码,反汇编器将二进制操作码数据转换为机器指令的形式进行显示。

二、主要功能

汇编和反汇编器主要实现以下功能:

  1. 机器指令转二进制
    • 机器指令到初始指令结构体(Instruction)
    • 初始指令类到指令结构体(Insn)
    • 指令列表通过切片转换为二进制
  2. 二进制转机器指令
    • 循环解析到机器指令

三、关键函数解析

3.1 汇编器

3.1.1 parse -转换为Instruction列表

pub fn parse(input: &str) -> Result<Vec<Instruction>, String> {
    //1.跳过零个或多个空格
    //2.这里的with 不关心((), ["mov", "add", "sub"]) 里的()
    let mut with = spaces().with(many(instruction()).skip(eof()));

    #[cfg(feature = "std")]
    {
        //根据with解析器去解析指令
        match with.easy_parse(position::Stream::new(input)) {
            Ok((insts, _)) => Ok(insts),
            Err(err) => Err(err.to_string()),
        }
    }
    #[cfg(not(feature = "std"))]
    {
        match with.parse(position::Stream::new(input)) {
            Ok((insts, _)) => Ok(insts),
            Err(err) => Err(err.to_string()),
        }
    }
}

在parse方法中,会将机器指令如:"move r1, 0"格式转换为:

[Instruction { name: "mov", operands: [Register(1), Integer(0)] }]

主要使用的是combine 转换库,在这里是根据空格和换行分割后,使用instruction()进行封装,instruction()方法内容如下:

n instruction<I>() -> impl Parser<I, Output = Instruction>
where
    I: Stream<Token = char>,
    I::Error: ParseError<I::Token, I::Range, I::Position>,
{
    //解析以特定分隔符分隔的多个元素。
    let operands = sep_by(operand(), char(',').skip(spaces()));

    (ident().skip(spaces()), operands, spaces()).map(|t| Instruction {
        name: t.0,
        operands: t.1,
    })
}

什么是combine?
combine 是一个基于解析器组合子(parser combinators)的库,它允许开发者通过组合简单的解析器来构建复杂的解析器。解析器组合子是一种函数式编程技术,通过将小的解析器组合起来,形成更大、更复杂的解析器。

combine文档

3.1.2 assemble_internal-转换为Insn

fn assemble_internal(parsed: &[Instruction]) -> Result<Vec<Insn>, String> {
    let instruction_map = make_instruction_map();
    let mut result: Vec<Insn> = vec![];

    //循环parsed列表 (parsed来自parse方法返回值)
    for instruction in parsed {
        //获取命令名称
        let name = instruction.name.as_str();
        //匹配类型和opcode
        match instruction_map.get(name) {
            Some(&(inst_type, opc)) => {
                match encode(inst_type, opc, &instruction.operands) {
                    //匹配成功后返在结果内添加命令
                    Ok(insn) => result.push(insn),
                    //发生错误时,返回错误
                    Err(msg) => return Err(format!("Failed to encode {name}: {msg}")),
                }
                // Special case for lddw.
                // 当类型是imm类型时,对命令取高32位进行拼接
                if let LoadImm = inst_type {
                    if let Integer(imm) = instruction.operands[1] {
                        result.push(insn(0, 0, 0, 0, imm >> 32).unwrap());
                    }
                }
            }
            None => return Err(format!("Invalid instruction {name:?}")),
        }
    }
    Ok(result)
}

assemble_internal()作用是将parse()处理完成后的数据进行进一步的处理,处理成以下数据格式:

[Insn { opc: 183, dst: 1, src: 0, off: 0, imm: 0 }]

Insn数据为ebpf的指令格式.

  31      24 23     16 15      8 7       0
+--------+--------+--------+--------+
|    dst  |    src  |  offset  |  opcode |
+--------+--------+--------+--------+
|           immediate / address          |
+----------------------------------------+

然后通过切片extend_from_slice的方式将其转换为二进制格式。完整的转换代码如下:

pub fn assemble(src: &str) -> Result<Vec<u8>, String> {
    let parsed = (parse(src))?;
    //Ok([Instruction { name: "mov", operands: [Register(0), Integer(0)] }, Instruction { name: "add", operands: [Register(1), Integer(2)] }])
    let insns = (assemble_internal(&parsed))?;

    let mut result: Vec<u8> = vec![];
    for insn in insns {
        result.extend_from_slice(&insn.to_array());
    }
    Ok(result)
}

3.2 反汇编器

3.2.1 to_insn_vec-转换为机器指令

pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
    //验证程序是规定的8位
    if prog.len() % ebpf::INSN_SIZE != 0 {
        panic!(
            "[Disassembler] Error: eBPF program length must be a multiple of {:?} octets",
            ebpf::INSN_SIZE
        );
    }
    //验证是否为空
    if prog.is_empty() {
        return vec![];
    }
    let mut res = vec![];
    let mut insn_ptr: usize = 0;

    //循环遍历指令
    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
        let insn = ebpf::get_insn(prog, insn_ptr);
        let name;
        let desc;
        let mut imm = insn.imm as i64;

        match insn.opc {
          ebpf::LD_ABS_B => {
                name = "ldabsb";
                desc = ldabs_str(name, &insn);
            },
          ......
    }
    res
}

to_insn_vec方法代码中使用循环的方式对每个二进制指令(8位),根据每条指令的opcode码进行转换,转换为字符串格式的机器指令(desc),其中包括对指令长度、是否为空进行检查。

四、总结

通过上述对源码进行解读,可以看到汇编器和反汇编器在虚拟机中起着重要的作用,允许开发者直接编写与 eBPF 架构兼容的指令。通过汇编器,这些指令被翻译成内核能够理解和执行的二进制形式。

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

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

我的GitHub:forked


感谢您的点赞、关注、收藏!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2324922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

虚拟现实--->unity学习

前言&#xff1a;这学期劳动课选了虚拟现实&#xff0c;其中老师算挺认真的&#xff0c;当然对一些不感兴趣的同学来说是一种折磨&#xff0c;我对这个unity的学习以及后续的虚幻引擎刚开始连基础的概念都没有&#xff0c;后面渐渐也是滋生了一些兴趣&#xff0c;用这篇博客记录…

一文详解QT环境搭建:ubuntu20.4安装配置Qt5

随着软件开发技术的不断进步&#xff0c;跨平台应用程序的需求日益增长&#xff0c;开发者们面临着如何在不同操作系统之间保持代码的一致性和效率的问题。Qt作为一个成熟的跨平台C框架&#xff0c;在这方面提供了卓越的支持&#xff0c;不仅简化了GUI应用程序的创建过程&#…

【IDEA的个性化配置】

目录&#xff1a; 一&#xff1a;隐藏项目路径二&#xff1a;禁用斜体注释三&#xff1a;重新Maven构建未完待续... 一&#xff1a;隐藏项目路径 &#x1f60a;在IDEA左侧的Project目录中&#xff0c;项目名称后面显示了项目的文件路径地址&#xff0c;如果不喜欢可以隐藏&…

【Kafka】分布式消息队列的核心奥秘

文章目录 一、Kafka 的基石概念​主题&#xff08;Topic&#xff09;​分区&#xff08;Partition&#xff09;​生产者&#xff08;Producer&#xff09;​消费者&#xff08;Consumer&#xff09;​ 二、Kafka 的架构探秘​Broker 集群​副本机制​ 三、Kafka 的卓越特性​高…

自动化发布工具CI/CD实践Jenkins部署与配置教程

1. 前言背景 其实一直想把jenkins 的笔记整理下&#xff0c;介于公司这次升级jenkins2.0 &#xff0c;根据自己部署的一些经验&#xff0c;我把它整理成笔记。 之前我们的jenkins1.0 时代 还一直停留在 free style 或者 maven 风格的项目&#xff0c;随着项目的日益增多&#x…

什么是SQL作业

SQL作业是在数据库服务器上按特定时间或间隔自动执行的计划任务或流程&#xff0c;这些作业由Microsoft SQL Server中的SQL Server代理管理&#xff0c;对于自动执行日常任务&#xff08;如数据库系统中的备份、数据导入和报告生成&#xff09;以及确保及时准确地处理和更新数据…

Android实践开发制作小猴子摘桃小游戏

Android实践制作小猴子摘桃小游戏 实践素材项目源文件获取&#xff1a;Android可能存在版本差异项目如果不能正确运行&#xff0c;可以使用里面的素材自己构建项目Android实践制作小猴子摘桃小游戏Android实践制作小猴子摘桃小游戏https://mp.weixin.qq.com/s/jNU_hVfj9xklsil…

springboot整合couchbase(集群)

springboot整合couchbase 1、Couchbase1.1、介绍1.2、Bucket1.3、Couchbase SDK 2、(key,value)写入couchbase集群2.1、总体图2.2、依赖2.3、CouchbaseConfig 配置文件2.4、代码使用 1、Couchbase 1.1、介绍 1.2、Bucket 在 Couchbase 中&#xff0c;bucket 是一个重要的概念…

VsCode启用右括号自动跳过(自动重写) - 自录制gif演示

VsCode启用右括号自动跳过(自动重写) - 自录制gif演示 前言 不知道大家在编程时候的按键习惯是怎样的。输入完左括号后编辑器一般会自动补全右括号&#xff0c;输入完左括号的内容后&#xff0c;是按→跳过右括号还是按)跳过右括号呢&#xff1f; for (int i 0; i < a.s…

[Linux]在vim中批量注释与批量取消注释

1.在vim中批量注释的步骤&#xff1a; 1.在normal模式下按Ctrl v &#xff0c;进入V-BLOCK模式 2.按 J 键 或 K 键选择要注释的内容&#xff0c;J向上K向下 我们给第5&#xff0c;6&#xff0c;7行进行注释 3.按住shift i进入插入模式&#xff0c;输入 // 4.点击ESC键&…

NC,GFS、ICON 数据气象信息可视化--降雨量的实现

随着气象数据的快速发展和应用&#xff0c;气象信息的可视化成为了一项不可或缺的技术手段。它不仅能帮助气象专家快速解读数据&#xff0c;还能为公众提供直观的天气预报信息。今天&#xff0c;我们将从降雨量的可视化出发&#xff0c;带大家一起了解如何实现气象数据的可视化…

LLM之RAG实战(五十二)| 如何使用混合搜索优化RAG 检索

在RAG项目中&#xff0c;大模型生成的参考内容&#xff08;专业术语称为块&#xff09;来自前一步的检索&#xff0c;检索的内容在很大程度上直接决定了生成的效果&#xff0c;因此检索对于RAG项目至关重要&#xff0c;最常用的检索方法是关键字搜索和语义搜索。本文将分别介绍…

[操作系统,学习记录]3.进程(2)

1.fork(); 玩法一&#xff1a;通过返回值if&#xff0c;else去执行不同的代码片段 玩法二&#xff1a;if&#xff0c;else然后调用execve函数去执行新的程序 2.进程终止&#xff1a; 退出码&#xff0c;子进程通过exit/return返回&#xff0c;父进程wait/waitpid等待而得&am…

26考研——排序_选择排序_选择排序的基本思想 简单选择排序(8)

408答疑 文章目录 四、选择排序选择排序的基本思想简单选择排序定义算法思想性能分析空间效率时间效率稳定性 适用性 九、参考资料鲍鱼科技课件26王道考研书 四、选择排序 选择排序的基本思想 每一趟&#xff08;如第 i i i 趟&#xff09;在剩下 n − i 1 n-i1 n−i1&…

PPT——组合SCI论文图片

SCI论文中对于图的排版常常是最头疼的事情&#xff0c;通常需要几个图组合在一起&#xff0c;并且如何控制图中的字体一致也是麻烦事。 保持这个大图里面的一致&#xff0c;转头一看跟其他图又不一致了。最近跟我的博导学了一手&#xff0c;今天就来记录一下吧。主要用到的软件…

Tabby 一:如何在Mac配置保姆级教程(本地模型替换hugging face下载)

1. brew安装 mac需要先安装brew&#xff0c;如果本地已经安装过brew这一步可以忽略&#xff0c;遇到问题可以自己ai问 /bin/bash -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 可能遇到source .zprofile失败&#xff0c;因为…

CentOS 安装LAMP全过程 - 完整步骤与最佳实践

在开始搭建 LAMP 环境之前&#xff0c;需要确保系统已经满足以下条件&#xff1a; 1、操作系统&#xff1a;CentOS 7 或 CentOS 8 2、网络连接&#xff1a;系统必须能够访问互联网以下载所需的软件包 3、权限&#xff1a;需要 root 权限或者通过sudo 提权执行命令 先更新系…

基于DCT变换和Huffman编码的图像压缩解压缩算法matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 DCT变换 4.2 Huffman编码的数学原理 4.3 图像压缩流程 4.4 仿真测试指标 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a/matl…

Vue下 Sortable 实现 table 列表字段可拖拽排序,显示隐藏组件开发

vue 开发table 列表时&#xff0c;需要动态调整列字段的顺序和显示隐藏 实现效果如图所示&#xff1a; vue 组件代码 <template><div style"width: 90%; margin: 0 auto;"><el-table :data"tableData" border"" ref"table…

李飞飞、吴佳俊团队新作:FlowMo如何以零卷积、零对抗损失实现ImageNet重构新巅峰

目录 一、摘要 二、引言 三、相关工作 四、方法 基于扩散先前的离散标记化器利用广告 架构 阶段 1A&#xff1a;模式匹配预训练 阶段 1B&#xff1a;模式搜索后训练 采样 第二阶段&#xff1a;潜在生成建模 五、Coovally AI模型训练与应用平台 六、实验 主要结果 …