Przeglądaj źródła

cranelift: Add complete Cranelift API

Signed-off-by: Afonso Bordado <afonsobordado@az8.co>
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Afonso Bordado 1 rok temu
rodzic
commit
fa5a4fd90e
3 zmienionych plików z 344 dodań i 44 usunięć
  1. 2 1
      examples/rbpf_plugin.rs
  2. 305 19
      src/lib.rs
  3. 37 24
      tests/cranelift.rs

+ 2 - 1
examples/rbpf_plugin.rs

@@ -109,7 +109,8 @@ fn main() {
             return;
         }
         #[cfg(feature = "cranelift")] {
-            result = vm.execute_cranelift(&mut memory).unwrap();
+            vm.cranelift_compile().unwrap();
+            result = vm.execute_program_cranelift(&mut memory).unwrap();
         }
     }
     else {

+ 305 - 19
src/lib.rs

@@ -120,6 +120,8 @@ pub struct EbpfVmMbuff<'a> {
     verifier: Verifier,
     #[cfg(not(windows))]
     jit: Option<jit::JitMemory<'a>>,
+    #[cfg(feature = "cranelift")]
+    cranelift_prog: Option<cranelift::CraneliftProgram>,
     helpers: HashMap<u32, ebpf::Helper>,
 }
 
@@ -149,6 +151,8 @@ impl<'a> EbpfVmMbuff<'a> {
             verifier: verifier::check,
             #[cfg(not(windows))]
             jit: None,
+            #[cfg(feature = "cranelift")]
+            cranelift_prog: None,
             helpers: HashMap::new(),
         })
     }
@@ -413,9 +417,27 @@ impl<'a> EbpfVmMbuff<'a> {
         }
     }
 
-    /// Compiles and executes the program using the cranelift JIT.
+    /// Compile the loaded program using the Cranelift JIT.
+    ///
+    /// If using helper functions, be sure to register them into the VM before calling this
+    /// function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into R1.
+    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// // Instantiate a VM.
+    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    /// ```
     #[cfg(feature = "cranelift")]
-    pub fn execute_cranelift(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> Result<u64, Error> {
+    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
         use crate::cranelift::CraneliftCompiler;
 
         let prog = match self.prog {
@@ -426,6 +448,59 @@ impl<'a> EbpfVmMbuff<'a> {
             ))?,
         };
 
+        let mut compiler = CraneliftCompiler::new(self.helpers.clone());
+        let program = compiler.compile_function(prog)?;
+
+        self.cranelift_prog = Some(program);
+        Ok(())
+    }
+
+    /// Execute the previously compiled program, with the given packet data and metadata
+    /// buffer, in a manner very similar to `execute_program()`.
+    ///
+    /// If the program is made to be compatible with Linux kernel, it is expected to load the
+    /// address of the beginning and of the end of the memory area used for packet data from the
+    /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
+    /// pointers are correctly stored in the buffer.
+    ///
+    ///
+    /// # Examples
+    ///
+    /// ```ignore
+    /// let prog = &[
+    ///     0x79, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // Load mem from mbuff into r1.
+    ///     0x69, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, // ldhx r1[2], r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    /// let mem = &mut [
+    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
+    /// ];
+    ///
+    /// // Just for the example we create our metadata buffer from scratch, and we store the
+    /// // pointers to packet data start and end in it.
+    /// let mut mbuff = [0u8; 32];
+    /// unsafe {
+    ///     let mut data     = mbuff.as_ptr().offset(8)  as *mut u64;
+    ///     let mut data_end = mbuff.as_ptr().offset(24) as *mut u64;
+    ///     *data     = mem.as_ptr() as u64;
+    ///     *data_end = mem.as_ptr() as u64 + mem.len() as u64;
+    /// }
+    ///
+    /// // Instantiate a VM.
+    /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    ///
+    /// // Provide both a reference to the packet data, and to the metadata buffer.
+    /// let res = vm.execute_program_cranelift(mem, &mut mbuff).unwrap();
+    /// assert_eq!(res, 0x2211);
+    /// ```
+    #[cfg(feature = "cranelift")]
+    pub fn execute_program_cranelift(
+        &self,
+        mem: &mut [u8],
+        mbuff: &'a mut [u8],
+    ) -> Result<u64, Error> {
         // If packet data is empty, do not send the address of an empty slice; send a null pointer
         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
@@ -435,19 +510,23 @@ impl<'a> EbpfVmMbuff<'a> {
             _ => mem.as_ptr() as *mut u8,
         };
 
-        let mut compiler = CraneliftCompiler::new(self.helpers.clone());
-
-        let module = compiler.compile_function(prog)?;
-        let res = module.execute(
-            mem_ptr,
-            mem.len(),
-            mbuff.as_ptr() as *mut u8,
-            mbuff.len(),
-            0,
-            0,
-        );
-
-        Ok(res)
+        // The last two arguments are not used in this function. They would be used if there was a
+        // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
+        // should be stored; this is what happens with struct EbpfVmFixedMbuff.
+        match &self.cranelift_prog {
+            Some(prog) => Ok(prog.execute(
+                mem_ptr,
+                mem.len(),
+                mbuff.as_ptr() as *mut u8,
+                mbuff.len(),
+                0,
+                0,
+            )),
+            None => Err(Error::new(
+                ErrorKind::Other,
+                "Error: program has not been compiled with cranelift",
+            )),
+        }
     }
 }
 
