0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

eBPF指令集v1.0使用規(guī)范介紹

Linux閱碼場 ? 來源:Linux閱碼場 ? 2023-03-08 10:21 ? 次閱讀

目的:編譯成功的eBPF程序,加載時偶爾會過不了內(nèi)核BPF verifier,冒出一堆匯編語句。理解eBPF指令集,可以幫助我們調(diào)試這類問題。

1. eBPF指令集規(guī)范v1.0

本文檔是eBPF指令集規(guī)范,版本 1.0

1.1 寄存器和使用規(guī)范

eBPF有10個通用寄存器和一個只讀的棧幀寄存器,他們都是64-bit寬度。

eBPF的寄存器使用規(guī)范為:

R0: 保存函數(shù)返回值和eBPF程序退出值。

R1 - R5: 用于函數(shù)調(diào)用參數(shù)。

R6 - R9: callee函數(shù)負責進入時保存這幾個寄存器到棧中,函數(shù)退出前再恢復寄存器原有值。(callee saved registers that function calls will preserve)

R10: 只讀的棧幀寄存器,用于訪問棧。

R0 - R5是臨時寄存器,eBPF程序如果希望在函數(shù)調(diào)用后寄存器值不變,需要自己保存和恢復寄存器。(R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if necessary across calls.)

譯者注:

Scratch register / temporary register:顧名思義,用于保存臨時值或者中間值。

Caller 和 Callee: A函數(shù)中調(diào)用B函數(shù),那么 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函數(shù)負責保存和恢復寄存器(也可以不保存和恢復) Callee函數(shù)負責保存和恢復寄存器,這樣寄存器的值在子函數(shù)調(diào)用后不會改變

更多資料

1.2 指令編碼

eBPF有兩種編碼模式:

基礎(chǔ)編碼,64bit固定長度編碼。

寬指令編碼,在基礎(chǔ)編碼后增加了一個64bit的立即數(shù)(imm64)。這樣指令為128bit。

基礎(chǔ)編碼格式,每一列約定為field:

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

注意:絕大多數(shù)指令不會使用所有的field,不使用的field被置0。

寬指令編碼目前只有64-bit立即數(shù)指令使用。

1.2.1 指令類型(class)

基礎(chǔ)編碼中的field的opcode,一共8bit,其中最低位3bit用來保存指令類型:

class value description reference
BPF_LD 0x00 只能用于寬指令,從imm64中加載數(shù)據(jù)到寄存器 Load 和 store指令
BPF_LDX 0x01 從內(nèi)存中加載數(shù)據(jù)到dst_reg Load 和 store指令
BPF_ST 0x02 把imm32數(shù)據(jù)保存到內(nèi)存中 Load 和 store指令
BPF_STX 0x03 把src_reg寄存器數(shù)據(jù)保存到內(nèi)存 Load 和 store指令
BPF_ALU 0x04 32bit算術(shù)運算 算術(shù)和跳轉(zhuǎn)指令
BPF_JMP 0x05 64bit跳轉(zhuǎn)操作 算術(shù)和跳轉(zhuǎn)指令
BPF_JMP32 0x06 32bit跳轉(zhuǎn)操作 算術(shù)和跳轉(zhuǎn)指令
BPF_ALU64 0x07 64bit算術(shù)運算 算術(shù)和跳轉(zhuǎn)指令

1.3 算術(shù)和跳轉(zhuǎn)指令

(BPF_ALU, BPF_ALU64, BPF_JMP和BPF_JMP32)稱為算術(shù)和跳轉(zhuǎn)指令。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作為源操作數(shù)
BPF_X 0x08 使用源寄存器(src_reg)作為源操作數(shù)

4個bit的operation code用來存儲具體指令操作碼。

1.3.1 算術(shù)指令(BPF_ALU, BPF_ALU64)

BPF_ALU操作數(shù)為32bit,BPF_ALU64操作數(shù)為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 算術(shù)右移操作。對于負數(shù),右移會在左邊最高位補上右移次數(shù)個1,對于正數(shù)則補0
BPF_END 0xd0 字節(jié)的swap操作

譯者注:

上表中dst一定是指目的寄存器,不支持內(nèi)存地址。

上表中src可能是源寄存器,也可能是imm32,根據(jù)source位(BPF_K或者BPF_X)來區(qū)分。

