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

Refactor - Move memory instruction classes #603

Merged
merged 10 commits into from
Oct 8, 2024
Prev Previous commit
Next Next commit
Enables the new opcodes conditionally in the dis-/assembler.
Lichtso committed Oct 7, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 727d464feefb75a46d016e3aa7e457559cee5bb9
64 changes: 40 additions & 24 deletions src/assembler.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use crate::{
},
ebpf::{self, Insn},
elf::Executable,
program::{BuiltinProgram, FunctionRegistry},
program::{BuiltinProgram, FunctionRegistry, SBPFVersion},
vm::ContextObject,
};
use std::collections::HashMap;
@@ -47,7 +47,7 @@ enum InstructionType {
NoOperand,
}

fn make_instruction_map() -> HashMap<String, (InstructionType, u8)> {
fn make_instruction_map(sbpf_version: &SBPFVersion) -> HashMap<String, (InstructionType, u8)> {
let mut result = HashMap::new();

let alu_binary_ops = [
@@ -66,11 +66,31 @@ fn make_instruction_map() -> HashMap<String, (InstructionType, u8)> {
("hor", ebpf::BPF_HOR),
];

let mem_classes = [
(
"ldx",
LoadReg,
ebpf::BPF_MEM | ebpf::BPF_LDX,
ebpf::BPF_ALU | ebpf::BPF_X,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should give BPF_ALU another name, as it is going to be associated with memory operations.

),
(
"st",
StoreImm,
ebpf::BPF_MEM | ebpf::BPF_ST,
ebpf::BPF_ALU64 | ebpf::BPF_K,
),
(
"stx",
StoreReg,
ebpf::BPF_MEM | ebpf::BPF_STX,
ebpf::BPF_ALU64 | ebpf::BPF_X,
),
];
let mem_sizes = [
("w", ebpf::BPF_W),
("h", ebpf::BPF_H),
("b", ebpf::BPF_B),
("dw", ebpf::BPF_DW),
("b", ebpf::BPF_B, ebpf::BPF_1B),
("h", ebpf::BPF_H, ebpf::BPF_2B),
("w", ebpf::BPF_W, ebpf::BPF_4B),
("dw", ebpf::BPF_DW, ebpf::BPF_8B),
];

let jump_conditions = [
@@ -189,23 +209,19 @@ fn make_instruction_map() -> HashMap<String, (InstructionType, u8)> {
);
entry("srem32", AluBinary, ebpf::BPF_PQR | ebpf::BPF_SREM);

// LoadReg, StoreImm, and StoreReg.
for &(suffix, size) in &mem_sizes {
entry(
&format!("ldx{suffix}"),
LoadReg,
ebpf::BPF_MEM | ebpf::BPF_LDX | size,
);
entry(
&format!("st{suffix}"),
StoreImm,
ebpf::BPF_MEM | ebpf::BPF_ST | size,
);
entry(
&format!("stx{suffix}"),
StoreReg,
ebpf::BPF_MEM | ebpf::BPF_STX | size,
);
// Memory
if sbpf_version.move_memory_instruction_classes() {
for &(prefix, class, _, opcode) in &mem_classes {
for &(suffix, _, size) in &mem_sizes {
entry(&format!("{prefix}{suffix}"), class, opcode | size);
}
}
} else {
for &(prefix, class, opcode, _) in &mem_classes {
for &(suffix, size, _) in &mem_sizes {
entry(&format!("{prefix}{suffix}"), class, opcode | size);
}
}
}

// JumpConditional.
@@ -300,7 +316,7 @@ pub fn assemble<C: ContextObject>(
let sbpf_version = loader.get_config().enabled_sbpf_versions.end().clone();

let statements = parse(src)?;
let instruction_map = make_instruction_map();
let instruction_map = make_instruction_map(&sbpf_version);
let mut insn_ptr = 0;
let mut function_registry = FunctionRegistry::default();
let mut labels = HashMap::new();
12 changes: 12 additions & 0 deletions src/disassembler.rs
Original file line number Diff line number Diff line change
@@ -148,8 +148,10 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::SUB32_REG => { name = "sub32"; desc = alu_reg_str(name, insn); },
ebpf::MUL32_IMM if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_imm_str(name, insn); },
ebpf::MUL32_REG if !sbpf_version.enable_pqr() => { name = "mul32"; desc = alu_reg_str(name, insn); },
ebpf::LD_1B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxb"; desc = ld_reg_str(name, insn); },
ebpf::DIV32_IMM if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_imm_str(name, insn); },
ebpf::DIV32_REG if !sbpf_version.enable_pqr() => { name = "div32"; desc = alu_reg_str(name, insn); },
ebpf::LD_2B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxh"; desc = ld_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); },
@@ -159,8 +161,10 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::RSH32_IMM => { name = "rsh32"; desc = alu_imm_str(name, insn); },
ebpf::RSH32_REG => { name = "rsh32"; desc = alu_reg_str(name, insn); },
ebpf::NEG32 if sbpf_version.enable_neg() => { name = "neg32"; desc = format!("{} r{}", name, insn.dst); },
ebpf::LD_4B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxw"; desc = ld_reg_str(name, insn); },
ebpf::MOD32_IMM if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_imm_str(name, insn); },
ebpf::MOD32_REG if !sbpf_version.enable_pqr() => { name = "mod32"; desc = alu_reg_str(name, insn); },
ebpf::LD_8B_REG if sbpf_version.move_memory_instruction_classes() => { name = "ldxdw"; desc = ld_reg_str(name, insn); },
ebpf::XOR32_IMM => { name = "xor32"; desc = alu_imm_str(name, insn); },
ebpf::XOR32_REG => { name = "xor32"; desc = alu_reg_str(name, insn); },
ebpf::MOV32_IMM => { name = "mov32"; desc = alu_imm_str(name, insn); },
@@ -176,9 +180,13 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::SUB64_IMM => { name = "sub64"; desc = alu_imm_str(name, insn); },
ebpf::SUB64_REG => { name = "sub64"; desc = alu_reg_str(name, insn); },
ebpf::MUL64_IMM if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_imm_str(name, insn); },
ebpf::ST_1B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stb"; desc = ld_st_imm_str(name, insn); },
ebpf::MUL64_REG if !sbpf_version.enable_pqr() => { name = "mul64"; desc = alu_reg_str(name, insn); },
ebpf::ST_1B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxb"; desc = st_reg_str(name, insn); },
ebpf::DIV64_IMM if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_imm_str(name, insn); },
ebpf::ST_2B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "sth"; desc = ld_st_imm_str(name, insn); },
ebpf::DIV64_REG if !sbpf_version.enable_pqr() => { name = "div64"; desc = alu_reg_str(name, insn); },
ebpf::ST_2B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxh"; desc = st_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); },
@@ -187,9 +195,13 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::LSH64_REG => { name = "lsh64"; desc = alu_reg_str(name, insn); },
ebpf::RSH64_IMM => { name = "rsh64"; desc = alu_imm_str(name, insn); },
ebpf::RSH64_REG => { name = "rsh64"; desc = alu_reg_str(name, insn); },
ebpf::ST_4B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stw"; desc = ld_st_imm_str(name, insn); },
ebpf::NEG64 if sbpf_version.enable_neg() => { name = "neg64"; desc = format!("{} r{}", name, insn.dst); },
ebpf::ST_4B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxw"; desc = st_reg_str(name, insn); },
ebpf::MOD64_IMM if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_imm_str(name, insn); },
ebpf::ST_8B_IMM if sbpf_version.move_memory_instruction_classes() => { name = "stdw"; desc = ld_st_imm_str(name, insn); },
ebpf::MOD64_REG if !sbpf_version.enable_pqr() => { name = "mod64"; desc = alu_reg_str(name, insn); },
ebpf::ST_8B_REG if sbpf_version.move_memory_instruction_classes() => { name = "stxdw"; desc = st_reg_str(name, insn); },
ebpf::XOR64_IMM => { name = "xor64"; desc = alu_imm_str(name, insn); },
ebpf::XOR64_REG => { name = "xor64"; desc = alu_reg_str(name, insn); },
ebpf::MOV64_IMM => { name = "mov64"; desc = alu_imm_str(name, insn); },
14 changes: 7 additions & 7 deletions test_utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -87,21 +87,21 @@ pub const TCP_SACK_ASM: &str = "
exit";

