Parse ELF exclusively on emulation thread

This commit is contained in:
2025-08-30 13:02:38 -04:00
parent e5abd48337
commit 04c92c1454
9 changed files with 182 additions and 137 deletions
+34 -9
View File
@@ -4,21 +4,24 @@ use std::{
fs::{self, File},
io::{Read, Seek as _, SeekFrom, Write as _},
path::{Path, PathBuf},
sync::Arc,
};
use crate::emulator::SimId;
use crate::emulator::{SimId, game_info::GameInfo};
pub struct Cart {
pub file_path: PathBuf,
pub rom: Vec<u8>,
sram_file: File,
pub sram: Vec<u8>,
pub info: Arc<GameInfo>,
}
impl Cart {
pub fn load(file_path: &Path, sim_id: SimId) -> Result<Self> {
let rom = fs::read(file_path)?;
let rom = try_parse_elf(&rom).unwrap_or(rom);
let (rom, info) =
try_parse_elf(file_path, &rom).unwrap_or_else(|| (rom, GameInfo::empty(file_path)));
let mut sram_file = File::options()
.read(true)
@@ -46,6 +49,7 @@ impl Cart {
rom,
sram_file,
sram,
info: Arc::new(info),
})
}
@@ -56,18 +60,39 @@ impl Cart {
}
}
fn try_parse_elf(data: &[u8]) -> Option<Vec<u8>> {
let parsed = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(data).ok()?;
fn try_parse_elf(file_path: &Path, data: &[u8]) -> Option<(Vec<u8>, GameInfo)> {
use object::read::elf::FileHeader;
let program = match object::FileKind::parse(data).ok()? {
object::FileKind::Elf32 => {
let header = object::elf::FileHeader32::parse(data).ok()?;
parse_elf_program(header, data)?
}
object::FileKind::Elf64 => {
let header = object::elf::FileHeader64::parse(data).ok()?;
parse_elf_program(header, data)?
}
_ => return None,
};
let info = GameInfo::new(file_path, data).unwrap_or_else(|_| GameInfo::empty(file_path));
Some((program, info))
}
fn parse_elf_program<Elf: object::read::elf::FileHeader<Endian = object::Endianness>>(
header: &Elf,
data: &[u8],
) -> Option<Vec<u8>> {
use object::read::elf::ProgramHeader;
let endian = header.endian().ok()?;
let mut bytes = vec![];
let mut pstart = None;
for phdr in parsed.segments()? {
if phdr.p_filesz == 0 {
for phdr in header.program_headers(endian, data).ok()? {
if phdr.p_filesz(endian).into() == 0 {
continue;
}
let start = pstart.unwrap_or(phdr.p_paddr);
let start = pstart.unwrap_or(phdr.p_paddr(endian).into());
pstart = Some(start);
bytes.resize((phdr.p_paddr - start) as usize, 0);
let data = parsed.segment_data(&phdr).ok()?;
bytes.resize((phdr.p_paddr(endian).into() - start) as usize, 0);
let data = phdr.data(endian, data).ok()?;
bytes.extend_from_slice(data);
}
Some(bytes)