eBPF寄存器都是64bit,根據(jù)操作數(shù)類型,可以使用全部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 字節(jié)swap指令

字節(jié)swap指令,屬于BPF_ALU分類,操作碼為BPF_END。

字節(jié)swap指令操作數(shù)只有dst_reg,不操作src_reg和imm32。

opcode中的source位含義現(xiàn)在更改為:

source value description
BPF_TO_LE 0x00 主機字節(jié)序到小端字節(jié)序
BPF_TO_BE 0x08 主字節(jié)序序到大端字節(jié)序

基礎(chǔ)編碼格式中的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 跳轉(zhuǎn)指令(BPF_JMP32, BPF_JMP)

操作數(shù)為寄存器,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 函數(shù)調(diào)用
BPF_EXIT 0x90 函數(shù)或者程序返回 僅用在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程序在調(diào)用BPF_EXIT前,需要把返回值保存在R0寄存器中。

譯者注: 上表中的術(shù)語:

PC:程序計數(shù)器。

off: 基礎(chǔ)編碼格式中的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立即數(shù)指令 64bit立即數(shù)指令
BPF_ABS 0x20 經(jīng)典BPF數(shù)據(jù)包訪問(直接) 經(jīng)典BPF數(shù)據(jù)包訪問指令
BPF_IND 0x40 經(jīng)典BPF數(shù)據(jù)包訪問(間接) 經(jīng)典BPF數(shù)據(jù)包訪問指令
BPF_MEM 0x60 標準load和store操作 標準load和store指令
BPF_ATOMIC 0xc0 原子操作 原子操作

size含義:

size value description
BPF_W 0x00 字長(4字節(jié))
BPF_H 0x08 半字長(2字節(jié))
BPF_B 0x010 字節(jié)(1字節(jié))
BPF_DW 0x18 雙字長(8字節(jié))

1.4.1 標準load和store指令

BPF_MEM代表了標準load和store指令,這些指令用于寄存器和內(nèi)存之間傳遞數(shù)據(jù)。

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 原子操作

原子操作,指的的是對內(nèi)存的操作,不會被其他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)指向內(nèi)存的值
BPF_CMPXCHG 0xf0|BPF_FETCH 原子CAS.if (*(uXX*)(dst_reg + off16) == R0) { *(uXX*)(dst_reg + off16) = (src_reg) };無論是否交換成功,R0都會保存(dst_reg + off16)指向內(nèi)存的被修改前的原始值。如果是32bit操作數(shù),那么用會0補齊高位后再保存到R0。

BPF_FETCH:

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

對于簡單原子指令是可選的,如果設(shè)置了,src_reg將保存(dst_reg + off16)指向的內(nèi)存中被修改前的原始值。

對于復雜原子指令是必選的。

1.4.3 64bit立即數(shù)指令

mode為BPF_IMM的指令,用于eBPF寬指令,有額外的一個imm64值。
目前只有一條指令:
BPF_LD | BPF_DW | BPF_IMM,含義為:
dst_reg = imm64

1.4.4 經(jīng)典BPF數(shù)據(jù)包訪問指令

eBPF之前為了兼容經(jīng)典BPF,引入了一些訪問數(shù)據(jù)包的指令?,F(xiàn)在已經(jīng)廢棄不再使用。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120447
  • JMP
    JMP
    +關(guān)注

    關(guān)注

    1

    文章

    17

    瀏覽量

    12609
  • ALU
    ALU
    +關(guān)注

    關(guān)注

    0

    文章

    33

    瀏覽量

    13105
  • BPF
    BPF
    +關(guān)注

    關(guān)注

    0

    文章

    25

    瀏覽量

    4007

