mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-06-22 14:33:28 +00:00
Quick & dirty ALF support in elf2dol
This commit is contained in:
parent
bb18a4b253
commit
a064ddfd68
@ -6,16 +6,17 @@ use object::{Architecture, Endianness, Object, ObjectKind, ObjectSection, Sectio
|
|||||||
use typed_path::Utf8NativePathBuf;
|
use typed_path::Utf8NativePathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::{file::buf_writer, path::native_path},
|
obj::ObjSectionKind,
|
||||||
|
util::{alf::ALF_MAGIC, dol::process_dol, file::buf_writer, path::native_path},
|
||||||
vfs::open_file,
|
vfs::open_file,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
#[derive(FromArgs, PartialEq, Eq, Debug)]
|
||||||
/// Converts an ELF file to a DOL file.
|
/// Converts an ELF (or ALF) file to a DOL file.
|
||||||
#[argp(subcommand, name = "elf2dol")]
|
#[argp(subcommand, name = "elf2dol")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argp(positional, from_str_fn(native_path))]
|
#[argp(positional, from_str_fn(native_path))]
|
||||||
/// path to input ELF
|
/// path to input ELF or ALF file
|
||||||
elf_file: Utf8NativePathBuf,
|
elf_file: Utf8NativePathBuf,
|
||||||
#[argp(positional, from_str_fn(native_path))]
|
#[argp(positional, from_str_fn(native_path))]
|
||||||
/// path to output DOL
|
/// path to output DOL
|
||||||
@ -48,7 +49,12 @@ const MAX_DATA_SECTIONS: usize = 11;
|
|||||||
|
|
||||||
pub fn run(args: Args) -> Result<()> {
|
pub fn run(args: Args) -> Result<()> {
|
||||||
let mut file = open_file(&args.elf_file, true)?;
|
let mut file = open_file(&args.elf_file, true)?;
|
||||||
let obj_file = object::read::File::parse(file.map()?)?;
|
let data = file.map()?;
|
||||||
|
if data.len() >= 4 && &data[0..4] == ALF_MAGIC {
|
||||||
|
return convert_alf(args, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_file = object::read::File::parse(data)?;
|
||||||
match obj_file.architecture() {
|
match obj_file.architecture() {
|
||||||
Architecture::PowerPc => {}
|
Architecture::PowerPc => {}
|
||||||
arch => bail!("Unexpected architecture: {arch:?}"),
|
arch => bail!("Unexpected architecture: {arch:?}"),
|
||||||
@ -153,6 +159,89 @@ pub fn run(args: Args) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_alf(args: Args, data: &[u8]) -> Result<()> {
|
||||||
|
let obj = process_dol(data, "")?;
|
||||||
|
|
||||||
|
let mut header = DolHeader { entry_point: obj.entry.unwrap() as u32, ..Default::default() };
|
||||||
|
let mut offset = 0x100u32;
|
||||||
|
let mut out = buf_writer(&args.dol_file)?;
|
||||||
|
out.seek(SeekFrom::Start(offset as u64))?;
|
||||||
|
|
||||||
|
// Text sections
|
||||||
|
for (_, section) in obj.sections.iter().filter(|(_, s)| s.kind == ObjSectionKind::Code) {
|
||||||
|
log::debug!("Processing text section '{}'", section.name);
|
||||||
|
let address = section.address as u32;
|
||||||
|
let size = align32(section.size as u32);
|
||||||
|
*header.text_sections.get_mut(header.text_section_count).ok_or_else(|| {
|
||||||
|
anyhow!("Too many text sections (while processing '{}')", section.name)
|
||||||
|
})? = DolSection { offset, address, size };
|
||||||
|
header.text_section_count += 1;
|
||||||
|
write_aligned(&mut out, §ion.data, size)?;
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data sections
|
||||||
|
for (_, section) in obj
|
||||||
|
.sections
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, s)| matches!(s.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData))
|
||||||
|
{
|
||||||
|
log::debug!("Processing data section '{}'", section.name);
|
||||||
|
let address = section.address as u32;
|
||||||
|
let size = align32(section.size as u32);
|
||||||
|
*header.data_sections.get_mut(header.data_section_count).ok_or_else(|| {
|
||||||
|
anyhow!("Too many data sections (while processing '{}')", section.name)
|
||||||
|
})? = DolSection { offset, address, size };
|
||||||
|
header.data_section_count += 1;
|
||||||
|
write_aligned(&mut out, §ion.data, size)?;
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSS sections
|
||||||
|
for (_, section) in obj.sections.iter().filter(|(_, s)| s.kind == ObjSectionKind::Bss) {
|
||||||
|
let address = section.address as u32;
|
||||||
|
let size = section.size as u32;
|
||||||
|
if header.bss_address == 0 {
|
||||||
|
header.bss_address = address;
|
||||||
|
}
|
||||||
|
header.bss_size = (address + size) - header.bss_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offsets
|
||||||
|
out.rewind()?;
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.offset.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.offset.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addresses
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.address.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.address.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes
|
||||||
|
for section in &header.text_sections {
|
||||||
|
out.write_all(§ion.size.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
for section in &header.data_sections {
|
||||||
|
out.write_all(§ion.size.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BSS + entry
|
||||||
|
out.write_all(&header.bss_address.to_be_bytes())?;
|
||||||
|
out.write_all(&header.bss_size.to_be_bytes())?;
|
||||||
|
out.write_all(&header.entry_point.to_be_bytes())?;
|
||||||
|
|
||||||
|
// Done!
|
||||||
|
out.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn align32(x: u32) -> u32 { (x + 31) & !31 }
|
const fn align32(x: u32) -> u32 { (x + 31) & !31 }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user