disassemble __get_debug_bba
This commit is contained in:
parent
d765c01039
commit
3194257761
14 changed files with 256 additions and 51 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@
|
|||
/build.ninja
|
||||
/build
|
||||
.ninja_log
|
||||
.ninja_deps
|
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -97,6 +97,7 @@ dependencies = [
|
|||
"clap",
|
||||
"csv",
|
||||
"goblin",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -152,6 +153,12 @@ version = "2.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
|
|
|
@ -11,3 +11,4 @@ anyhow = "1.0.42"
|
|||
goblin = "0.4.2"
|
||||
clap = "2.33.3"
|
||||
csv = "1.1.6"
|
||||
once_cell = "1.8.0"
|
|
@ -1,13 +1,15 @@
|
|||
./build/obj/init_80004000_80006728.o
|
||||
./build/obj/extab_80006740_800068cc.o
|
||||
./build/obj/extabindex_800068e0_800069e4.o
|
||||
./build/obj/text_80006a00_80406244.o
|
||||
./build/obj/ctors_80406260_80406530.o
|
||||
./build/obj/dtors_80406540_8040654c.o
|
||||
./build/obj/rodata_80406560_80421030.o
|
||||
./build/obj/data_80421040_804966fc.o
|
||||
./build/obj/bss_80496700_8055640c.o
|
||||
./build/obj/sdata_80556420_8055c6d0.o
|
||||
./build/obj/sbss_8055c6e0_8055df74.o
|
||||
./build/obj/sdata2_8055df80_805643b0.o
|
||||
./build/obj/sbss2_805643c0_805643fc.o
|
||||
build/obj/init_80004000_80006300.o
|
||||
build/obj/sdk/rvl/os/__start.o
|
||||
build/obj/init_80006308_80006728.o
|
||||
build/obj/extab_80006740_800068cc.o
|
||||
build/obj/extabindex_800068e0_800069e4.o
|
||||
build/obj/text_80006a00_80406244.o
|
||||
build/obj/ctors_80406260_80406530.o
|
||||
build/obj/dtors_80406544_8040654c.o
|
||||
build/obj/rodata_80406560_80421030.o
|
||||
build/obj/data_80421040_804966fc.o
|
||||
build/obj/bss_80496700_8055640c.o
|
||||
build/obj/sdata_80556420_8055c6d0.o
|
||||
build/obj/sbss_8055c6e0_8055df74.o
|
||||
build/obj/sdata2_8055df80_805643b0.o
|
||||
build/obj/sbss2_805643c0_805643fc.o
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
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,2 +1,6 @@
|
|||
Address,SymbolName
|
||||
80006310,__start
|
||||
80006300,__get_debug_bba
|
||||
80004000,_LOC_80004000
|
||||
80006310,_LOC_80006310
|
||||
80006b88,__destroy_global_chain
|
|
|
@ -10,3 +10,10 @@ rule genlcf
|
|||
rule ccld
|
||||
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
7
sdk/rvl/os/__start.c
Normal 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
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, BufWriter, Write},
|
||||
io::{BufRead, BufReader},
|
||||
num::ParseIntError,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
const SOURCES: &[(&str, &str)] = &[("sdk/rvl/os/__start.c", "sdk")];
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut ninja = donut_decomp::ninja::NinjaFile::new("build.ninja")?;
|
||||
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() {
|
||||
let objfile = format!(
|
||||
|
@ -51,22 +52,21 @@ fn main() -> Result<()> {
|
|||
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_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(())
|
||||
}
|
||||
|
|
26
src/bin/elf2dol.rs
Normal file
26
src/bin/elf2dol.rs
Normal 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(())
|
||||
}
|
|
@ -49,9 +49,6 @@ MEMORY {
|
|||
.sbss2 ALIGN(0x20):{}
|
||||
.stack ALIGN(0x100):{}
|
||||
} > text
|
||||
GROUP:{
|
||||
binary_blobs ALIGN(0x20):{}
|
||||
} > binary_blobs
|
||||
|
||||
_stack_addr = (_f_sbss2 + SIZEOF(.sbss2) + 65536 + 0x7) & ~0x7;
|
||||
_stack_end = _f_sbss2 + SIZEOF(.sbss2);
|
||||
|
|
118
src/dol/mod.rs
118
src/dol/mod.rs
|
@ -2,11 +2,13 @@
|
|||
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
io::{BufWriter, Read, Seek, SeekFrom, Write},
|
||||
path::Path,
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use goblin::elf::Elf;
|
||||
|
||||
pub const SECTION_NAMES: &[&str] = &[
|
||||
".init",
|
||||
|
@ -16,8 +18,8 @@ pub const SECTION_NAMES: &[&str] = &[
|
|||
".text4",
|
||||
".text5",
|
||||
".text6",
|
||||
"extab",
|
||||
"extabindex",
|
||||
"extab_",
|
||||
"extabindex_",
|
||||
".ctors",
|
||||
".dtors",
|
||||
".rodata",
|
||||
|
@ -172,27 +174,29 @@ impl<R: Read + Seek> Dol<R> {
|
|||
let mut binfile = File::create(&binfile_name)?;
|
||||
binfile.write_all(&data)?;
|
||||
}
|
||||
Command::new("objcopy")
|
||||
Command::new("llvm-objcopy")
|
||||
.arg("-I")
|
||||
.arg("binary")
|
||||
.arg("-O")
|
||||
.arg("elf32-big")
|
||||
.arg("elf32-powerpc")
|
||||
.arg(&binfile_name)
|
||||
.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(format!(
|
||||
".data={},{}",
|
||||
SECTION_NAMES[section], SECTION_BITS[section]
|
||||
))
|
||||
.arg("--change-section-address")
|
||||
.arg(format!(".data={}", address))
|
||||
.arg("--strip-all")
|
||||
.arg(outname)
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
fs::remove_file(&binfile_name)?;
|
||||
Command::new("objcopy")
|
||||
.arg("--format")
|
||||
.arg("elf32-big")
|
||||
Command::new("llvm-objcopy")
|
||||
.arg("--add-symbol")
|
||||
.arg(format!(
|
||||
"_LOC_{:08x}={}:0x{:08x},global",
|
||||
|
@ -220,3 +224,93 @@ impl<R: Read + Seek> Dol<R> {
|
|||
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(§ion_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(())
|
||||
}
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
//! Ninja file generator
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
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)]
|
||||
pub struct NinjaFile {
|
||||
|
@ -127,4 +134,54 @@ impl NinjaFile {
|
|||
self.emit_mkdir(parent)?;
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ impl Ranges {
|
|||
}
|
||||
pub fn add_range(&mut self, start: u32, end: u32) -> &mut Self {
|
||||
self.range_list.insert(start, end);
|
||||
self.merge_ranges();
|
||||
//self.merge_ranges();
|
||||
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(end, range_end);
|
||||
self.range_list.remove(&start);
|
||||
self.merge_ranges();
|
||||
//self.merge_ranges();
|
||||
self
|
||||
}
|
||||
fn merge_ranges(&mut self) {
|
||||
pub fn merge_ranges(&mut self) {
|
||||
let mut last_start = 0;
|
||||
let mut last_end = 0;
|
||||
let mut block_gc_list = vec![];
|
||||
|
|
Loading…
Reference in a new issue