diff options
Diffstat (limited to 'src/execload.rs')
| -rw-r--r-- | src/execload.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/execload.rs b/src/execload.rs new file mode 100644 index 0000000..12fe90d --- /dev/null +++ b/src/execload.rs @@ -0,0 +1,67 @@ +// Copyright (c) 2025 taitep +// SPDX-License-Identifier: MIT +// +// This file is part of TRVE (https://gitea.taitep.se/taitep/trve) +// See LICENSE file in the project root for full license text. + +use std::{fs, path::Path}; + +use anyhow::{Result, bail}; +use goblin::{ + Object, + elf::{ + header::{EM_RISCV, ET_EXEC}, + program_header::PT_LOAD, + }, +}; +use trve::consts::Addr; + +pub fn load<P: AsRef<Path>>(path: P, ram: &mut [u8], ram_start: Addr) -> Result<Addr> { + let buf = fs::read(path)?; + + match Object::parse(&buf)? { + Object::Elf(elf) => { + if elf.header.e_type != ET_EXEC { + bail!("Executable type incorrect, may not be an executable or may be dynamic"); + } + if elf.header.e_machine != EM_RISCV { + bail!("Executable architecture is not RISC-V"); + } + if !elf.is_64 { + bail!("Executable is not 64-bit"); + } + if !elf.little_endian { + bail!("Executable is not little-endian"); + } + + for ph in elf.program_headers { + if ph.p_type == PT_LOAD { + let start = (ph.p_vaddr - ram_start) as usize; + let end = start + ph.p_memsz as usize; + let file_end = start + ph.p_filesz as usize; + + if end > ram_start as usize + ram.len() { + bail!("Segment at 0x{:x} does not fit in RAM", ph.p_vaddr); + } + + ram[start..file_end].copy_from_slice( + &buf[ph.p_offset as usize..(ph.p_offset + ph.p_filesz) as usize], + ); + + ram[file_end..end].fill(0); + } + } + + Ok(elf.entry) + } + Object::Unknown(_) => { + eprintln!("Unrecognized executable format identifier, assuming raw binary"); + if buf.len() > ram.len() { + bail!("Program too large for RAM"); + } + ram[..buf.len()].copy_from_slice(&buf); + Ok(ram_start) + } + _ => bail!("Unsupported executable format"), + } +} |
