disassemble __get_debug_bba

This commit is contained in:
Charlotte Delenk 2021-08-02 10:59:42 +01:00
parent d765c01039
commit 3194257761
14 changed files with 256 additions and 51 deletions

3
.gitignore vendored
View file

@ -2,4 +2,5 @@
/bin /bin
/build.ninja /build.ninja
/build /build
.ninja_log .ninja_log
.ninja_deps

7
Cargo.lock generated
View file

@ -97,6 +97,7 @@ dependencies = [
"clap", "clap",
"csv", "csv",
"goblin", "goblin",
"once_cell",
] ]
[[package]] [[package]]
@ -152,6 +153,12 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]] [[package]]
name = "plain" name = "plain"
version = "0.2.3" version = "0.2.3"

View file

@ -10,4 +10,5 @@ default-run = "buildgen"
anyhow = "1.0.42" anyhow = "1.0.42"
goblin = "0.4.2" goblin = "0.4.2"
clap = "2.33.3" clap = "2.33.3"
csv = "1.1.6" csv = "1.1.6"
once_cell = "1.8.0"

View file

@ -1,13 +1,15 @@
./build/obj/init_80004000_80006728.o build/obj/init_80004000_80006300.o
./build/obj/extab_80006740_800068cc.o build/obj/sdk/rvl/os/__start.o
./build/obj/extabindex_800068e0_800069e4.o build/obj/init_80006308_80006728.o
./build/obj/text_80006a00_80406244.o build/obj/extab_80006740_800068cc.o
./build/obj/ctors_80406260_80406530.o build/obj/extabindex_800068e0_800069e4.o
./build/obj/dtors_80406540_8040654c.o build/obj/text_80006a00_80406244.o
./build/obj/rodata_80406560_80421030.o build/obj/ctors_80406260_80406530.o
./build/obj/data_80421040_804966fc.o build/obj/dtors_80406544_8040654c.o
./build/obj/bss_80496700_8055640c.o build/obj/rodata_80406560_80421030.o
./build/obj/sdata_80556420_8055c6d0.o build/obj/data_80421040_804966fc.o
./build/obj/sbss_8055c6e0_8055df74.o build/obj/bss_80496700_8055640c.o
./build/obj/sdata2_8055df80_805643b0.o build/obj/sdata_80556420_8055c6d0.o
./build/obj/sbss2_805643c0_805643fc.o build/obj/sbss_8055c6e0_8055df74.o
build/obj/sdata2_8055df80_805643b0.o
build/obj/sbss2_805643c0_805643fc.o

View file

@ -1 +1,3 @@
StartAddress,EndAddress,Section,File,function StartAddress,EndAddress,Section,File,function
80006300,80006308,.init,__start.o,__get_debug_bba
80406540,80406544,.dtors,linker generated,Symbol is generated by the linker automatically
1 StartAddress EndAddress Section File function
2 80006300 80006308 .init __start.o __get_debug_bba
3 80406540 80406544 .dtors linker generated Symbol is generated by the linker automatically

View file

@ -1,2 +1,6 @@
Address,SymbolName Address,SymbolName
80006310,__start 80006310,__start
80006300,__get_debug_bba
80004000,_LOC_80004000
80006310,_LOC_80006310
80006b88,__destroy_global_chain
1 Address SymbolName
2 80006310 __start
3 80006300 __get_debug_bba
4 80004000 _LOC_80004000
5 80006310 _LOC_80006310
6 80006b88 __destroy_global_chain

View file

@ -10,3 +10,10 @@ rule genlcf
rule ccld rule ccld
command = ./run-exe.sh bin/mwcc/mwldeppc.exe $in -o $out -lcf $lcf -fp hard -linkmode moreram -map $map command = ./run-exe.sh bin/mwcc/mwldeppc.exe $in -o $out -lcf $lcf -fp hard -linkmode moreram -map $map
rule cc
command = ./run-exe.sh bin/mwcc/mwcceppc.exe $cflags -c $in -o $out -gccdep -MD
depfile = $out.d
deps = gcc
rule elf2dol
command = cargo run --quiet --release --bin elf2dol -- $in $out

7
sdk/rvl/os/__start.c Normal file
View file