@@ -848,6 +927,108 @@ impl<'a> EbpfVmFixedMbuff<'a> {
             )),
         }
     }
+
+    /// Compile the loaded program using the Cranelift JIT.
+    ///
+    /// If using helper functions, be sure to register them into the VM before calling this
+    /// function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
+    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
+    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
+    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
+    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
+    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
+    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    /// ```
+    #[cfg(feature = "cranelift")]
+    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
+        use crate::cranelift::CraneliftCompiler;
+
+        let prog = match self.parent.prog {
+            Some(prog) => prog,
+            None => Err(Error::new(
+                ErrorKind::Other,
+                "Error: No program set, call prog_set() to load one",
+            ))?,
+        };
+
+        let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
+        let program = compiler.compile_function(prog)?;
+
+        self.parent.cranelift_prog = Some(program);
+        Ok(())
+    }
+
+    /// Execute the previously compiled program, with the given packet data and metadata
+    /// buffer, in a manner very similar to `execute_program()`.
+    ///
+    /// If the program is made to be compatible with Linux kernel, it is expected to load the
+    /// address of the beginning and of the end of the memory area used for packet data from some
+    /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
+    /// the addresses should be placed should have be set at the creation of the VM.
+    ///
+    /// # Examples
+    ///
+    /// ```ignore
+    /// let prog = &[
+    ///     0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
+    ///     0x79, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem from r1[0x40] to r2
+    ///     0x07, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // add r2, 5
+    ///     0x79, 0x11, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, // load mem_end from r1[0x50] to r1
+    ///     0x2d, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // if r2 > r1 skip 3 instructions
+    ///     0x71, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // load r2 (= *(mem + 5)) into r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    /// let mem = &mut [
+    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
+    /// ];
+    ///
+    /// // Instantiate a VM. Note that we provide the start and end offsets for mem pointers.
+    /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    ///
+    /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
+    /// let res = vm.execute_program_cranelift(mem).unwrap();
+    /// assert_eq!(res, 0xdd);
+    /// ```
+    #[cfg(feature = "cranelift")]
+    pub fn execute_program_cranelift(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
+        // If packet data is empty, do not send the address of an empty slice; send a null pointer
+        //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
+        //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
+        //  See `mul_loop` test.
+        let mem_ptr = match mem.len() {
+            0 => std::ptr::null_mut(),
+            _ => mem.as_ptr() as *mut u8,
+        };
+
+        match &self.parent.cranelift_prog {
+            Some(prog) => Ok(prog.execute(
+                mem_ptr,
+                mem.len(),
+                self.mbuff.buffer.as_ptr() as *mut u8,
+                self.mbuff.buffer.len(),
+                self.mbuff.data_offset,
+                self.mbuff.data_end_offset,
+            )),
+            None => Err(Error::new(
+                ErrorKind::Other,
+                "Error: program has not been compiled with cranelift",
+            )),
+        }
+    }
 }
 
 /// A virtual machine to run eBPF program. This kind of VM is used for programs expecting to work
