Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - Product/Quotient/Remainder (PQR) Instruction Class #498

Merged
merged 8 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 78 additions & 3 deletions src/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,84 @@ fn make_instruction_map() -> HashMap<String, (InstructionType, u8)> {
entry(&format!("{name}64"), AluBinary, ebpf::BPF_ALU64 | opc);
}

entry("sdiv", AluBinary, ebpf::BPF_ALU64 | ebpf::BPF_SDIV);
entry("sdiv64", AluBinary, ebpf::BPF_ALU64 | ebpf::BPF_SDIV);
entry("sdiv32", AluBinary, ebpf::BPF_ALU | ebpf::BPF_SDIV);
// Product Quotient Remainder.
entry(
"lmul",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_LMUL,
);
entry(
"lmul64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_LMUL,
);
entry("lmul32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_LMUL);
entry(
"uhmul",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UHMUL,
);
entry(
"uhmul64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UHMUL,
);
entry("uhmul32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_UHMUL);
entry(
"shmul",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SHMUL,
);
entry(
"shmul64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SHMUL,
);
entry("shmul32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SHMUL);
entry(
"udiv",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UDIV,
);
entry(
"udiv64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UDIV,
);
entry("udiv32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_UDIV);
entry(
"urem",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UREM,
);
entry(
"urem64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_UREM,
);
entry("urem32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_UREM);
entry(
"sdiv",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SDIV,
);
entry(
"sdiv64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SDIV,
);
entry("sdiv32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SDIV);
entry(
"srem",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SREM,
);
entry(
"srem64",
AluBinary,
ebpf::BPF_PQR | ebpf::BPF_B | ebpf::BPF_SREM,
);
entry("srem32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SREM);

// LoadAbs, LoadInd, LoadReg, StoreImm, and StoreReg.
for &(suffix, size) in &mem_sizes {
Expand Down
30 changes: 26 additions & 4 deletions src/disassembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::MUL32_REG => { name = "mul32"; desc = alu_reg_str(name, insn); },
ebpf::DIV32_IMM => { name = "div32"; desc = alu_imm_str(name, insn); },
ebpf::DIV32_REG => { name = "div32"; desc = alu_reg_str(name, insn); },
ebpf::SDIV32_IMM => { name = "sdiv32"; desc = alu_imm_str(name, insn); },
ebpf::SDIV32_REG => { name = "sdiv32"; desc = alu_reg_str(name, insn); },
ebpf::OR32_IMM => { name = "or32"; desc = alu_imm_str(name, insn); },
ebpf::OR32_REG => { name = "or32"; desc = alu_reg_str(name, insn); },
ebpf::AND32_IMM => { name = "and32"; desc = alu_imm_str(name, insn); },
Expand Down Expand Up @@ -181,8 +179,6 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::MUL64_REG => { name = "mul64"; desc = alu_reg_str(name, insn); },
ebpf::DIV64_IMM => { name = "div64"; desc = alu_imm_str(name, insn); },
ebpf::DIV64_REG => { name = "div64"; desc = alu_reg_str(name, insn); },
ebpf::SDIV64_IMM => { name = "sdiv64"; desc = alu_imm_str(name, insn); },
ebpf::SDIV64_REG => { name = "sdiv64"; desc = alu_reg_str(name, insn); },
ebpf::OR64_IMM => { name = "or64"; desc = alu_imm_str(name, insn); },
ebpf::OR64_REG => { name = "or64"; desc = alu_reg_str(name, insn); },
ebpf::AND64_IMM => { name = "and64"; desc = alu_imm_str(name, insn); },
Expand All @@ -202,6 +198,32 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::ARSH64_REG => { name = "arsh64"; desc = alu_reg_str(name, insn); },
ebpf::HOR64_IMM => { name = "hor64"; desc = alu_imm_str(name, insn); },

// BPF_PQR class
ebpf::LMUL32_IMM => { name = "lmul32"; desc = alu_imm_str(name, insn); },
ebpf::LMUL32_REG => { name = "lmul32"; desc = alu_reg_str(name, insn); },
ebpf::LMUL64_IMM => { name = "lmul64"; desc = alu_imm_str(name, insn); },
ebpf::LMUL64_REG => { name = "lmul64"; desc = alu_reg_str(name, insn); },
ebpf::UHMUL64_IMM => { name = "uhmul64"; desc = alu_imm_str(name, insn); },
ebpf::UHMUL64_REG => { name = "uhmul64"; desc = alu_reg_str(name, insn); },
ebpf::SHMUL64_IMM => { name = "shmul64"; desc = alu_imm_str(name, insn); },
ebpf::SHMUL64_REG => { name = "shmul64"; desc = alu_reg_str(name, insn); },
ebpf::UDIV32_IMM => { name = "udiv32"; desc = alu_imm_str(name, insn); },
ebpf::UDIV32_REG => { name = "udiv32"; desc = alu_reg_str(name, insn); },
ebpf::UDIV64_IMM => { name = "udiv64"; desc = alu_imm_str(name, insn); },
ebpf::UDIV64_REG => { name = "udiv64"; desc = alu_reg_str(name, insn); },
ebpf::UREM32_IMM => { name = "urem32"; desc = alu_imm_str(name, insn); },
ebpf::UREM32_REG => { name = "urem32"; desc = alu_reg_str(name, insn); },
ebpf::UREM64_IMM => { name = "urem64"; desc = alu_imm_str(name, insn); },
ebpf::UREM64_REG => { name = "urem64"; desc = alu_reg_str(name, insn); },
ebpf::SDIV32_IMM => { name = "sdiv32"; desc = alu_imm_str(name, insn); },
ebpf::SDIV32_REG => { name = "sdiv32"; desc = alu_reg_str(name, insn); },
ebpf::SDIV64_IMM => { name = "sdiv64"; desc = alu_imm_str(name, insn); },
ebpf::SDIV64_REG => { name = "sdiv64"; desc = alu_reg_str(name, insn); },
ebpf::SREM32_IMM => { name = "srem32"; desc = alu_imm_str(name, insn); },
ebpf::SREM32_REG => { name = "srem32"; desc = alu_reg_str(name, insn); },
ebpf::SREM64_IMM => { name = "srem64"; desc = alu_imm_str(name, insn); },
ebpf::SREM64_REG => { name = "srem64"; desc = alu_reg_str(name, insn); },

// BPF_JMP class
ebpf::JA => {
name = "ja";
Expand Down
110 changes: 85 additions & 25 deletions src/ebpf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub const MM_INPUT_START: u64 = 0x400000000;
// See also https://www.kernel.org/doc/Documentation/networking/filter.txt

// Three least significant bits are operation class:
/// BPF operation class: load from immediate.
/// BPF operation class: load from immediate. [DEPRECATED]
pub const BPF_LD: u8 = 0x00;
/// BPF operation class: load from register.
pub const BPF_LDX: u8 = 0x01;
Expand All @@ -73,7 +73,8 @@ pub const BPF_STX: u8 = 0x03;
pub const BPF_ALU: u8 = 0x04;
/// BPF operation class: jump.
pub const BPF_JMP: u8 = 0x05;
// [ class 6 unused, reserved for future use ]
/// BPF operation class: product / quotient / remainder.
pub const BPF_PQR: u8 = 0x06;
/// BPF operation class: 64 bits arithmetic operation.
pub const BPF_ALU64: u8 = 0x07;

Expand Down Expand Up @@ -125,9 +126,9 @@ pub const BPF_X: u8 = 0x08;
pub const BPF_ADD: u8 = 0x00;
/// BPF ALU/ALU64 operation code: subtraction.
pub const BPF_SUB: u8 = 0x10;
/// BPF ALU/ALU64 operation code: multiplication.
/// BPF ALU/ALU64 operation code: multiplication. [DEPRECATED]
pub const BPF_MUL: u8 = 0x20;
/// BPF ALU/ALU64 operation code: division.
/// BPF ALU/ALU64 operation code: division. [DEPRECATED]
pub const BPF_DIV: u8 = 0x30;
/// BPF ALU/ALU64 operation code: or.
pub const BPF_OR: u8 = 0x40;
Expand All @@ -137,9 +138,9 @@ pub const BPF_AND: u8 = 0x50;
pub const BPF_LSH: u8 = 0x60;
/// BPF ALU/ALU64 operation code: right shift.
pub const BPF_RSH: u8 = 0x70;
/// BPF ALU/ALU64 operation code: negation.
/// BPF ALU/ALU64 operation code: negation. [DEPRECATED]
pub const BPF_NEG: u8 = 0x80;
/// BPF ALU/ALU64 operation code: modulus.
/// BPF ALU/ALU64 operation code: modulus. [DEPRECATED]
pub const BPF_MOD: u8 = 0x90;
/// BPF ALU/ALU64 operation code: exclusive or.
pub const BPF_XOR: u8 = 0xa0;
Expand All @@ -149,11 +150,28 @@ pub const BPF_MOV: u8 = 0xb0;
pub const BPF_ARSH: u8 = 0xc0;
/// BPF ALU/ALU64 operation code: endianness conversion.
pub const BPF_END: u8 = 0xd0;
/// BPF ALU/ALU64 operation code: signed division.
pub const BPF_SDIV: u8 = 0xe0;
/// BPF ALU/ALU64 operation code: high or.
pub const BPF_HOR: u8 = 0xf0;

// Operation codes -- BPF_PQR class:
// 7 6 5 4 3 2-0
// 0 Unsigned Multiplication Product Lower Half / Quotient 32 Bit Immediate PQR
// 1 Signed Division Product Upper Half / Remainder 64 Bit Register PQR
/// BPF PQR operation code: unsigned high multiplication.
pub const BPF_UHMUL: u8 = 0x20;
/// BPF PQR operation code: unsigned division quotient.
pub const BPF_UDIV: u8 = 0x40;
/// BPF PQR operation code: unsigned division remainder.
pub const BPF_UREM: u8 = 0x60;
/// BPF PQR operation code: low multiplication.
pub const BPF_LMUL: u8 = 0x80;
/// BPF PQR operation code: signed high multiplication.
pub const BPF_SHMUL: u8 = 0xA0;
/// BPF PQR operation code: signed division quotient.
pub const BPF_SDIV: u8 = 0xC0;
/// BPF PQR operation code: signed division remainder.
pub const BPF_SREM: u8 = 0xE0;

// Operation codes -- BPF_JMP class:
/// BPF JMP operation code: jump.
pub const BPF_JA: u8 = 0x00;
Expand Down Expand Up @@ -188,7 +206,7 @@ pub const BPF_JSLE: u8 = 0xd0;
// (Following operation names are not “official”, but may be proper to rbpf; Linux kernel only
// combines above flags and does not attribute a name per operation.)

/// BPF opcode: `lddw dst, imm` /// `dst = imm`.
/// BPF opcode: `lddw dst, imm` /// `dst = imm`. [DEPRECATED]
pub const LD_DW_IMM: u8 = BPF_LD | BPF_IMM | BPF_DW;
/// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`.
pub const LD_B_REG: u8 = BPF_LDX | BPF_MEM | BPF_B;
Expand Down Expand Up @@ -262,17 +280,38 @@ pub const MOV32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOV;
/// BPF opcode: `mov32 dst, src` /// `dst = src`.
pub const MOV32_REG: u8 = BPF_ALU | BPF_X | BPF_MOV;
/// BPF opcode: `arsh32 dst, imm` /// `dst >>= imm (arithmetic)`.
///
/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
pub const ARSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_ARSH;
/// BPF opcode: `arsh32 dst, src` /// `dst >>= src (arithmetic)`.
///
/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
pub const ARSH32_REG: u8 = BPF_ALU | BPF_X | BPF_ARSH;
/// BPF opcode: `sdiv32 dst, imm` /// `dst s/= imm`.
pub const SDIV32_IMM: u8 = BPF_ALU | BPF_K | BPF_SDIV;
/// BPF opcode: `sdiv32 dst, src` /// `dst s/= src`.
pub const SDIV32_REG: u8 = BPF_ALU | BPF_X | BPF_SDIV;

/// BPF opcode: `lmul32 dst, imm` /// `dst *= (dst * imm) as u32`.
pub const LMUL32_IMM: u8 = BPF_PQR | BPF_K | BPF_LMUL;
/// BPF opcode: `lmul32 dst, src` /// `dst *= (dst * src) as u32`.
pub const LMUL32_REG: u8 = BPF_PQR | BPF_X | BPF_LMUL;
/// BPF opcode: `uhmul32 dst, imm` /// `dst = (dst * imm) as u64`.
// pub const UHMUL32_IMM: u8 = BPF_PQR | BPF_K | BPF_UHMUL;
/// BPF opcode: `uhmul32 dst, src` /// `dst = (dst * src) as u64`.
// pub const UHMUL32_REG: u8 = BPF_PQR | BPF_X | BPF_UHMUL;
/// BPF opcode: `udiv32 dst, imm` /// `dst /= imm`.
pub const UDIV32_IMM: u8 = BPF_PQR | BPF_K | BPF_UDIV;
/// BPF opcode: `udiv32 dst, src` /// `dst /= src`.
pub const UDIV32_REG: u8 = BPF_PQR | BPF_X | BPF_UDIV;
/// BPF opcode: `urem32 dst, imm` /// `dst %= imm`.
pub const UREM32_IMM: u8 = BPF_PQR | BPF_K | BPF_UREM;
/// BPF opcode: `urem32 dst, src` /// `dst %= src`.
pub const UREM32_REG: u8 = BPF_PQR | BPF_X | BPF_UREM;
/// BPF opcode: `shmul32 dst, imm` /// `dst = (dst * imm) as i64`.
// pub const SHMUL32_IMM: u8 = BPF_PQR | BPF_K | BPF_SHMUL;
/// BPF opcode: `shmul32 dst, src` /// `dst = (dst * src) as i64`.
// pub const SHMUL32_REG: u8 = BPF_PQR | BPF_X | BPF_SHMUL;
/// BPF opcode: `sdiv32 dst, imm` /// `dst /= imm`.
pub const SDIV32_IMM: u8 = BPF_PQR | BPF_K | BPF_SDIV;
/// BPF opcode: `sdiv32 dst, src` /// `dst /= src`.
pub const SDIV32_REG: u8 = BPF_PQR | BPF_X | BPF_SDIV;
/// BPF opcode: `srem32 dst, imm` /// `dst %= imm`.
pub const SREM32_IMM: u8 = BPF_PQR | BPF_K | BPF_SREM;
/// BPF opcode: `srem32 dst, src` /// `dst %= src`.
pub const SREM32_REG: u8 = BPF_PQR | BPF_X | BPF_SREM;

/// BPF opcode: `le dst` /// `dst = htole<imm>(dst), with imm in {16, 32, 64}`.
pub const LE: u8 = BPF_ALU | BPF_K | BPF_END;
Expand Down Expand Up @@ -326,20 +365,41 @@ pub const MOV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOV;
/// BPF opcode: `mov64 dst, src` /// `dst = src`.
pub const MOV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOV;
/// BPF opcode: `arsh64 dst, imm` /// `dst >>= imm (arithmetic)`.
///
/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
pub const ARSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ARSH;
/// BPF opcode: `arsh64 dst, src` /// `dst >>= src (arithmetic)`.
///
/// <https://en.wikipedia.org/wiki/Arithmetic_shift>
pub const ARSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ARSH;
/// BPF opcode: `sdiv64 dst, imm` /// `dst s/= imm`.
pub const SDIV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_SDIV;
/// BPF opcode: `sdiv64 dst, src` /// `dst s/= src`.
pub const SDIV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_SDIV;
/// BPF opcode: `hor64 dst, imm` /// `dst |= imm << 32`.
pub const HOR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_HOR;

/// BPF opcode: `lmul64 dst, imm` /// `dst = (dst * imm) as u64`.
pub const LMUL64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_LMUL;
/// BPF opcode: `lmul64 dst, src` /// `dst = (dst * src) as u64`.
pub const LMUL64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_LMUL;
/// BPF opcode: `uhmul64 dst, imm` /// `dst = (dst * imm) >> 64`.
pub const UHMUL64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_UHMUL;
/// BPF opcode: `uhmul64 dst, src` /// `dst = (dst * src) >> 64`.
pub const UHMUL64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_UHMUL;
/// BPF opcode: `udiv64 dst, imm` /// `dst /= imm`.
pub const UDIV64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_UDIV;
/// BPF opcode: `udiv64 dst, src` /// `dst /= src`.
pub const UDIV64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_UDIV;
/// BPF opcode: `urem64 dst, imm` /// `dst %= imm`.
pub const UREM64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_UREM;
/// BPF opcode: `urem64 dst, src` /// `dst %= src`.
pub const UREM64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_UREM;
/// BPF opcode: `shmul64 dst, imm` /// `dst = (dst * imm) >> 64`.
pub const SHMUL64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_SHMUL;
/// BPF opcode: `shmul64 dst, src` /// `dst = (dst * src) >> 64`.
pub const SHMUL64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_SHMUL;
/// BPF opcode: `sdiv64 dst, imm` /// `dst /= imm`.
pub const SDIV64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_SDIV;
/// BPF opcode: `sdiv64 dst, src` /// `dst /= src`.
pub const SDIV64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_SDIV;
/// BPF opcode: `srem64 dst, imm` /// `dst %= imm`.
pub const SREM64_IMM: u8 = BPF_PQR | BPF_B | BPF_K | BPF_SREM;
/// BPF opcode: `srem64 dst, src` /// `dst %= src`.
pub const SREM64_REG: u8 = BPF_PQR | BPF_B | BPF_X | BPF_SREM;

/// BPF opcode: `ja +off` /// `PC += off`.
pub const JA: u8 = BPF_JMP | BPF_JA;
/// BPF opcode: `jeq dst, imm, +off` /// `PC += off if dst == imm`.
Expand Down
4 changes: 2 additions & 2 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ impl SBPFVersion {
self != &SBPFVersion::V1
}

/// Enable native signed division
pub fn enable_sdiv(&self) -> bool {
/// Enable the BPF_PQR instruction class
pub fn enable_pqr(&self) -> bool {
self != &SBPFVersion::V1
}

Expand Down
Loading