Prechádzať zdrojové kódy

cranelift: Implement IND and ABS load instructions

Signed-off-by: Afonso Bordado <afonsobordado@az8.co>
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Afonso Bordado 1 rok pred
rodič
commit
8b287dd46a
2 zmenil súbory, kde vykonal 189 pridanie a 1 odobranie
  1. 48 1
      src/cranelift.rs
  2. 141 0
      tests/cranelift.rs

+ 48 - 1
src/cranelift.rs

@@ -25,7 +25,7 @@ use cranelift_module::{FuncId, Linkage, Module};
 
 use crate::ebpf::{
     self, Insn, BPF_ALU_OP_MASK, BPF_JEQ, BPF_JGE, BPF_JGT, BPF_JLE, BPF_JLT, BPF_JMP32, BPF_JNE,
-    BPF_JSET, BPF_JSGE, BPF_JSGT, BPF_JSLE, BPF_JSLT, BPF_X, STACK_SIZE,
+    BPF_JSET, BPF_JSGE, BPF_JSGT, BPF_JSLE, BPF_JSLT, BPF_X, STACK_SIZE, BPF_IND,
 };
 
 use super::Error;
@@ -272,6 +272,53 @@ impl CraneliftCompiler {
             bcx.set_srcloc(SourceLoc::new(insn_ptr as u32));
 
             match insn.opc {
+                // BPF_LD class
+                // LD_ABS_* and LD_IND_* are supposed to load pointer to data from metadata buffer.
+                // Since this pointer is constant, and since we already know it (mem), do not
+                // bother re-fetching it, just use mem already.
+                ebpf::LD_ABS_B
+                | ebpf::LD_ABS_H
+                | ebpf::LD_ABS_W
+                | ebpf::LD_ABS_DW
+                | ebpf::LD_IND_B
+                | ebpf::LD_IND_H
+                | ebpf::LD_IND_W
+                | ebpf::LD_IND_DW => {
+                    let ty = match insn.opc {
+                        ebpf::LD_ABS_B | ebpf::LD_IND_B => I8,
+                        ebpf::LD_ABS_H | ebpf::LD_IND_H => I16,
+                        ebpf::LD_ABS_W | ebpf::LD_IND_W => I32,
+                        ebpf::LD_ABS_DW | ebpf::LD_IND_DW => I64,
+                        _ => unreachable!(),
+                    };
+
+                    // Both instructions add the imm part of the instruction to the pointer
+                    let ptr = bcx.use_var(self.mem_start);
+                    let offset = bcx
+                        .ins()
+                        .iconst(self.isa.pointer_type(), insn.imm as u32 as i64);
+                    let addr = bcx.ins().iadd(ptr, offset);
+
+                    // IND instructions additionally add the value of the source register
+                    let is_ind = (insn.opc & BPF_IND) != 0;
+                    let addr = if is_ind {
+                        let src_reg = self.insn_src(bcx, &insn);
+                        bcx.ins().iadd(addr, src_reg)
+                    } else {
+                        addr
+                    };
+
+                    // The offset here has already been added to the pointer, so we pass 0
+                    let loaded = self.reg_load(bcx, ty, addr, 0);
+
+                    let ext = if ty != I64 {
+                        bcx.ins().uextend(I64, loaded)
+                    } else {
+                        loaded
+                    };
+
+                    self.set_dst(bcx, &insn, ext);
+                }
                 ebpf::LD_DW_IMM => {
                     insn_ptr += 1;
                     let next_insn = ebpf::get_insn(prog, insn_ptr);

+ 141 - 0
tests/cranelift.rs

@@ -2109,3 +2109,144 @@ fn test_cranelift_tcp_sack_nomatch() {
     vm.cranelift_compile().unwrap();
     assert_eq!(vm.execute_program_cranelift(mem.as_mut_slice()).unwrap(), 0x0);
 }
+
+
+#[test]
+fn test_cranelift_ldabsb() {
+    let prog = &[
+        0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x33);
+
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x33);
+}
+
+#[test]
+fn test_cranelift_ldabsh() {
+    let prog = &[
+        0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x4433);
+
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x4433);
+}
+
+#[test]
+fn test_cranelift_ldabsw() {
+    let prog = &[
+        0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x66554433);
+    vm.cranelift_compile().unwrap();
+
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x66554433);
+}
+
+#[test]
+fn test_cranelift_ldabsdw() {
+    let prog = &[
+        0x38, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0xaa99887766554433);
+    vm.cranelift_compile().unwrap();
+
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0xaa99887766554433);
+}
+
+#[test]
+fn test_cranelift_ldindb() {
+    let prog = &[
+        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+        0x50, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x88);
+
+    vm.cranelift_compile().unwrap();
+        assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x88);
+}
+
+#[test]
+fn test_cranelift_ldindh() {
+    let prog = &[
+        0xb7, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+        0x48, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x9988);
+
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x9988);
+}
+
+#[test]
+fn test_cranelift_ldindw() {
+    let prog = &[
+        0xb7, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+        0x40, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0x88776655);
+    vm.cranelift_compile().unwrap();
+
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x88776655);
+}
+
+#[test]
+fn test_cranelift_ldinddw() {
+    let prog = &[
+        0xb7, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+        0x58, 0x10, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+    ];
+    let mem = &mut [
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+    ];
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    assert_eq!(vm.execute_program(mem).unwrap(), 0xccbbaa9988776655);
+    vm.cranelift_compile().unwrap();
+
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0xccbbaa9988776655);
+}