eBPF指令集_sse3指令集

2022-11-08 16:43:59 浏览数 (2)

大家好,又见面了,我是你们的朋友全栈君。

寄存器及调用约定

通用的RISC指令集,11个64位寄存器,一个程序计数器和512字节的栈空间构成。

10个通用寄存器 1个只读FP(帧指针寄存器),所有寄存器64bit宽。操作模式默认为64位,32位子寄存器只能通过特殊的算数逻辑单元ALU操作访问。

栈帧的边界由SP和FP限定

SP一直指向栈顶

每个进程的栈空间为一帧,FP指向当前进程栈空间的栈底。

  • R0:函数返回值、程序退出值
  • R1-R5:函数调用参数
  • R6-R9:被调用者保存函数(调用保留的)寄存器
  • R10:只读FP用于访问栈

R0-R5是临时寄存器,eBPF程序在调用之间将它们从寄存器转移到内存或从内存转移到寄存器。(spill/fill,解释见https://www.geeksforgeeks.org/what-is-spilling/)

指令编码

  • 基础指令编码:一条指令64bit
  • 宽指令编码:在基础指令编码后附加一个64bit的立即数,一共128bit

基础指令编码结构:

32 bits (MSB)

16 bits

4 bits

4 bits

8 bits (LSB)

immediate

offset

source register

destination register

opcode

指令分类

Opcode低三位:

指令分类

class

value

description

算数指令

BPF_ALU

0x04

32-bit 算数操作

BPF_ALU64

0x07

64-bit 算数操作

跳转指令

BPF_JMP

0x05

64-bit 跳转操作

BPF_JMP32

0x06

32-bit 跳转操作

载入指令

BPF_LD

0x00

non-standard load operations

BPF_LDX

0x01

载入寄存器操作

存储指令

BPF_ST

0x02

存储立即数操作

BPF_STX

0x03

存储寄存器操作

算数和跳转指令

包括:BPF_ALU, BPF_ALU64, BPF_JMP and BPF_JMP32

opcode分为三部分

4 bits (MSB)

1 bit

3 bits (LSB)

operation code

source

instruction class

第四位编码了source操作数:

source

value

description

BPF_K

0x00

使用 32-bit 立即数作为源操作数

BPF_X

0x08

使用 ‘src_reg’ 寄存器作为源操作数

算数指令

operation code编码的操作

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

sign extending shift right

BPF_END

0xd0

byte swap operations (see separate section below)

例子:

BPF_XOR | BPF_K | BPF_ALU == src_reg = (u32) src_reg ^ (u32) imm32

字节交换指令

仅对目标寄存器进行操作,不使用源寄存器或立即数

source字段用于选择转换的字节序

source

value

description

BPF_TO_LE

0x00

转换主机字节序到小端

BPF_TO_BE

0x08

转换主机字节序到大端

立即数字段用于编码交换操作的宽度,可以是16/32/64

例子

BPF_ALU | BPF_TO_LE | BPF_END with imm = 16

dst_reg = htole16(dst_reg)

跳转指令

code

value

description

notes

BPF_JA

0x00

PC = off

BPF_JMP only

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

function call

BPF_EXIT

0x90

function / program return

BPF_JMP only

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

载入和存储指令

包括:BPF_LD, BPF_LDX, BPF_ST and BPF_STX

Opcode结构:

3 bits (MSB)

2 bits

3 bits (LSB)

mode

size

instruction class

size修饰符

size modifier

value

description

BPF_W

0x00

word (4 bytes)

BPF_H

0x08

half word (2 bytes)

BPF_B

0x10

byte

BPF_DW

0x18

double word (8 bytes)

mode修饰符

mode modifier

value

description

BPF_IMM

0x00

64-bit immediate instructions

BPF_ABS

0x20

legacy BPF packet access (absolute)

BPF_IND

0x40

legacy BPF packet access (indirect)

BPF_MEM

0x60

regular load and store operations,寄存器和内存间传递数据的标准载入和存储指令

BPF_ATOMIC

0xc0

atomic operations,原子操作

举例

把立即数的值放到dst_reg off的内存位置

BPF_MEM | <size> | BPF_ST == *(size *) (dst_reg off) = imm32

原子操作

在内存上的操作,不会被中断或破坏,使用mode修饰符BPF_ATOMIC,只支持32位和64位操作,不支持8/16位。

立即数字段用于编码实际的原子操作:

imm

value

description

BPF_ADD

0x00

atomic add

BPF_OR

0x40

atomic or

BPF_AND

0x50

atomic and

BPF_XOR

0xa0

atomic xor

例子:

BPF_ATOMIC | BPF_W | BPF_STX with imm = BPF_ADD

*(u32 *)(dst_reg off16) = src_reg

除了简单原子操作,还有一个修饰符和两个复杂原子操作

imm

value

description

BPF_FETCH

0x01

modifier: return old value

BPF_XCHG

0xe0 | BPF_FETCH

atomic exchange

BPF_CMPXCHG

0xf0 | BPF_FETCH

atomic compare and exchange

如果设置了BPF_FETCH,会使用修改前内存中的值覆盖src_reg

BPF_XCHG以原子操作交换src_reg的值和dst_reg off地址的值

BPF_CMPXCHG以原子操作将dst_reg off地址的值和R0进行比较,如果相等,dst_reg off地址的值将替换为src_reg。操作前dst_reg off地址的值会被扩展零,然后加载回R0。

clang可以生成原子指令通过默认的 -mcpu=v3

如果较低版本的 -mcpu被设置,clang只能生成不带 BPF_FETCHBPF_ADD

如果需要启用原子特征,并保持较低版本的 -mcpu,可以使用 -Xclang -target-feature -Xclang alu32

64位立即数指令

带有BPF_IMMmode修饰符的指令,对额外的64位立即数使用宽指令编码:

BPF_LD | BPF_DW | BPF_IMM means dst_reg = imm64

传统的BPF Packet访问指令

用于访问数据包数据,并且只能在程序上下文是指向网络数据包的指针时使用。

两种指令形式

  • BPF_ABS | <size> | BPF_LDBPF_ABS访问由立即数指定的绝对偏移的数据包数据
  • BPF_IND | <size> | BPF_LDBPF_IND访问除立即数外还包括寄存器值作为偏移的数据包数据。

七个隐式操作数:

  • R6,隐式输入,指向 struct sk_buff 的指针
  • R0,隐式输出,从数据包中获取的数据
  • R1-5,临时寄存器,在调用BPF_ABS | BPF_LDBPF_IND | BPF_LD后被破坏

隐式的程序退出条件:当eBPF程序试图访问数据包边界外的数据时,执行将被终止。

例子:

BPF_IND | BPF_W | BPF_LD

R0 = ntohl(*(u32 *) (((struct sk_buff *) R6)->data src_reg imm32))

参考

eBPF Instruction Set ‒ The Linux Kernel documentation

BPF and XDP Reference Guide — Cilium 1.11.3 documentation

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190954.html原文链接:https://javaforall.cn

0 人点赞