pub const TCP_SACK_BIN: [u8; 352] = [
0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, //
0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x55, 0x03, 0x25, 0x00, 0x08, 0x00, 0x00, 0x00, //
0x71, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x12, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x55, 0x02, 0x23, 0x00, 0x06, 0x00, 0x00, 0x00, //
0x71, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x12, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x07, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, //
0x57, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, //
0x67, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, //
0x0f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x69, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x3c, 0x14, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x07, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, //
0x77, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, //
0x57, 0x04, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, //
@@ -115,15 +115,15 @@ pub const TCP_SACK_BIN: [u8; 352] = [
0xc7, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, //
0xbf, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x0f, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x71, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x15, 0x05, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, //
0x15, 0x05, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //
0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x15, 0x05, 0x09, 0x00, 0x05, 0x00, 0x00, 0x00, //
0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x07, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, //
0xbf, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x71, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x2c, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x0f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x67, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, //
0xc7, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, //
90 changes: 18 additions & 72 deletions tests/assembler.rs
Original file line number Diff line number Diff line change
@@ -72,33 +72,6 @@ fn test_neg64() {
assert_eq!(asm("neg64 r1"), Ok(vec![insn(0, ebpf::NEG64, 1, 0, 0, 0)]));
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxw() {
assert_eq!(
asm("ldxw r1, [r2+5]"),
Ok(vec![insn(0, ebpf::LD_W_REG, 1, 2, 5, 0)])
);
}

// Example for InstructionType::StoreImm.
#[test]
fn test_stw() {
assert_eq!(
asm("stw [r2+5], 7"),
Ok(vec![insn(0, ebpf::ST_W_IMM, 2, 0, 5, 7)])
);
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxw() {
assert_eq!(
asm("stxw [r2+5], r8"),
Ok(vec![insn(0, ebpf::ST_W_REG, 2, 8, 5, 0)])
);
}

// Example for InstructionType::JumpUnconditional.
#[test]
fn test_ja() {
@@ -161,33 +134,6 @@ fn test_lddw() {
);
}

// Example for InstructionType::LoadReg.
#[test]
fn test_ldxdw() {
assert_eq!(
asm("ldxdw r1, [r2+3]"),
Ok(vec![insn(0, ebpf::LD_DW_REG, 1, 2, 3, 0)])
);
}

// Example for InstructionType::StoreImm.
#[test]
fn test_sth() {
assert_eq!(
asm("sth [r1+2], 3"),
Ok(vec![insn(0, ebpf::ST_H_IMM, 1, 0, 2, 3)])
);
}

// Example for InstructionType::StoreReg.
#[test]
fn test_stxh() {
assert_eq!(
asm("stxh [r1+2], r3"),
Ok(vec![insn(0, ebpf::ST_H_REG, 1, 3, 2, 0)])
);
}

// Test all supported AluBinary mnemonics.
#[test]
fn test_alu_binary() {
@@ -385,15 +331,15 @@ fn test_alu_unary() {
#[test]
fn test_load_reg() {
assert_eq!(
asm("ldxw r1, [r2+3]
asm("ldxb r1, [r2+3]
ldxh r1, [r2+3]
ldxb r1, [r2+3]
ldxw r1, [r2+3]
ldxdw r1, [r2+3]"),
Ok(vec![
insn(0, ebpf::LD_W_REG, 1, 2, 3, 0),
insn(1, ebpf::LD_H_REG, 1, 2, 3, 0),
insn(2, ebpf::LD_B_REG, 1, 2, 3, 0),
insn(3, ebpf::LD_DW_REG, 1, 2, 3, 0)
insn(0, ebpf::LD_1B_REG, 1, 2, 3, 0),
insn(1, ebpf::LD_2B_REG, 1, 2, 3, 0),
insn(2, ebpf::LD_4B_REG, 1, 2, 3, 0),
insn(3, ebpf::LD_8B_REG, 1, 2, 3, 0)
])
);
}
@@ -402,15 +348,15 @@ fn test_load_reg() {
#[test]
fn test_store_imm() {
assert_eq!(
asm("stw [r1+2], 3
asm("stb [r1+2], 3
sth [r1+2], 3
stb [r1+2], 3
stw [r1+2], 3
stdw [r1+2], 3"),
Ok(vec![
insn(0, ebpf::ST_W_IMM, 1, 0, 2, 3),
insn(1, ebpf::ST_H_IMM, 1, 0, 2, 3),
insn(2, ebpf::ST_B_IMM, 1, 0, 2, 3),
insn(3, ebpf::ST_DW_IMM, 1, 0, 2, 3)
insn(0, ebpf::ST_1B_IMM, 1, 0, 2, 3),
insn(1, ebpf::ST_2B_IMM, 1, 0, 2, 3),
insn(2, ebpf::ST_4B_IMM, 1, 0, 2, 3),
insn(3, ebpf::ST_8B_IMM, 1, 0, 2, 3)
])
);
}
@@ -419,15 +365,15 @@ fn test_store_imm() {
#[test]
fn test_store_reg() {
assert_eq!(
asm("stxw [r1+2], r3
asm("stxb [r1+2], r3
stxh [r1+2], r3
stxb [r1+2], r3
stxw [r1+2], r3
stxdw [r1+2], r3"),
Ok(vec![
insn(0, ebpf::ST_W_REG, 1, 3, 2, 0),
insn(1, ebpf::ST_H_REG, 1, 3, 2, 0),
insn(2, ebpf::ST_B_REG, 1, 3, 2, 0),
insn(3, ebpf::ST_DW_REG, 1, 3, 2, 0)
insn(0, ebpf::ST_1B_REG, 1, 3, 2, 0),
insn(1, ebpf::ST_2B_REG, 1, 3, 2, 0),
insn(2, ebpf::ST_4B_REG, 1, 3, 2, 0),
insn(3, ebpf::ST_8B_REG, 1, 3, 2, 0)
])
);
}