@@ -1112,10 +1293,72 @@ impl<'a> EbpfVmRaw<'a> {
         self.parent.execute_program_jit(mem, &mut mbuff)
     }
 
+    /// Compile the loaded program using the Cranelift JIT.
+    ///
+    /// If using helper functions, be sure to register them into the VM before calling this
+    /// function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
+    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
+    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    /// ```
+    #[cfg(feature = "cranelift")]
+    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
+        use crate::cranelift::CraneliftCompiler;
+
+        let prog = match self.parent.prog {
+            Some(prog) => prog,
+            None => Err(Error::new(
+                ErrorKind::Other,
+                "Error: No program set, call prog_set() to load one",
+            ))?,
+        };
+
+        let mut compiler = CraneliftCompiler::new(self.parent.helpers.clone());
+        let program = compiler.compile_function(prog)?;
+
+        self.parent.cranelift_prog = Some(program);
+        Ok(())
+    }
+
+    /// Execute the previously compiled program, with the given packet data, in a manner very
+    /// similar to `execute_program()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0x71, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, // ldxb r1[0x04], r1
+    ///     0x07, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, // add r1, 0x22
+    ///     0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, r1
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// let mem = &mut [
+    ///     0xaa, 0xbb, 0x11, 0x22, 0xcc, 0x27
+    /// ];
+    ///
+    /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    ///
+    /// let res = vm.execute_program_cranelift(mem).unwrap();
+    /// assert_eq!(res, 0x22cc);
+    /// ```
     #[cfg(feature = "cranelift")]
-    pub fn execute_cranelift(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
+    pub fn execute_program_cranelift(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
         let mut mbuff = vec![];
-        self.parent.execute_cranelift(mem, &mut mbuff)
+        self.parent.execute_program_cranelift(mem, &mut mbuff)
     }
 }
 
@@ -1367,8 +1610,51 @@ impl<'a> EbpfVmNoData<'a> {
         self.parent.execute_program_jit(&mut [])
     }
 
+    /// Compile the loaded program using the Cranelift JIT.
+    ///
+    /// If using helper functions, be sure to register them into the VM before calling this
+    /// function.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
+    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
+    ///
+    ///
+    /// vm.cranelift_compile();
+    /// ```
+    #[cfg(feature = "cranelift")]
+    pub fn cranelift_compile(&mut self) -> Result<(), Error> {
+        self.parent.cranelift_compile()
+    }
+
+    /// Execute the previously JIT-compiled program, without providing pointers to any memory area
+    /// whatsoever, in a manner very similar to `execute_program()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let prog = &[
+    ///     0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
+    ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
+    ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
+    /// ];
+    ///
+    /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
+    ///
+    /// vm.cranelift_compile();
+    ///
+    /// let res = vm.execute_program_cranelift().unwrap();
+    /// assert_eq!(res, 0x1122);
+    /// ```
     #[cfg(feature = "cranelift")]
-    pub fn execute_cranelift(&self) -> Result<u64, Error> {
-        self.parent.execute_cranelift(&mut [])
+    pub fn execute_program_cranelift(&self) -> Result<u64, Error> {
+        self.parent.execute_program_cranelift(&mut [])
     }
 }

+ 37 - 24
tests/cranelift.rs

