0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

eBPF指令集v1.0使用规范介绍

Linux阅码场 来源:Linux阅码场 2023-03-08 10:21 次阅读

目的:编译成功的eBPF程序,加载时偶尔会过不了内核BPF verifier,冒出一堆汇编语句。理解eBPF指令集,可以帮助我们调试这类问题。

1. eBPF指令集规范v1.0

本文档是eBPF指令集规范,版本 1.0

1.1 寄存器和使用规范

eBPF有10个通用寄存器和一个只读的栈帧寄存器,他们都是64-bit宽度。

eBPF的寄存器使用规范为:

R0: 保存函数返回值和eBPF程序退出值。

R1 - R5: 用于函数调用参数

R6 - R9: callee函数负责进入时保存这几个寄存器到栈中,函数退出前再恢复寄存器原有值。(callee saved registers that function calls will preserve)

R10: 只读的栈帧寄存器,用于访问栈。

R0 - R5是临时寄存器,eBPF程序如果希望在函数调用后寄存器值不变,需要自己保存和恢复寄存器。(R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if necessary across calls.)

译者注:

Scratch register / temporary register:顾名思义,用于保存临时值或者中间值。

Caller 和 Callee: A函数中调用B函数,那么 A是Caller,B是Callee。

Caller saved registers 和 Callee saved registers

Caller saved registers(AKA volatile registers, or call-clobbered) Callee saved registers(AKA non-volatile registers, or call-preserved)
Caller函数负责保存和恢复寄存器(也可以不保存和恢复) Callee函数负责保存和恢复寄存器,这样寄存器的值在子函数调用后不会改变

更多资料

1.2 指令编码

eBPF有两种编码模式:

基础编码,64bit固定长度编码。

宽指令编码,在基础编码后增加了一个64bit的立即数(imm64)。这样指令为128bit。

基础编码格式,每一列约定为field:

32 bits (MSB,最高bit位) 16 bits 4 bits 4 bits 8 bits (LSB,最低比特位)
imm32(立即数) off16(偏移) src_reg(源寄存器) dst_reg(目的寄存器) opcode(操作码)

注意:绝大多数指令不会使用所有的field,不使用的field被置0。

宽指令编码目前只有64-bit立即数指令使用。

1.2.1 指令类型(class)

基础编码中的field的opcode,一共8bit,其中最低位3bit用来保存指令类型:

class value description reference
BPF_LD 0x00 只能用于宽指令,从imm64中加载数据到寄存器 Load 和 store指令
BPF_LDX 0x01 从内存中加载数据到dst_reg Load 和 store指令
BPF_ST 0x02 把imm32数据保存到内存中 Load 和 store指令
BPF_STX 0x03 把src_reg寄存器数据保存到内存 Load 和 store指令
BPF_ALU 0x04 32bit算术运算 算术和跳转指令
BPF_JMP 0x05 64bit跳转操作 算术和跳转指令
BPF_JMP32 0x06 32bit跳转操作 算术和跳转指令
BPF_ALU64 0x07 64bit算术运算 算术和跳转指令

1.3 算术和跳转指令

(BPF_ALU, BPF_ALU64, BPF_JMP和BPF_JMP32)称为算术和跳转指令。8bit的opcode被分为3个部分:

4 bits (MSB,最高bit位) 1 bit 3 bits (LSB,最低bit位)
operation code source 指令类型(BPF_ALU, BPF_ALU64, BPF_JMP或BPF_JMP32)

第4个bit(source)含义:

source value description
BPF_K 0x00 使用32-bitimm32作为源操作数
BPF_X 0x08 使用源寄存器(src_reg)作为源操作数

4个bit的operation code用来存储具体指令操作码。

1.3.1 算术指令(BPF_ALU, BPF_ALU64)

BPF_ALU操作数为32bit,BPF_ALU64操作数为64bit。4个bit的operation code编码了如下操作:

operation code value description
BPF_ADD 0x00 dst += src
BPF_SUB 0x10 dst -= src
BPF_MUL 0x20 dst *= src
BPF_DIV 0x30 dst /= src
BPF_OR 0x40 dst |= src
BPF_AND 0x50 dst &= src
BPF_LSH 0x60 dst <<= src
BPF_RSH 0x70 dst >>= src
BPF_NEG 0x80 dst = ~src
BPF_MOD 0x90 dst %= src
BPF_XOR 0xa0 dst ^= src
BPF_MOV 0xb0 dst = src
BPF_ARSH 0xc0 算术右移操作。对于负数,右移会在左边最高位补上右移次数个1,对于正数则补0
BPF_END 0xd0 字节的swap操作

译者注:

上表中dst一定是指目的寄存器,不支持内存地址。

上表中src可能是源寄存器,也可能是imm32,根据source位(BPF_K或者BPF_X)来区分。

eBPF寄存器都是64bit,根据操作数类型,可以使用全部64bit,也可以只使用其中32bit。

一些例子:

BPF_ADD | BPF_X | BPF_ALU:

dst_reg = (u32) dst_reg + (u32) src_reg;

BPF_XOR | BPF_K | BPF_ALU64:

dst_reg = dst_reg + src_reg

BPF_XOR | BPF_K | BPF_ALU:

dst_reg = (u32) dst_reg ^ (u32) imm32

BPF_XOR | BPF_K | BPF_ALU64:

dst_reg = dst_reg ^ imm32

1.3.1.1 字节swap指令

字节swap指令,属于BPF_ALU分类,操作码为BPF_END。

字节swap指令操作数只有dst_reg,不操作src_reg和imm32。

opcode中的source位含义现在更改为:

source value description
BPF_TO_LE 0x00 主机字节序到小端字节序
BPF_TO_BE 0x08 主字节序序到大端字节序

基础编码格式中的imm32,此时编码了swap操作的位宽。支持:16,32和64bit。
例子:

BPF_ALU | BPF_TO_LE | BPF_END,并且imm32= 16:

dst_reg = htole16(dst_reg)

BPF_ALU | BPF_TO_LE | BPF_END,并且imm32= 64:

dst_reg = htole64(dst_reg)

1.3.2 跳转指令(BPF_JMP32, BPF_JMP)

操作数为寄存器,BPF_JMP32使用32bit,BPF_JMP使用64bit,其它行为都一样。operation code含义如下:

operation code value description notes
BPF_JA 0x00 PC += off 仅用在BPF_JMP中
BPF_JEQ 0x10 PC += off if dst == src
BPF_JGT 0x20 PC += off if dst > src unsigned
BPF_JGE 0x30 PC += off if dst >= src unsigned
BPF_JSET 0x40 PC += off if dst & src
BPF_JNE 0x50 PC += off if dst != src
BPF_JSGT 0x60 PC += off if dst > src signed
BPF_JSGE 0x70 PC += off if dst >= src signed
BPF_CALL 0x80 函数调用
BPF_EXIT 0x90 函数或者程序返回 仅用在BPF_JMP分类中
BPF_JLT 0xa0 PC += off if dst < src unsigned
BPF_JLE 0xb0 PC += off if dst <= src unsigned
BPF_JSLT 0xc0 PC += off if dst < src signed
BPF_JSLE 0xd0 PC += off if dst <= src signed

eBPF程序在调用BPF_EXIT前,需要把返回值保存在R0寄存器中。

译者注: 上表中的术语:

PC:程序计数器。

off: 基础编码格式中的off16。

src,dst: 都是指的寄存器的值。

1.4 Load 和 Store指令

BPF_LD, BPF_LDX, BPF_ST和BPF_STX指令类型中,8bit的opcode含义为:

3 bits (MSB) 2 bit 3 bits (LSB)
mode size 指令类型(BPF_LD, BPF_LDX, BPF_ST或BPF_STX)

mode含义是:

mode value description reference
BPF_IMM 0x00 64bit立即数指令 64bit立即数指令
BPF_ABS 0x20 经典BPF数据包访问(直接) 经典BPF数据包访问指令
BPF_IND 0x40 经典BPF数据包访问(间接) 经典BPF数据包访问指令
BPF_MEM 0x60 标准load和store操作 标准load和store指令
BPF_ATOMIC 0xc0 原子操作 原子操作

size含义:

size value description
BPF_W 0x00 字长(4字节)
BPF_H 0x08 半字长(2字节)
BPF_B 0x010 字节(1字节)
BPF_DW 0x18 双字长(8字节)

1.4.1 标准load和store指令

BPF_MEM代表了标准load和store指令,这些指令用于寄存器和内存之间传递数据。

BPF_MEM | | BPF_STX:

*(size *) (dst_reg + off16) = src_reg

BPF_MEM | | BPF_ST:

*(size *) (dst_reg + off16) = imm32

BPF_MEM | | BPF_LDX:

dst_reg = *(size *) (src_reg + off16)

size可选值:BPF_B, BPF_H, BPF_W, or BPF_DW

1.4.2 原子操作

原子操作,指的的是对内存的操作,不会被其他eBPF程序中途扰乱。

eBPF所有的原子操作由BPF_ATOMIC指定,例如:

BPF_ATOMIC | BPF_W | BPF_STX:32-bit原子操作。

BPF_ATOMIC | BPF_DW | BPF_STX:64-bit原子操作。

8-bit和16-bit原子操作不支持。

基本编码格式的imm32用来编码真正的原子操作, 以下是简单原子指令:

imm32 value description
BPF_ADD 0x00 原子加
BPF_OR 0x40 原子或
BPF_AND 0x50 原子与
BPF_XOR 0xa0 原子异或

BPF_ATOMIC | BPF_W | BPF_STX,imm32 = BPF_ADD,含义:

*(u32 *)(dst_reg + off16) += src_reg

BPF_ATOMIC | BPF_DW | BPF_STX,imm32 = BPF_ADD, 含义:

*(u64 *)(dst_reg + off16) += src_reg

除了以上比较简单的原子操作,还有2个复杂原子指令:

imm32 value description
BPF_XCHG 0xe0|BPF_FETCH 原子交换,交换src_reg和(dst_reg + off16)指向内存的值
BPF_CMPXCHG 0xf0|BPF_FETCH 原子CAS.if (*(uXX*)(dst_reg + off16) == R0) { *(uXX*)(dst_reg + off16) = (src_reg) };无论是否交换成功,R0都会保存(dst_reg + off16)指向内存的被修改前的原始值。如果是32bit操作数,那么用会0补齐高位后再保存到R0。

BPF_FETCH:

imm32 value description
BPF_FETCH 0x01 代表需要返回旧值

对于简单原子指令是可选的,如果设置了,src_reg将保存(dst_reg + off16)指向的内存中被修改前的原始值。

对于复杂原子指令是必选的。

1.4.3 64bit立即数指令

mode为BPF_IMM的指令,用于eBPF宽指令,有额外的一个imm64值。
目前只有一条指令:
BPF_LD | BPF_DW | BPF_IMM,含义为:
dst_reg = imm64

1.4.4 经典BPF数据包访问指令

eBPF之前为了兼容经典BPF,引入了一些访问数据包的指令。现在已经废弃不再使用。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5342

    浏览量

    120325
  • JMP
    JMP
    +关注

    关注

    1

    文章

    17

    浏览量

    12599
  • ALU
    ALU
    +关注

    关注

    0

    文章

    33

    浏览量

    13100
  • BPF
    BPF
    +关注

    关注

    0

    文章

    25

    浏览量

    4005

