Skip to content

Commit

Permalink
Modify interpreter and jit
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasSte committed Oct 18, 2024
1 parent 95a7746 commit db7a66d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 64 deletions.
69 changes: 33 additions & 36 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

//! Interpreter for eBPF programs.
use crate::program::BuiltinFunction;
use crate::{
ebpf::{self, STACK_PTR_REG},
elf::Executable,
Expand Down Expand Up @@ -526,46 +527,34 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {

// Do not delegate the check to the verifier, since self.registered functions can be
// changed after the program has been verified.
ebpf::CALL_IMM
| ebpf::SYSCALL if insn.opc == ebpf::CALL_IMM || self.executable.get_sbpf_version().static_syscalls() => {
let mut resolved = false;
let (external, internal) = if self.executable.get_sbpf_version().static_syscalls() {
(insn.src == 0, insn.src != 0)
} else {
(true, true)
};

if external {
if let Some((_function_name, function)) = self.executable.get_loader().get_sparse_function_registry().lookup_by_key(insn.imm as u32) {
resolved = true;

self.vm.due_insn_count = self.vm.previous_instruction_meter - self.vm.due_insn_count;
self.vm.registers[0..6].copy_from_slice(&self.reg[0..6]);
self.vm.invoke_function(function);
self.vm.due_insn_count = 0;
self.reg[0] = match &self.vm.program_result {
ProgramResult::Ok(value) => *value,
ProgramResult::Err(_err) => return false,
};
}
}

if internal && !resolved {
if let Some((_function_name, target_pc)) = self.executable.get_function_registry().lookup_by_key(insn.imm as u32) {
resolved = true;

// make BPF to BPF call
if !self.push_frame(config) {
return false;
}
check_pc!(self, next_pc, target_pc as u64);
ebpf::CALL_IMM => {
if let Some((_, function)) = self.executable.get_loader().get_sparse_function_registry().lookup_by_key(insn.imm as u32) {
// SBPFv1 syscall
self.reg[0] = match self.dispatch_syscall(function) {
ProgramResult::Ok(value) => *value,
ProgramResult::Err(_err) => return false,
};
} else if let Some((_, target_pc)) = self.executable.get_function_registry().lookup_by_key(insn.imm as u32) {
// make BPF to BPF call
if !self.push_frame(config) {
return false;
}
}

if !resolved {
check_pc!(self, next_pc, target_pc as u64);
} else {
throw_error!(self, EbpfError::UnsupportedInstruction);
}
}
ebpf::SYSCALL if self.executable.get_sbpf_version().static_syscalls() => {
if let Some((_, function)) = self.executable.get_loader().get_dense_function_registry().lookup_by_key(insn.imm as u32) {
// SBPFv2 syscall
self.reg[0] = match self.dispatch_syscall(function) {
ProgramResult::Ok(value) => *value,
ProgramResult::Err(_err) => return false,
};
} else {
throw_error!(self, EbpfError::UnsupportedInstruction);
}
},
ebpf::RETURN
| ebpf::EXIT => {
if (insn.opc == ebpf::EXIT && self.executable.get_sbpf_version().static_syscalls())
Expand Down Expand Up @@ -600,4 +589,12 @@ impl<'a, 'b, C: ContextObject> Interpreter<'a, 'b, C> {
self.reg[11] = next_pc;
true
}

fn dispatch_syscall(&mut self, function: BuiltinFunction<C>) -> &ProgramResult {
self.vm.due_insn_count = self.vm.previous_instruction_meter - self.vm.due_insn_count;
self.vm.registers[0..6].copy_from_slice(&self.reg[0..6]);
self.vm.invoke_function(function);
self.vm.due_insn_count = 0;
&self.vm.program_result
}
}
57 changes: 29 additions & 28 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use rand::{
};
use std::{fmt::Debug, mem, ptr};

use crate::program::BuiltinFunction;
use crate::{
ebpf::{self, FIRST_SCRATCH_REG, FRAME_PTR_REG, INSN_SIZE, SCRATCH_REGS, STACK_PTR_REG},
elf::Executable,
Expand Down Expand Up @@ -705,37 +706,23 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
ebpf::JSLT_REG => self.emit_conditional_branch_reg(0x8c, false, src, dst, target_pc),
ebpf::JSLE_IMM => self.emit_conditional_branch_imm(0x8e, false, insn.imm, dst, target_pc),
ebpf::JSLE_REG => self.emit_conditional_branch_reg(0x8e, false, src, dst, target_pc),
ebpf::CALL_IMM | ebpf::SYSCALL
if insn.opc == ebpf::CALL_IMM || self.executable.get_sbpf_version().static_syscalls() => {
ebpf::CALL_IMM => {
// For JIT, external functions MUST be registered at compile time.

let mut resolved = false;
let (external, internal) = if self.executable.get_sbpf_version().static_syscalls() {
(insn.src == 0, insn.src != 0)
if let Some((_, function)) = self.executable.get_loader().get_sparse_function_registry().lookup_by_key(insn.imm as u32) {
// SBPFv1 syscall
self.emit_syscall_dispatch(function);
} else if let Some((_function_name, target_pc)) = self.executable.get_function_registry().lookup_by_key(insn.imm as u32) {
// BPF to BPF call
self.emit_internal_call(Value::Constant64(target_pc as i64, true));
} else {
(true, true)
};

if external {
if let Some((_function_name, function)) = self.executable.get_loader().get_sparse_function_registry().lookup_by_key(insn.imm as u32) {
self.emit_validate_and_profile_instruction_count(false, Some(0));
self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, REGISTER_SCRATCH, function as usize as i64));
self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_EXTERNAL_FUNCTION_CALL, 5)));
self.emit_undo_profile_instruction_count(0);
resolved = true;
}
}

if internal {
if let Some((_function_name, target_pc)) = self.executable.get_function_registry().lookup_by_key(insn.imm as u32) {
self.emit_internal_call(Value::Constant64(target_pc as i64, true));
resolved = true;
}
self.emit_throw_unsupported_instruction();
}

if !resolved {
self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, REGISTER_SCRATCH, self.pc as i64));
self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_CALL_UNSUPPORTED_INSTRUCTION, 5)));
},
ebpf::SYSCALL if self.executable.get_sbpf_version().static_syscalls() => {
if let Some((_, function)) = self.executable.get_loader().get_dense_function_registry().lookup_by_key(insn.imm as u32) {
self.emit_syscall_dispatch(function);
} else {
self.emit_throw_unsupported_instruction();
}
},
ebpf::CALL_REG => {
Expand Down Expand Up @@ -1135,6 +1122,20 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
}
}

#[inline]
fn emit_syscall_dispatch(&mut self, function: BuiltinFunction<C>) {
self.emit_validate_and_profile_instruction_count(false, Some(0));
self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, REGISTER_SCRATCH, function as usize as i64));
self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_EXTERNAL_FUNCTION_CALL, 5)));
self.emit_undo_profile_instruction_count(0);
}

#[inline]
fn emit_throw_unsupported_instruction(&mut self) {
self.emit_ins(X86Instruction::load_immediate(OperandSize::S64, REGISTER_SCRATCH, self.pc as i64));
self.emit_ins(X86Instruction::jump_immediate(self.relative_to_anchor(ANCHOR_CALL_UNSUPPORTED_INSTRUCTION, 5)));
}

#[inline]
fn emit_address_translation(&mut self, dst: Option<u8>, vm_addr: Value, len: u64, value: Option<Value>) {
debug_assert_ne!(dst.is_some(), value.is_some());
Expand Down

0 comments on commit db7a66d

Please sign in to comment.