summaryrefslogtreecommitdiff
path: root/src/execload.rs
diff options
context:
space:
mode:
authortaitep <taitep@taitep.se>2025-12-23 19:56:42 +0100
committertaitep <taitep@taitep.se>2025-12-23 19:56:42 +0100
commit8ed4845d587eff7ba0252bedf34f98de8802153d (patch)
tree56c6140eaddffef52802461ca435aeda001348e4 /src/execload.rs
parent36faa1e39c8675a84d7b7762d17e14640e991907 (diff)
ADD ELF SUPPORT
Diffstat (limited to 'src/execload.rs')
-rw-r--r--src/execload.rs67
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"),
+ }
+}