1use {
2 crate::errors::{RuntimeError, RuntimeResult},
3 either::Either,
4 sbpf_common::{inst_param::Number, instruction::Instruction, opcode::Opcode},
5 sbpf_disassembler::{
6 program::{Disassembly, Parsed, Program},
7 rodata::RodataSection,
8 },
9 sbpf_vm::memory::Memory,
10};
11
12pub fn load_elf(elf_bytes: &[u8]) -> RuntimeResult<(Vec<Instruction>, Vec<u8>, usize)> {
14 let program = Program::from_bytes(elf_bytes)
15 .map_err(|e| RuntimeError::ElfParseError(format!("{:?}", e)))?;
16
17 let Disassembly {
18 instructions,
19 rodata: rodata_section,
20 entrypoint: entrypoint_idx,
21 } = program
22 .to_ixs()
23 .and_then(Parsed::into_strict)
24 .map_err(|e| RuntimeError::ElfParseError(format!("{:?}", e)))?;
25 let entrypoint = entrypoint_idx.unwrap_or(0);
26
27 let mut instructions: Vec<Instruction> = instructions
29 .into_iter()
30 .map(|ix| ix.expect_left("strict disassembly contains no decode errors"))
31 .collect();
32
33 let mut rodata = rodata_section
34 .as_ref()
35 .map(|s| s.data.clone())
36 .unwrap_or_default();
37
38 if let Some(ref section) = rodata_section {
39 apply_relocations(&mut instructions, &mut rodata, section);
40 }
41
42 Ok((instructions, rodata, entrypoint))
43}
44
45fn apply_relocations(instructions: &mut [Instruction], rodata: &mut [u8], section: &RodataSection) {
47 let elf_base = section.base_address;
48 let elf_end = elf_base + section.data.len() as u64;
49
50 if elf_base != Memory::RODATA_START {
52 for ix in instructions.iter_mut() {
53 if ix.opcode == Opcode::Lddw
54 && let Some(Either::Right(Number::Int(imm))) = &ix.imm
55 {
56 let addr = *imm as u64;
57 if addr >= elf_base && addr < elf_end {
58 ix.imm = Some(Either::Right(Number::Int(
59 (Memory::RODATA_START + addr - elf_base) as i64,
60 )));
61 }
62 }
63 }
64 }
65
66 for &offset in §ion.data_relocations {
68 if offset + 8 <= rodata.len() {
69 let ptr = u64::from_le_bytes(rodata[offset..offset + 8].try_into().unwrap());
70 if ptr >= elf_base && ptr < elf_end {
71 let relocated = Memory::RODATA_START + (ptr - elf_base);
72 rodata[offset..offset + 8].copy_from_slice(&relocated.to_le_bytes());
73 }
74 }
75 }
76
77 for &(offset, ix_idx) in §ion.text_relocations {
79 if offset + 8 <= rodata.len() {
80 rodata[offset..offset + 8].copy_from_slice(&(ix_idx as u64).to_le_bytes());
81 }
82 }
83}