原文标题:eBPF指令集规范v1.0

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    RISC-V和arm指令集的对比分析

    、开放性 RISC-V :RISC-V指令集架构规范公开,可以免费使用。任何人都可以基于RISC-V架构设计、制造和销售处理器,这种开放性使
    发表于 09-28 11:05

    RISC-V指令集概述

    RISC-V就是RISC的第五代指令集架构。而RISC-V目标就是“成为一种完全开放的指令集架构,可被任何学术机构或商业组织自由使用”。 RISC-
    发表于 11-30 23:30

    敏俊物联MJIOT-AMB-03模块AT指令集V1.0

    `敏俊物联MJIOT-AMB-03模块AT指令集V1.0`
    发表于 04-27 13:10

    简单介绍ARM的指令集

    处理器架构是处理器厂商为同一个系列的处理器规定的一个规范。ARM架构是一种精简指令集(RISC)架构,具有以下RISC架构特点:较大的通用寄存器堆。load/store体系结构,其中数据处理操作仅对
    发表于 08-18 10:58

    ARM的指令集文章集合

    三、指令集如果你想要集中学习一下关于ARM指令集方面的知识(比如下面几个知识点),可以看下下面的文章1、机器码2、运算指令3、控制指令4、汇编指令
    发表于 09-07 22:06

    Thumb指令集是什么意思呢

    了一些变种。Thumb指令集(T变种)Thumb指令集是将ARM指令集的一个子集重新编码形成的指令集。ARM指令长度为32位,Thumb
    发表于 12-14 09:01

    ARM指令集详解

    ARM指令集详解 内容提要 ARM指令集 ARM指令集分类与指令格式 ARM指令的寻址方式 ARM
    发表于 03-09 09:39 263次下载
    ARM<b class='flag-5'>指令集</b>详解

    ESP8266 WIFIAT指令集_v0.1

    ESP8266 WIFIAT指令集_v0.1,Espressif AT 指令集
    发表于 12-29 14:16 36次下载

    LeMedia使用教程V1.0

    LeMedia使用教程V1.0介绍LeMedia如何使用。
    发表于 02-22 17:29 10次下载

    ARM指令集介绍

    arm开发板 嵌入式开发 指令集 PDF文档。
    发表于 05-03 16:42 5次下载

    thumb指令集是什么_thumb指令集与arm指令集的区别

    thumb指令集是arm指令集的一个子集,是针对代码密度问题而提出的,它具有16位的代码宽度。与等价的32位代码相比较,thumb指令集在保留32位代码优势的同时,大大的节省了系统的存储空间
    发表于 11-03 17:34 1.8w次阅读
    thumb<b class='flag-5'>指令集</b>是什么_thumb<b class='flag-5'>指令集</b>与arm<b class='flag-5'>指令集</b>的区别

    印度确立RISC-V为国家指令集 中国CPU指令集还在孤芳自赏

    目前中国CPU指令集还处在群雄割据的状态,印度就已早一步确定了“国家版”,印度将RISC-V确立为国家指令集,并将目标调整为研制6款基于RISC-V
    发表于 12-19 16:58 7662次阅读
    印度确立RISC-<b class='flag-5'>V</b>为国家<b class='flag-5'>指令集</b> 中国CPU<b class='flag-5'>指令集</b>还在孤芳自赏

    ARM架构及ARM指令集 Thumb指令集你了解多少?

    ARM架构及ARM指令集、Thumb指令集你了解多少?
    的头像 发表于 02-26 16:09 7138次阅读

    简单讲讲RISC-V指令集CPU的参数

    本次CPU采用32位RISC-V指令集架构(一代是自己瞎编指令集)。指令集就是程序指令的集合,指引硬件如何设计、如何运行。
    的头像 发表于 08-07 14:55 3667次阅读
    简单讲讲RISC-<b class='flag-5'>V</b><b class='flag-5'>指令集</b>CPU的参数

    RISC-V指令集是如何设计的

    我们先讲最基础的RV32I指令集。作为最基础的指令集,其包括几种指令类型。分别是数字运算指令(包括寄存器指令和立即数
    的头像 发表于 08-08 14:47 2932次阅读
    RISC-<b class='flag-5'>V</b><b class='flag-5'>指令集</b>是如何设计的