原文標題:eBPF指令集規(guī)范v1.0

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

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

    、開放性 RISC-V :RISC-V指令集架構(gòu)規(guī)范公開,可以免費使用。任何人都可以基于RISC-V架構(gòu)設(shè)計、制造和銷售處理器,這種開放性使
    發(fā)表于 09-28 11:05

    RISC-V指令集概述

    RISC-V就是RISC的第五代指令集架構(gòu)。而RISC-V目標就是“成為一種完全開放的指令集架構(gòu),可被任何學術(shù)機構(gòu)或商業(yè)組織自由使用”。 RISC-
    發(fā)表于 11-30 23:30

    敏俊物聯(lián)MJIOT-AMB-03模塊AT指令集V1.0

    `敏俊物聯(lián)MJIOT-AMB-03模塊AT指令集V1.0`
    發(fā)表于 04-27 13:10

    簡單介紹ARM的指令集

    處理器架構(gòu)是處理器廠商為同一個系列的處理器規(guī)定的一個規(guī)范。ARM架構(gòu)是一種精簡指令集(RISC)架構(gòu),具有以下RISC架構(gòu)特點:較大的通用寄存器堆。load/store體系結(jié)構(gòu),其中數(shù)據(jù)處理操作僅對
    發(fā)表于 08-18 10:58

    ARM的指令集文章集合

    三、指令集如果你想要集中學習一下關(guān)于ARM指令集方面的知識(比如下面幾個知識點),可以看下下面的文章1、機器碼2、運算指令3、控制指令4、匯編指令
    發(fā)表于 09-07 22:06

    Thumb指令集是什么意思呢

    了一些變種。Thumb指令集(T變種)Thumb指令集是將ARM指令集的一個子集重新編碼形成的指令集。ARM指令長度為32位,Thumb
    發(fā)表于 12-14 09:01

    ARM指令集詳解

    ARM指令集詳解 內(nèi)容提要 ARM指令集 ARM指令集分類與指令格式 ARM指令的尋址方式 ARM
    發(fā)表于 03-09 09:39 ?263次下載
    ARM<b class='flag-5'>指令集</b>詳解

    ESP8266 WIFIAT指令集_v0.1

    ESP8266 WIFIAT指令集_v0.1,Espressif AT 指令集
    發(fā)表于 12-29 14:16 ?36次下載

    LeMedia使用教程V1.0

    LeMedia使用教程V1.0,介紹LeMedia如何使用。
    發(fā)表于 02-22 17:29 ?10次下載

    ARM指令集介紹

    arm開發(fā)板 嵌入式開發(fā) 指令集 PDF文檔。
    發(fā)表于 05-03 16:42 ?5次下載

    thumb指令集是什么_thumb指令集與arm指令集的區(qū)別

    thumb指令集是arm指令集的一個子集,是針對代碼密度問題而提出的,它具有16位的代碼寬度。與等價的32位代碼相比較,thumb指令集在保留32位代碼優(yōu)勢的同時,大大的節(jié)省了系統(tǒng)的存儲空間
    發(fā)表于 11-03 17:34 ?1.8w次閱讀
    thumb<b class='flag-5'>指令集</b>是什么_thumb<b class='flag-5'>指令集</b>與arm<b class='flag-5'>指令集</b>的區(qū)別

    印度確立RISC-V為國家指令集 中國CPU指令集還在孤芳自賞

    目前中國CPU指令集還處在群雄割據(jù)的狀態(tài),印度就已早一步確定了“國家版”,印度將RISC-V確立為國家指令集,并將目標調(diào)整為研制6款基于RISC-V
    發(fā)表于 12-19 16:58 ?7664次閱讀
    印度確立RISC-<b class='flag-5'>V</b>為國家<b class='flag-5'>指令集</b> 中國CPU<b class='flag-5'>指令集</b>還在孤芳自賞

    ARM架構(gòu)及ARM指令集 Thumb指令集你了解多少?

    ARM架構(gòu)及ARM指令集、Thumb指令集你了解多少?
    的頭像 發(fā)表于 02-26 16:09 ?7148次閱讀

    簡單講講RISC-V指令集CPU的參數(shù)

    本次CPU采用32位RISC-V指令集架構(gòu)(一代是自己瞎編指令集)。指令集就是程序指令的集合,指引硬件如何設(shè)計、如何運行。
    的頭像 發(fā)表于 08-07 14:55 ?3680次閱讀
    簡單講講RISC-<b class='flag-5'>V</b><b class='flag-5'>指令集</b>CPU的參數(shù)

    RISC-V指令集是如何設(shè)計的

    我們先講最基礎(chǔ)的RV32I指令集。作為最基礎(chǔ)的指令集,其包括幾種指令類型。分別是數(shù)字運算指令(包括寄存器指令和立即數(shù)
    的頭像 發(fā)表于 08-08 14:47 ?2937次閱讀
    RISC-<b class='flag-5'>V</b><b class='flag-5'>指令集</b>是如何設(shè)計的