@@ -15,8 +15,9 @@ macro_rules! test_cranelift {
         #[test]
         fn $name() {
             let prog = assemble($prog).unwrap();
-            let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-            assert_eq!(vm.execute_cranelift().unwrap(), $expected);
+            let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
+            vm.cranelift_compile().unwrap();
+            assert_eq!(vm.execute_program_cranelift().unwrap(), $expected);
         }
     };
     ($name:ident, $prog:expr, $mem:expr, $expected:expr) => {
@@ -24,8 +25,9 @@ macro_rules! test_cranelift {
         fn $name() {
             let prog = assemble($prog).unwrap();
             let mem = &mut $mem;
-            let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-            assert_eq!(vm.execute_cranelift(mem).unwrap(), $expected);
+            let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
+            vm.cranelift_compile().unwrap();
+            assert_eq!(vm.execute_program_cranelift(mem).unwrap(), $expected);
         }
     };
 }
@@ -270,7 +272,8 @@ fn test_cranelift_call() {
 
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
     vm.register_helper(0, helpers::gather_bytes).unwrap();
-    assert_eq!(vm.execute_cranelift().unwrap(), 0x0102030405);
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x0102030405);
 }
 
 #[test]
@@ -285,8 +288,8 @@ fn test_cranelift_err_call_unreg() {
          call 63
          exit
     ").unwrap();
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_cranelift().unwrap();
+    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
+    vm.cranelift_compile().unwrap();
 }
 
 #[test]
@@ -306,7 +309,8 @@ fn test_cranelift_call_memfrob() {
     let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
     vm.register_helper(1, helpers::memfrob).unwrap();
     let mem = &mut [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
-    assert_eq!(vm.execute_cranelift(mem).unwrap(), 0x102292e2f2c0708);
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x102292e2f2c0708);
 }
 
 test_cranelift!(
@@ -467,8 +471,9 @@ fn test_cranelift_err_stack_out_of_bound() {
         0x72, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
         0x00,
     ];
-    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.execute_cranelift().unwrap();
+    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    vm.execute_program_cranelift().unwrap();
 }
 
 test_cranelift!(
@@ -1766,7 +1771,8 @@ fn test_cranelift_stack2() {
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
     vm.register_helper(0, helpers::gather_bytes).unwrap();
     vm.register_helper(1, helpers::memfrob).unwrap();
-    assert_eq!(vm.execute_cranelift().unwrap(), 0x01020304);
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x01020304);
 }
 
 test_cranelift!(
@@ -1840,7 +1846,8 @@ fn test_cranelift_string_stack() {
 
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
     vm.register_helper(4, helpers::strcmp).unwrap();
-    assert_eq!(vm.execute_cranelift().unwrap(), 0x0);
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift().unwrap(), 0x0);
 }
 
 test_cranelift!(
@@ -2029,8 +2036,9 @@ fn test_cranelift_tcp_port80_match() {
         0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
     ];
     let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem).unwrap(), 0x1);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x1);
 }
 
 #[test]
@@ -2045,8 +2053,9 @@ fn test_cranelift_tcp_port80_nomatch() {
         0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
     ];
     let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem).unwrap(), 0x0);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
 }
 
 #[test]
@@ -2061,8 +2070,9 @@ fn test_cranelift_tcp_port80_nomatch_ethertype() {
         0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
     ];
     let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem).unwrap(), 0x0);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
 }
 
 #[test]
@@ -2077,22 +2087,25 @@ fn test_cranelift_tcp_port80_nomatch_proto() {
         0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
     ];
     let prog = &PROG_TCP_PORT_80;
-    let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem).unwrap(), 0x0);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem).unwrap(), 0x0);
 }
 
 #[test]
 fn test_cranelift_tcp_sack_match() {
     let mut mem = TCP_SACK_MATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem.as_mut_slice()).unwrap(), 0x1);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem.as_mut_slice()).unwrap(), 0x1);
 }
 
 #[test]
 fn test_cranelift_tcp_sack_nomatch() {
     let mut mem = TCP_SACK_NOMATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();
-    let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.execute_cranelift(mem.as_mut_slice()).unwrap(), 0x0);
+    let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
+    vm.cranelift_compile().unwrap();
+    assert_eq!(vm.execute_program_cranelift(mem.as_mut_slice()).unwrap(), 0x0);
 }