Version 0.2.0

- Add `elf disasm` (disassemble an ELF)
- Add `elf fixup` (for GNU assembler)
- Add `map order` (link order deduction)
- Add `map slices` (ppcdis slices.yml, WIP)
- Add `map symbols` (ppcdis symbols.yml, WIP)
- Big speed improvement for map processing
- Minor `elf2dol` cleanup
This commit is contained in:
2022-12-10 01:28:23 -05:00
parent f6dbe94bac
commit 141339fcb0
18 changed files with 2548 additions and 334 deletions

View File

@@ -29,8 +29,10 @@ pub struct DolSection {
#[derive(Debug, Clone, Default)]
pub struct DolHeader {
pub text_sections: Vec<DolSection>,
pub data_sections: Vec<DolSection>,
pub text_section_count: usize,
pub data_section_count: usize,
pub text_sections: [DolSection; MAX_TEXT_SECTIONS],
pub data_sections: [DolSection; MAX_DATA_SECTIONS],
pub bss_address: u32,
pub bss_size: u32,
pub entry_point: u32,
@@ -38,32 +40,32 @@ pub struct DolHeader {
const MAX_TEXT_SECTIONS: usize = 7;
const MAX_DATA_SECTIONS: usize = 11;
const ZERO_BUF: [u8; 32] = [0u8; 32];
pub fn run(args: Args) -> Result<()> {
let elf_file = File::open(&args.elf_file)
.with_context(|| format!("Failed to open ELF file '{}'", args.elf_file))?;
let map = unsafe { MmapOptions::new().map(&elf_file) }
.with_context(|| format!("Failed to mmap binary: '{}'", args.elf_file))?;
.with_context(|| format!("Failed to mmap ELF file: '{}'", args.elf_file))?;
let obj_file = object::read::File::parse(&*map)?;
match obj_file.architecture() {
Architecture::PowerPc => {}
arch => return Err(Error::msg(format!("Unexpected architecture: {:?}", arch))),
arch => return Err(Error::msg(format!("Unexpected architecture: {arch:?}"))),
};
if obj_file.is_little_endian() {
return Err(Error::msg("Expected big endian"));
}
match obj_file.kind() {
ObjectKind::Executable => {}
kind => return Err(Error::msg(format!("Unexpected ELF type: {:?}", kind))),
kind => return Err(Error::msg(format!("Unexpected ELF type: {kind:?}"))),
}
let mut header = DolHeader { entry_point: obj_file.entry() as u32, ..Default::default() };
let mut offset = 0x100u32;
let mut out = BufWriter::new(
File::create(&args.dol_file)
.with_context(|| format!("Failed to create DOL file '{}'", args.dol_file))?,
);
let mut header = DolHeader { entry_point: obj_file.entry() as u32, ..Default::default() };
let mut offset = 0x100u32;
out.seek(SeekFrom::Start(offset as u64))?;
// Text sections
for section in obj_file.sections() {
@@ -72,9 +74,14 @@ pub fn run(args: Args) -> Result<()> {
}
let address = section.address() as u32;
let size = align32(section.size() as u32);
header.text_sections.push(DolSection { offset, address, size });
out.seek(SeekFrom::Start(offset as u64))?;
write_aligned(&mut out, section.data()?)?;
*header.text_sections.get_mut(header.text_section_count).ok_or_else(|| {
Error::msg(format!(
"Too many text sections (while processing '{}')",
section.name().unwrap_or("[error]")
))
})? = DolSection { offset, address, size };
header.text_section_count += 1;
write_aligned(&mut out, section.data()?, size)?;
offset += size;
}
@@ -85,9 +92,14 @@ pub fn run(args: Args) -> Result<()> {
}
let address = section.address() as u32;
let size = align32(section.size() as u32);
header.data_sections.push(DolSection { offset, address, size });
out.seek(SeekFrom::Start(offset as u64))?;
write_aligned(&mut out, section.data()?)?;
*header.data_sections.get_mut(header.data_section_count).ok_or_else(|| {
Error::msg(format!(
"Too many data sections (while processing '{}')",
section.name().unwrap_or("[error]")
))
})? = DolSection { offset, address, size };
header.data_section_count += 1;
write_aligned(&mut out, section.data()?, size)?;
offset += size;
}
@@ -104,68 +116,50 @@ pub fn run(args: Args) -> Result<()> {
header.bss_size = (address + size) - header.bss_address;
}
if header.text_sections.len() > MAX_TEXT_SECTIONS {
return Err(Error::msg(format!(
"Too many text sections: {} / {}",
header.text_sections.len(),
MAX_TEXT_SECTIONS
)));
}
if header.data_sections.len() > MAX_DATA_SECTIONS {
return Err(Error::msg(format!(
"Too many data sections: {} / {}",
header.data_sections.len(),
MAX_DATA_SECTIONS
)));
}
// Offsets
out.rewind()?;
for section in &header.text_sections {
out.write_all(&section.offset.to_be_bytes())?;
}
out.seek(SeekFrom::Start(0x1c))?;
for section in &header.data_sections {
out.write_all(&section.offset.to_be_bytes())?;
}
// Addresses
out.seek(SeekFrom::Start(0x48))?;
for section in &header.text_sections {
out.write_all(&section.address.to_be_bytes())?;
}
out.seek(SeekFrom::Start(0x64))?;
for section in &header.data_sections {
out.write_all(&section.address.to_be_bytes())?;
}
// Sizes
out.seek(SeekFrom::Start(0x90))?;
for section in &header.text_sections {
out.write_all(&section.size.to_be_bytes())?;
}
out.seek(SeekFrom::Start(0xac))?;
for section in &header.data_sections {
out.write_all(&section.size.to_be_bytes())?;
}
// BSS + entry
out.seek(SeekFrom::Start(0xd8))?;
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]
fn align32(x: u32) -> u32 { (x + 31) & !31 }
const fn align32(x: u32) -> u32 { (x + 31) & !31 }
const ZERO_BUF: [u8; 32] = [0u8; 32];
#[inline]
fn write_aligned<T: Write>(out: &mut T, bytes: &[u8]) -> std::io::Result<()> {
let len = bytes.len() as u32;
let padding = align32(len) - len;
fn write_aligned<T: Write>(out: &mut T, bytes: &[u8], aligned_size: u32) -> std::io::Result<()> {
out.write_all(bytes)?;
let padding = aligned_size - bytes.len() as u32;
if padding > 0 {
out.write_all(&ZERO_BUF[0..padding as usize])?;
}