@ -0,0 +1,7 @@
__declspec(section ".init") asm void __get_debug_bba() {
// clang-format off
nofralloc;
lbz r3, -0x1ba8(r13);
blr;
// clang-format on
}

View file

@ -1,8 +1,7 @@
use std::{ use std::{
fs::File, fs::File,
io::{BufReader, BufWriter, Write}, io::{BufRead, BufReader},
num::ParseIntError, num::ParseIntError,
process::Command,
}; };
use anyhow::Result; use anyhow::Result;
@ -12,6 +11,8 @@ fn parse_hex(s: &str) -> Result<u32, ParseIntError> {
u32::from_str_radix(s.trim_start_matches("0x"), 16) u32::from_str_radix(s.trim_start_matches("0x"), 16)
} }
const SOURCES: &[(&str, &str)] = &[("sdk/rvl/os/__start.c", "sdk")];
fn main() -> Result<()> { fn main() -> Result<()> {
let mut ninja = donut_decomp::ninja::NinjaFile::new("build.ninja")?; let mut ninja = donut_decomp::ninja::NinjaFile::new("build.ninja")?;
let mut ranges = Ranges::new(); let mut ranges = Ranges::new();
@ -41,7 +42,7 @@ fn main() -> Result<()> {
); );
} }
let mut objs = vec![]; ranges.merge_ranges();
for (start, end) in ranges.into_iter() { for (start, end) in ranges.into_iter() {
let objfile = format!( let objfile = format!(
@ -51,22 +52,21 @@ fn main() -> Result<()> {
end end
); );
ninja.emit_extract("bin/donut/donut.dol", &objfile, start, end)?; ninja.emit_extract("bin/donut/donut.dol", &objfile, start, end)?;
objs.push(objfile); }
for source in SOURCES.iter() {
ninja.emit_cc(source.0, source.1)?;
} }
ninja.emit_genlcf("build/donut.lcf")?; ninja.emit_genlcf("build/donut.lcf")?;
ninja.emit_ccld("build/donut.elf", "build/donut.lcf", &objs)?; ninja.emit_ccld(
"build/donut.elf",
"build/donut.lcf",
&BufReader::new(File::open("data/objects.txt")?)
.lines()
.collect::<Result<Vec<_>, std::io::Error>>()?,
)?;
ninja.emit_elf2dol("build/donut.dol", "build/donut.elf")?;
let mut obj_list = BufWriter::new(File::create("data/objects.txt")?);
for obj in objs.iter() {
obj_list.write_all(b"./")?;
obj_list.write_all(obj.as_bytes())?;
obj_list.write_all(b"\n")?;
}
Command::new("ninja")
.arg("build/donut.elf")
.spawn()?
.wait()?;
Ok(()) Ok(())
} }

26
src/bin/elf2dol.rs Normal file
View file

@ -0,0 +1,26 @@
use anyhow::Result;
use clap::{App, Arg};
fn main() -> Result<()> {
let matches = App::new("ELF to DOL converter")
.version("0.0")
.author("Charlotte D. <darkkirb@darkkirb.de>")
.about("Generates a DOL from an ELF")
.arg(
Arg::with_name("INPUT")
.help("Input ELF file")
.required(true)
.index(1),
)
.arg(
Arg::with_name("OUTPUT")
.help("Output DOL file")
.required(true)
.index(2),
)
.get_matches();
let input = matches.value_of("INPUT").unwrap();
let output = matches.value_of("OUTPUT").unwrap();
donut_decomp::dol::elf_to_dol(input, output)?;
Ok(())
}

View file

@ -49,9 +49,6 @@ MEMORY {
.sbss2 ALIGN(0x20):{} .sbss2 ALIGN(0x20):{}
.stack ALIGN(0x100):{} .stack ALIGN(0x100):{}
} > text } > text
GROUP:{
binary_blobs ALIGN(0x20):{}
} > binary_blobs
_stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7; _stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7;
_stack_end = _f_sbss2 + SIZEOF(.sbss2); _stack_end = _f_sbss2 + SIZEOF(.sbss2);

View file

