diff --git a/benches/jit_compile.rs b/benches/jit_compile.rs index d4524e66..2c38f5b1 100644 --- a/benches/jit_compile.rs +++ b/benches/jit_compile.rs @@ -47,5 +47,7 @@ fn bench_jit_compile(bencher: &mut Bencher) { SyscallRegistry::default(), ) .unwrap(); - bencher.iter(|| executable.jit_compile().unwrap()); + bencher.iter(|| { + Executable::::jit_compile(&mut executable).unwrap() + }); } diff --git a/benches/vm_execution.rs b/benches/vm_execution.rs index 81232616..1ea9ae6d 100644 --- a/benches/vm_execution.rs +++ b/benches/vm_execution.rs @@ -50,7 +50,7 @@ fn bench_init_jit_execution(bencher: &mut Bencher) { SyscallRegistry::default(), ) .unwrap(); - executable.jit_compile().unwrap(); + Executable::::jit_compile(&mut executable).unwrap(); let mut vm = EbpfVm::::new(&executable, &mut [], &mut []).unwrap(); bencher.iter(|| { @@ -73,7 +73,7 @@ fn bench_jit_vs_interpreter( SyscallRegistry::default(), ) .unwrap(); - executable.jit_compile().unwrap(); + Executable::::jit_compile(&mut executable).unwrap(); let mut vm = EbpfVm::new(&executable, &mut [], mem).unwrap(); let interpreter_summary = bencher .bench(|bencher| { diff --git a/cli/src/main.rs b/cli/src/main.rs index b2700d2c..699154eb 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -153,7 +153,7 @@ fn main() { } } .unwrap(); - executable.jit_compile().unwrap(); + Executable::::jit_compile(&mut executable).unwrap(); let analysis = Analysis::from_executable(&executable); match matches.value_of("use") { diff --git a/examples/uptime.rs b/examples/uptime.rs index 34fd8375..9e21a822 100644 --- a/examples/uptime.rs +++ b/examples/uptime.rs @@ -86,7 +86,7 @@ fn main() { .unwrap(); #[cfg(not(windows))] { - executable.jit_compile().unwrap(); + Executable::::jit_compile(&mut executable).unwrap(); } let mut vm = EbpfVm::::new(&executable, &mut [], &mut []).unwrap(); diff --git a/src/assembler.rs b/src/assembler.rs index d149f1ad..8851d26c 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -22,7 +22,10 @@ use crate::{ error::UserDefinedError, vm::{Config, InstructionMeter, SyscallRegistry, Verifier}, }; -use std::collections::{BTreeMap, HashMap}; +use std::{ + collections::{BTreeMap, HashMap}, + pin::Pin, +}; #[derive(Clone, Copy, Debug, PartialEq)] enum InstructionType { @@ -217,7 +220,7 @@ pub fn assemble( verifier: Option, config: Config, syscall_registry: SyscallRegistry, -) -> Result, String> { +) -> Result>>, String> { fn resolve_label( insn_ptr: usize, labels: &HashMap<&str, usize>, diff --git a/src/elf.rs b/src/elf.rs index 13c06cc5..23a339b7 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -21,7 +21,7 @@ use goblin::{ elf::{header::*, reloc::*, section_header::*, Elf}, error::Error as GoblinError, }; -use std::{collections::BTreeMap, fmt::Debug, mem, ops::Range, str}; +use std::{collections::BTreeMap, fmt::Debug, mem, ops::Range, pin::Pin, str}; /// Error definitions #[derive(Debug, thiserror::Error, PartialEq, Eq)] @@ -285,8 +285,9 @@ impl Executable { } /// JIT compile the executable - pub fn jit_compile(&mut self) -> Result<(), EbpfError> { - self.compiled_program = Some(JitProgram::::new(self)?); + pub fn jit_compile(executable: &mut Pin>) -> Result<(), EbpfError> { + // TODO: Turn back to `executable: &mut self` once Self::report_unresolved_symbol() is gone + executable.compiled_program = Some(JitProgram::::new(executable)?); Ok(()) } diff --git a/src/jit.rs b/src/jit.rs index 9499a4ee..cec51c7d 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -15,12 +15,13 @@ extern crate libc; -use std::fmt::Debug; -use std::mem; -use std::collections::HashMap; -use std::fmt::Formatter; -use std::fmt::Error as FormatterError; -use std::ops::{Index, IndexMut}; +use std::{ + collections::HashMap, + fmt::{Debug, Error as FormatterError, Formatter}, + mem, + ops::{Index, IndexMut}, + pin::Pin, +}; use rand::{rngs::SmallRng, Rng, SeedableRng}; use crate::{ @@ -147,7 +148,7 @@ impl PartialEq for JitProgram { } impl JitProgram { - pub fn new(executable: &Executable) -> Result> { + pub fn new(executable: &Pin>>) -> Result> { let program = executable.get_text_bytes().1; let mut jit = JitCompiler::new::(program, executable.get_config())?; jit.compile::(executable)?; @@ -979,7 +980,7 @@ impl JitCompiler { } fn compile(&mut self, - executable: &Executable) -> Result<(), EbpfError> { + executable: &Pin>>) -> Result<(), EbpfError> { let (program_vm_addr, program) = executable.get_text_bytes(); self.program_vm_addr = program_vm_addr; @@ -1300,7 +1301,7 @@ impl JitCompiler { // Workaround for unresolved symbols in ELF: Report error at runtime instead of compiletime emit_rust_call(self, Executable::::report_unresolved_symbol as *const _, &[ Argument { index: 2, value: Value::Constant64(self.pc as i64, false) }, - Argument { index: 1, value: Value::Constant64(executable as *const _ as i64, false) }, + Argument { index: 1, value: Value::Constant64(&*executable.as_ref() as *const _ as i64, false) }, Argument { index: 0, value: Value::RegisterIndirect(RBP, slot_on_environment_stack(self, EnvironmentStackSlot::OptRetValPtr), false) }, ], None, true)?; X86Instruction::load_immediate(OperandSize::S64, R11, self.pc as i64).emit(self)?; diff --git a/src/vm.rs b/src/vm.rs index 3dbfbd4b..b327c92b 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -27,6 +27,7 @@ use log::debug; use std::{ collections::{BTreeMap, HashMap}, fmt::Debug, + pin::Pin, u32, }; @@ -240,13 +241,12 @@ impl Executable { verifier: Option, config: Config, syscall_registry: SyscallRegistry, - ) -> Result> { - let ebpf_elf = Executable::load(config, elf_bytes, syscall_registry)?; - let text_bytes = ebpf_elf.get_text_bytes().1; + ) -> Result>, EbpfError> { + let executable = Executable::load(config, elf_bytes, syscall_registry)?; if let Some(verifier) = verifier { - verifier(text_bytes, &config)?; + verifier(executable.get_text_bytes().1, &config)?; } - Ok(ebpf_elf) + Ok(Pin::new(Box::new(executable))) } /// Creates a verified executable from machine code pub fn from_text_bytes( @@ -255,16 +255,16 @@ impl Executable { config: Config, syscall_registry: SyscallRegistry, bpf_functions: BTreeMap, - ) -> Result> { + ) -> Result>, EbpfError> { if let Some(verifier) = verifier { verifier(text_bytes, &config).map_err(EbpfError::VerifierError)?; } - Ok(Executable::new_from_text_bytes( + Ok(Pin::new(Box::new(Executable::new_from_text_bytes( config, text_bytes, syscall_registry, bpf_functions, - )) + )))) } } @@ -480,7 +480,7 @@ impl<'a, E: UserDefinedError, I: InstructionMeter> EbpfVm<'a, E, I> { /// let mut vm = EbpfVm::::new(&executable, &mut [], &mut []).unwrap(); /// ``` pub fn new( - executable: &'a Executable, + executable: &'a Pin>>, heap_region: &mut [u8], input_region: &mut [u8], ) -> Result, EbpfError> { diff --git a/tests/ubpf_execution.rs b/tests/ubpf_execution.rs index f385e981..917e0564 100644 --- a/tests/ubpf_execution.rs +++ b/tests/ubpf_execution.rs @@ -46,7 +46,7 @@ macro_rules! test_interpreter_and_jit { #[cfg(all(not(windows), target_arch = "x86_64"))] { let check_closure = $check; - let compilation_result = $executable.jit_compile(); + let compilation_result = Executable::::jit_compile(&mut $executable); let mut mem = $mem; let mut vm = EbpfVm::new(&$executable, &mut [], &mut mem).unwrap(); match compilation_result { @@ -2737,7 +2737,8 @@ impl SyscallObject for NestedVmSyscall { .unwrap(); #[cfg(all(not(windows), target_arch = "x86_64"))] { - executable.jit_compile().unwrap(); + Executable::::jit_compile(&mut executable) + .unwrap(); } let mut vm = EbpfVm::new(&executable, &mut [], mem).unwrap(); vm.bind_syscall_context_object(Box::new(NestedVmSyscall {}), None) @@ -3412,7 +3413,7 @@ fn execute_generated_program(prog: &[u8]) -> bool { } else { return false; }; - if executable.jit_compile().is_err() { + if Executable::::jit_compile(&mut executable).is_err() { return false; } let (instruction_count_interpreter, tracer_interpreter, result_interpreter) = {