@[toc]
Welcome to Code Block's blog本篇文章主要介绍了
[rbpf虚拟机-opcode码]
❤博主广交技术好友,喜欢我的文章的可以关注一下❤
一、概述
该篇文章是rbpf虚拟机opcode码作用和使用的整理。
(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)
经过验证器后在rbpf虚拟机需要知道每条指令是用来做什么的,就需要用到opcode码,opcode码中由8种操作码、5种访问模式、4种数据大小进行组合获得,其结构如下图:
7 6 5 4 | 3 2 | 1 0
+---------------+--------+--------+
| 操作码 | 访问模式 | 大小 |
+---------------+--------+--------+
二、eBPF 的指令格式
完整的 eBPF 指令通常是 8 字节(64 位),其中 opcode 仅占 低 8 位,其余部分包含寄存器编号、立即数等。
31 24 23 16 15 8 7 0
+--------+--------+--------+--------+
| dst | src | offset | opcode |
+--------+--------+--------+--------+
| immediate / address |
+----------------------------------------+
字段说明:
| 字段 | 位数 | 说明 |
|-------------|--------|---------|
| opcode | 8-bit | 操作码,包括 OP、MODE 和 SIZE |
| dst | 4-bit | 目标寄存器编号 |
| src | 4-bit | 源寄存器编号(用于二元运算) |
| offset | 16-bit | 偏移量(用于内存访问或跳转) |
| immediate | 32-bit | 立即数(用于算术或跳转指令) |
三、Opcode 具体字段解释
1. 操作码(OP,7~4位)4位
| Opcode 值 | 名称 | 说明 |
|---|---|---|
0x00 |
BPF_LD |
立即数/内存加载指令 |
0x40 |
BPF_LDX |
从内存加载到寄存器 |
0x60 |
BPF_ST |
存储指令(寄存器 → 内存) |
0x61 |
BPF_STX |
存储指令(寄存器 → 内存,带索引) |
0x80 |
BPF_ALU |
算术运算(立即数模式) |
0xc0 |
BPF_ALU64 |
64 位算术运算 |
0xa0 |
BPF_JMP |
跳转指令 |
0xe0 |
BPF_JMP32 |
32 位跳转指令 |
2. 访问模式(MODE,3~2位)2位
| Mode 值 | 名称 | 说明 |
|---|---|---|
0x00 |
BPF_IMM |
立即数模式(直接使用值) |
0x10 |
BPF_ABS |
绝对地址模式(用于 BPF_LD) |
0x20 |
BPF_IND |
间接地址模式(用于 BPF_LD) |
0x60 |
BPF_MEM |
内存模式(从内存读取/写入) |
0x70 |
BPF_LEN |
报文长度(仅在 BPF_LD 使用) |
3. 数据大小(SIZE,1~0位) 2位
| Size 值 | 名称 | 说明 |
|---|---|---|
0x00 |
BPF_W |
4 字节(32 位) |
0x08 |
BPF_H |
2 字节(16 位) |
0x10 |
BPF_B |
1 字节(8 位) |
0x18 |
BPF_DW |
8 字节(64 位) |
三、具体使用
opcode码有很多种,如果直接使用如:0x71表示从内存加载 1 字节到寄存器,在定义时如果使用:
LD_B_REG = 0x71
这读起来有点费力,不利于维护操作。为了解决这一问题,可以直接将上述的操作码、访问模式、数据大小进行预先定义,然后使用以下方式进行定义:
LD_B_REG = BPF_LDX | BPF_MEM | BPF_B
BPF_LDX表示从内存加载到寄存器,BPF_MEM表示内存模式,BPF_B表示1个字节。这时我们就可以清楚的知晓LD_B_REG为从内存加载 1 字节到寄存器。这样,哪怕不知道是什么值,也可以通过按位或计算得到
opcode(操作码).
LD_B_REG = BPF_LDX | BPF_MEM | BPF_B
= 0x61 | 0x00 | 0x10
= 0b0110 0001 | 0b0000 0000 | 0b0001 0000
------------------------------------------
= 0b0111 0001 // 结果 = 0x71(十六进制)
四、总结
通过上述对opcode码结构进行解读,对opcode码有了更深刻的理解,同时这种结构组合按位或处理可以产生很多组合结果,该方法可以很好的运用到日常的其它语言项目中。
代码来源:rbpf虚拟机
鸣谢: qmonnet 提供的开源代码.
当然,我也会将带有中文注释和自己理解的一些代码上传的我的github页面,感兴趣的朋友可以进行clone查看.
我的GitHub:forked
感谢您的点赞、关注、收藏!