@ -2,11 +2,13 @@
use std::{ use std::{
fs::{self, File}, fs::{self, File},
io::{Read, Seek, SeekFrom, Write}, io::{BufWriter, Read, Seek, SeekFrom, Write},
path::Path,
process::Command, process::Command,
}; };
use anyhow::Result; use anyhow::Result;
use goblin::elf::Elf;
pub const SECTION_NAMES: &[&str] = &[ pub const SECTION_NAMES: &[&str] = &[
".init", ".init",
@ -16,8 +18,8 @@ pub const SECTION_NAMES: &[&str] = &[
".text4", ".text4",
".text5", ".text5",
".text6", ".text6",
"extab", "extab_",
"extabindex", "extabindex_",
".ctors", ".ctors",
".dtors", ".dtors",
".rodata", ".rodata",
@ -172,27 +174,29 @@ impl<R: Read + Seek> Dol<R> {
let mut binfile = File::create(&binfile_name)?; let mut binfile = File::create(&binfile_name)?;
binfile.write_all(&data)?; binfile.write_all(&data)?;
} }
Command::new("objcopy") Command::new("llvm-objcopy")
.arg("-I") .arg("-I")
.arg("binary") .arg("binary")
.arg("-O") .arg("-O")
.arg("elf32-big") .arg("elf32-powerpc")
.arg(&binfile_name) .arg(&binfile_name)
.arg(outname) .arg(outname)
// .arg("--change-section-address")
// .arg(format!(".data={}", address))
.arg("--strip-all")
.spawn()?
.wait()?;
fs::remove_file(&binfile_name)?;
Command::new("llvm-objcopy")
.arg("--rename-section") .arg("--rename-section")
.arg(format!( .arg(format!(
".data={},{}", ".data={},{}",
SECTION_NAMES[section], SECTION_BITS[section] SECTION_NAMES[section], SECTION_BITS[section]
)) ))
.arg("--change-section-address") .arg(outname)
.arg(format!(".data={}", address))
.arg("--strip-all")
.spawn()? .spawn()?
.wait()?; .wait()?;
fs::remove_file(&binfile_name)?; Command::new("llvm-objcopy")
Command::new("objcopy")
.arg("--format")
.arg("elf32-big")
.arg("--add-symbol") .arg("--add-symbol")
.arg(format!( .arg(format!(
"_LOC_{:08x}={}:0x{:08x},global", "_LOC_{:08x}={}:0x{:08x},global",
@ -220,3 +224,93 @@ impl<R: Read + Seek> Dol<R> {
unreachable!(); unreachable!();
} }
} }
fn section_to_idx(section_name: &str) -> Option<usize> {
for (i, s) in SECTION_NAMES.iter().enumerate() {
if section_name == *s {
return Some(i);
}
}
None
}
pub fn elf_to_dol(elf_file: impl AsRef<Path>, dol_file: impl AsRef<Path>) -> Result<()> {
let elf_file = elf_file.as_ref();
let dol_file = dol_file.as_ref();
let mut elf_buf = Vec::new();
File::open(elf_file)?.read_to_end(&mut elf_buf)?;
let elf = Elf::parse(&elf_buf)?;
let mut dol = BufWriter::new(File::create(dol_file)?);
let mut file_offsets = [0u32; 18];
let mut loading_addresses = [0u32; 18];
let mut section_sizes = [0u32; 18];
let mut bss_address = 0;
let bss_size;
let mut sbss_end = 0;
let mut elf_offsets = [0usize; 18];
let entry_point = 0x80006310u32; // TODO: hack
for section in elf.section_headers.iter() {
let name = elf
.shdr_strtab
.get_at(section.sh_name)
.ok_or_else(|| anyhow::anyhow!("Failed to read section name!"))?;
let idx = section_to_idx(name);
if idx.is_none() {
continue;
}
let idx = idx.unwrap();
if idx == 20 {
sbss_end = (section.sh_addr + section.sh_size) as u32;
}
if idx > 18 {
continue;
}
if idx == 18 {
bss_address = section.sh_addr as u32;
continue;
}
loading_addresses[idx] = section.sh_addr as u32;
section_sizes[idx] = section.sh_size as u32;
elf_offsets[idx] = section.sh_offset as usize;
}
bss_size = sbss_end - bss_address;
let mut offset = 0x100;
for (i, file_offset) in file_offsets.iter_mut().enumerate() {
if section_sizes[i] == 0 {
continue;
}
*file_offset = offset;
offset += section_sizes[i];
offset = (offset + 31) & !31;
}
for file_offset in file_offsets {
dol.write(&file_offset.to_be_bytes())?;
}
for loading_address in loading_addresses {
dol.write(&loading_address.to_be_bytes())?;
}
for section_size in section_sizes {
let section_size = (section_size + 31) & !31;
dol.write(&section_size.to_be_bytes())?;
}
dol.write(&bss_address.to_be_bytes())?;
dol.write(&bss_size.to_be_bytes())?;
dol.write(&entry_point.to_be_bytes())?;
for i in 0..18 {
if section_sizes[i] == 0 {
continue;
}
dol.seek(SeekFrom::Start(file_offsets[i] as u64))?;
dol.write_all(&elf_buf[elf_offsets[i]..(elf_offsets[i] + section_sizes[i] as usize)])?;
}
while (dol.seek(SeekFrom::Current(0))? & 31) != 0 {
dol.write_all(b"\0")?;
}
Ok(())
}

View file

@ -1,11 +1,18 @@
//! Ninja file generator //! Ninja file generator
use std::collections::HashSet; use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
use std::io::{BufWriter, Write}; use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
use once_cell::sync::Lazy;
static CFLAGS: Lazy<HashMap<&'static str, &'static [&'static str]>> = Lazy::new(|| {
let mut hm = HashMap::new();
hm.insert("sdk", &["-opt", "level=4"][..]);
hm
});
#[derive(Debug)] #[derive(Debug)]
pub struct NinjaFile { pub struct NinjaFile {
@ -127,4 +134,54 @@ impl NinjaFile {
self.emit_mkdir(parent)?; self.emit_mkdir(parent)?;
Ok(()) Ok(())
} }
pub fn emit_cc(&mut self, infile: impl AsRef<Path>, component: &str) -> Result<String> {
let infile = infile.as_ref();
let outfile = AsRef::<Path>::as_ref("build/obj/").join(infile.with_extension("o"));
if self.emitted_targets.contains(&outfile) {
return Ok(outfile.to_string_lossy().into_owned());
}
self.emitted_targets.insert(outfile.to_owned());
let parent = outfile.parent().unwrap();
self.writer.write_all(
format!(
"build {}: cc {} || {}\n",
outfile.display(),
infile.display(),
parent.display()
)
.as_bytes(),
)?;
self.writer.write_all(b" cflags =")?;
for flag in CFLAGS[component] {
self.writer.write_all(format!(" \"{}\"", flag).as_bytes())?;
}
self.writer.write_all(b"\n")?;
self.emit_mkdir(parent)?;
Ok(outfile.to_string_lossy().into_owned())
}
pub fn emit_elf2dol(
&mut self,
outfile: impl AsRef<Path>,
infile: impl AsRef<Path>,
) -> Result<()> {
let infile = infile.as_ref();
let outfile = outfile.as_ref();
if self.emitted_targets.contains(outfile) {
return Ok(());
}
self.emitted_targets.insert(outfile.to_owned());
let parent = outfile.parent().unwrap();
self.writer.write_all(
format!(
"build {}: elf2dol {} || {}\n",
outfile.display(),
infile.display(),
parent.display()
)
.as_bytes(),
)?;
self.emit_mkdir(parent)?;
Ok(())
}
} }

View file

@ -13,7 +13,7 @@ impl Ranges {
} }
pub fn add_range(&mut self, start: u32, end: u32) -> &mut Self { pub fn add_range(&mut self, start: u32, end: u32) -> &mut Self {
self.range_list.insert(start, end); self.range_list.insert(start, end);
self.merge_ranges(); //self.merge_ranges();
self self
} }
pub fn remove_range(&mut self, start: u32, end: u32) -> &mut Self { pub fn remove_range(&mut self, start: u32, end: u32) -> &mut Self {
@ -31,10 +31,10 @@ impl Ranges {
self.split_range(start, end); self.split_range(start, end);
self.split_range(end, range_end); self.split_range(end, range_end);
self.range_list.remove(&start); self.range_list.remove(&start);
self.merge_ranges(); //self.merge_ranges();
self self
} }
fn merge_ranges(&mut self) { pub fn merge_ranges(&mut self) {
let mut last_start = 0; let mut last_start = 0;
let mut last_end = 0; let mut last_end = 0;
let mut block_gc_list = vec![]; let mut block_gc_list = vec![];