mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-12 22:56:28 +00:00
Begin REL analysis & rework lots of code to be section-address aware
This commit is contained in:
510
src/cmd/dol.rs
510
src/cmd/dol.rs
@@ -5,6 +5,7 @@ use std::{
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::mem::take;
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use argp::FromArgs;
|
||||
@@ -21,14 +22,15 @@ use crate::{
|
||||
},
|
||||
cmd::shasum::file_sha1,
|
||||
obj::{
|
||||
split::{is_linker_generated_object, split_obj, update_splits},
|
||||
ObjDataKind, ObjInfo, ObjRelocKind, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||
ObjDataKind, ObjInfo, ObjReloc, ObjRelocKind, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
|
||||
ObjSymbolFlags, ObjSymbolKind, ObjSymbolScope, SymbolIndex,
|
||||
},
|
||||
util::{
|
||||
asm::write_asm,
|
||||
comment::MWComment,
|
||||
config::{apply_splits, apply_symbols_file, write_splits_file, write_symbols_file},
|
||||
config::{
|
||||
apply_splits, apply_symbols_file, is_auto_symbol, write_splits_file, write_symbols_file,
|
||||
},
|
||||
dep::DepFile,
|
||||
dol::process_dol,
|
||||
elf::{process_elf, write_elf},
|
||||
@@ -37,6 +39,7 @@ use crate::{
|
||||
map::apply_map_file,
|
||||
rel::process_rel,
|
||||
rso::{process_rso, DOL_SECTION_ABS, DOL_SECTION_NAMES},
|
||||
split::{is_linker_generated_object, split_obj, update_splits},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -150,6 +153,8 @@ pub struct ProjectConfig {
|
||||
pub struct ModuleConfig {
|
||||
pub object: PathBuf,
|
||||
pub hash: Option<String>,
|
||||
pub splits: Option<PathBuf>,
|
||||
pub symbols: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@@ -159,9 +164,18 @@ pub struct OutputUnit {
|
||||
pub autogenerated: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct OutputModule {
|
||||
pub name: String,
|
||||
pub ldscript: PathBuf,
|
||||
pub units: Vec<OutputUnit>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct OutputConfig {
|
||||
pub ldscript: PathBuf,
|
||||
pub units: Vec<OutputUnit>,
|
||||
pub modules: Vec<OutputModule>,
|
||||
}
|
||||
|
||||
pub fn run(args: Args) -> Result<()> {
|
||||
@@ -174,6 +188,7 @@ pub fn run(args: Args) -> Result<()> {
|
||||
}
|
||||
|
||||
fn apply_selfile(obj: &mut ObjInfo, selfile: &Path) -> Result<()> {
|
||||
log::info!("Loading {}", selfile.display());
|
||||
let rso = process_rso(selfile)?;
|
||||
for symbol in rso.symbols.iter() {
|
||||
let dol_section_index = match symbol.section {
|
||||
@@ -191,13 +206,13 @@ fn apply_selfile(obj: &mut ObjInfo, selfile: &Path) -> Result<()> {
|
||||
DOL_SECTION_NAMES.get(dol_section_index).and_then(|&opt| opt).ok_or_else(|| {
|
||||
anyhow!("Can't add symbol for unknown DOL section {}", dol_section_index)
|
||||
})?;
|
||||
let dol_section = obj
|
||||
let (dol_section_index, dol_section) = obj
|
||||
.sections
|
||||
.iter()
|
||||
.find(|section| section.name == dol_section_name)
|
||||
.find(|&(_, section)| section.name == dol_section_name)
|
||||
.ok_or_else(|| anyhow!("Failed to locate DOL section {}", dol_section_name))?;
|
||||
(
|
||||
Some(dol_section.index),
|
||||
Some(dol_section_index),
|
||||
dol_section.address as u32 + symbol.address as u32,
|
||||
Some(dol_section.kind),
|
||||
)
|
||||
@@ -208,17 +223,17 @@ fn apply_selfile(obj: &mut ObjInfo, selfile: &Path) -> Result<()> {
|
||||
Some(_) => ObjSymbolKind::Object,
|
||||
None => ObjSymbolKind::Unknown,
|
||||
};
|
||||
let existing_symbols = obj.symbols.at_address(address).collect_vec();
|
||||
let existing_symbols = if let Some(section_index) = section {
|
||||
obj.symbols.at_section_address(section_index, address).collect_vec()
|
||||
} else {
|
||||
// TODO hmmm
|
||||
obj.symbols.iter_abs().filter(|(_, s)| s.address == address as u64).collect_vec()
|
||||
};
|
||||
let existing_symbol = existing_symbols
|
||||
.iter()
|
||||
.find(|(_, s)| s.section == section && s.name == symbol.name)
|
||||
.find(|(_, s)| s.name == symbol.name)
|
||||
.cloned()
|
||||
.or_else(|| {
|
||||
existing_symbols
|
||||
.iter()
|
||||
.find(|(_, s)| s.section == section && s.kind == symbol_kind)
|
||||
.cloned()
|
||||
});
|
||||
.or_else(|| existing_symbols.iter().find(|(_, s)| s.kind == symbol_kind).cloned());
|
||||
if let Some((existing_symbol_idx, existing_symbol)) = existing_symbol {
|
||||
log::debug!("Mapping symbol {} to {}", symbol.name, existing_symbol.name);
|
||||
obj.symbols.replace(existing_symbol_idx, ObjSymbol {
|
||||
@@ -273,7 +288,7 @@ fn info(args: InfoArgs) -> Result<()> {
|
||||
println!("Entry point: {:#010X}", obj.entry);
|
||||
println!("\nSections:");
|
||||
println!("\t{: >10} | {: <10} | {: <10} | {: <10}", "Name", "Address", "Size", "File Off");
|
||||
for section in &obj.sections {
|
||||
for (_, section) in obj.sections.iter() {
|
||||
println!(
|
||||
"\t{: >10} | {:#010X} | {: <#10X} | {: <#10X}",
|
||||
section.name, section.address, section.size, section.file_offset
|
||||
@@ -281,8 +296,8 @@ fn info(args: InfoArgs) -> Result<()> {
|
||||
}
|
||||
println!("\nDiscovered symbols:");
|
||||
println!("\t{: >23} | {: <10} | {: <10}", "Name", "Address", "Size");
|
||||
for (_, symbol) in obj.symbols.iter_ordered() {
|
||||
if symbol.name.starts_with('@') || symbol.name.starts_with("fn_") {
|
||||
for (_, symbol) in obj.symbols.iter_ordered().chain(obj.symbols.iter_abs()) {
|
||||
if symbol.name.starts_with('@') || is_auto_symbol(&symbol.name) {
|
||||
continue;
|
||||
}
|
||||
if symbol.size_known {
|
||||
@@ -314,6 +329,214 @@ fn verify_hash<P: AsRef<Path>>(path: P, hash_str: &str) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_symbols(obj: &mut ObjInfo, modules: &BTreeMap<u32, ObjInfo>) -> Result<()> {
|
||||
log::info!("Updating symbols for module {}", obj.module_id);
|
||||
|
||||
// Find all references to this module from other modules
|
||||
for rel_reloc in obj
|
||||
.unresolved_relocations
|
||||
.iter()
|
||||
.chain(modules.iter().flat_map(|(_, obj)| obj.unresolved_relocations.iter()))
|
||||
.filter(|r| r.module_id == obj.module_id)
|
||||
{
|
||||
let (target_section_index, target_section) = obj
|
||||
.sections
|
||||
.get_elf_index(rel_reloc.target_section as usize)
|
||||
.ok_or_else(|| anyhow!("Failed to locate REL section {}", rel_reloc.section))?;
|
||||
|
||||
let target_symbol = obj
|
||||
.symbols
|
||||
.at_section_address(target_section_index, rel_reloc.addend)
|
||||
.filter(|(_, s)| s.referenced_by(rel_reloc.kind))
|
||||
.at_most_one()
|
||||
.map_err(|e| {
|
||||
for (_, symbol) in e {
|
||||
log::warn!(
|
||||
"Multiple symbols found for {:#010X}: {}",
|
||||
rel_reloc.addend,
|
||||
symbol.name
|
||||
);
|
||||
}
|
||||
anyhow!("Multiple symbols found for {:#010X}", rel_reloc.addend)
|
||||
})?;
|
||||
|
||||
if let Some((symbol_index, symbol)) = target_symbol {
|
||||
// Update symbol
|
||||
log::trace!(
|
||||
"Found symbol in section {} at {:#010X}: {}",
|
||||
rel_reloc.target_section,
|
||||
rel_reloc.addend,
|
||||
symbol.name
|
||||
);
|
||||
obj.symbols.flags(symbol_index).set_force_active(true);
|
||||
} else {
|
||||
// Add label
|
||||
log::trace!(
|
||||
"Creating label in section {} at {:#010X}",
|
||||
rel_reloc.target_section,
|
||||
rel_reloc.addend
|
||||
);
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: format!(
|
||||
"lbl_mod{}_{}_{:08X}",
|
||||
obj.module_id,
|
||||
target_section.name.trim_start_matches('.'),
|
||||
rel_reloc.addend
|
||||
),
|
||||
demangled_name: None,
|
||||
address: rel_reloc.addend as u64,
|
||||
section: Some(target_section_index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::ForceActive.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: ObjDataKind::Unknown,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_relocations(
|
||||
obj: &mut ObjInfo,
|
||||
modules: &BTreeMap<u32, ObjInfo>,
|
||||
dol_obj: &ObjInfo,
|
||||
) -> Result<()> {
|
||||
log::info!("Creating relocations for module {}", obj.module_id);
|
||||
|
||||
// Resolve all relocations in this module
|
||||
for rel_reloc in take(&mut obj.unresolved_relocations) {
|
||||
let target_obj = if rel_reloc.module_id == 0 {
|
||||
dol_obj
|
||||
} else if rel_reloc.module_id == obj.module_id {
|
||||
&*obj
|
||||
} else {
|
||||
modules
|
||||
.get(&rel_reloc.module_id)
|
||||
.ok_or_else(|| anyhow!("Failed to locate module {}", rel_reloc.module_id))?
|
||||
};
|
||||
|
||||
let (target_section_index, _target_section) = if rel_reloc.module_id == 0 {
|
||||
target_obj.sections.at_address(rel_reloc.addend)?
|
||||
} else {
|
||||
target_obj.sections.get_elf_index(rel_reloc.target_section as usize).ok_or_else(
|
||||
|| {
|
||||
anyhow!(
|
||||
"Failed to locate module {} section {}",
|
||||
rel_reloc.module_id,
|
||||
rel_reloc.target_section
|
||||
)
|
||||
},
|
||||
)?
|
||||
};
|
||||
|
||||
if let Some((symbol_index, symbol)) = target_obj
|
||||
.symbols
|
||||
.at_section_address(target_section_index, rel_reloc.addend)
|
||||
.filter(|(_, s)| s.referenced_by(rel_reloc.kind))
|
||||
.at_most_one()
|
||||
.map_err(|e| {
|
||||
for (_, symbol) in e {
|
||||
log::warn!(
|
||||
"Multiple symbols found for {:#010X}: {}",
|
||||
rel_reloc.addend,
|
||||
symbol.name
|
||||
);
|
||||
}
|
||||
anyhow!("Multiple symbols found for {:#010X}", rel_reloc.addend)
|
||||
})?
|
||||
{
|
||||
// log::info!("Would create relocation to symbol {}", symbol.name);
|
||||
let reloc = ObjReloc {
|
||||
kind: rel_reloc.kind,
|
||||
address: rel_reloc.address as u64 & !3,
|
||||
target_symbol: symbol_index,
|
||||
addend: rel_reloc.addend as i64 - symbol.address as i64,
|
||||
module: if rel_reloc.module_id == obj.module_id {
|
||||
None
|
||||
} else {
|
||||
Some(rel_reloc.module_id)
|
||||
},
|
||||
};
|
||||
let (_, source_section) = obj
|
||||
.sections
|
||||
.get_elf_index_mut(rel_reloc.section as usize)
|
||||
.ok_or_else(|| anyhow!("Failed to locate REL section {}", rel_reloc.section))?;
|
||||
source_section.relocations.push(reloc);
|
||||
} else {
|
||||
bail!(
|
||||
"Couldn't find module {} symbol in section {} at {:#010X}",
|
||||
rel_reloc.module_id,
|
||||
rel_reloc.target_section,
|
||||
rel_reloc.addend
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_external_relocations(
|
||||
obj: &mut ObjInfo,
|
||||
modules: &BTreeMap<u32, ObjInfo>,
|
||||
dol_obj: Option<&ObjInfo>,
|
||||
) -> Result<()> {
|
||||
log::info!("Resolving relocations for module {}", obj.module_id);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
struct RelocRef {
|
||||
module_id: u32,
|
||||
symbol_index: SymbolIndex,
|
||||
}
|
||||
let mut reloc_to_symbol = HashMap::<RelocRef, usize>::new();
|
||||
|
||||
for (_section_index, section) in obj.sections.iter_mut() {
|
||||
for reloc in section.relocations.iter_mut() {
|
||||
if let Some(module_id) = reloc.module {
|
||||
let reloc_ref = RelocRef { module_id, symbol_index: reloc.target_symbol };
|
||||
let symbol_idx = match reloc_to_symbol.entry(reloc_ref) {
|
||||
hash_map::Entry::Occupied(e) => *e.get(),
|
||||
hash_map::Entry::Vacant(e) => {
|
||||
let target_obj = if module_id == obj.module_id {
|
||||
bail!("Relocation to self in module {}", obj.module_id)
|
||||
} else if module_id == 0 {
|
||||
dol_obj.unwrap()
|
||||
} else {
|
||||
modules.get(&module_id).ok_or_else(|| {
|
||||
anyhow!("Failed to locate module {}", reloc.module.unwrap())
|
||||
})?
|
||||
};
|
||||
|
||||
let target_symbol = &target_obj.symbols[reloc.target_symbol];
|
||||
let symbol_idx = obj.symbols.add_direct(ObjSymbol {
|
||||
name: target_symbol.name.clone(),
|
||||
demangled_name: target_symbol.demangled_name.clone(),
|
||||
address: 0,
|
||||
section: None,
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: Default::default(),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: Default::default(),
|
||||
})?;
|
||||
|
||||
e.insert(symbol_idx);
|
||||
symbol_idx
|
||||
}
|
||||
};
|
||||
|
||||
reloc.target_symbol = symbol_idx;
|
||||
reloc.module = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn split(args: SplitArgs) -> Result<()> {
|
||||
log::info!("Loading {}", args.config.display());
|
||||
let mut config_file = File::open(&args.config)
|
||||
@@ -335,6 +558,7 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
}
|
||||
|
||||
let mut modules = BTreeMap::<u32, ObjInfo>::new();
|
||||
let mut module_ids = Vec::with_capacity(config.modules.len());
|
||||
for module_config in &config.modules {
|
||||
log::info!("Loading {}", module_config.object.display());
|
||||
if let Some(hash_str) = &module_config.hash {
|
||||
@@ -342,6 +566,7 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
}
|
||||
let map = map_file(&module_config.object)?;
|
||||
let rel_obj = process_rel(map_reader(&map))?;
|
||||
module_ids.push(rel_obj.module_id);
|
||||
match modules.entry(rel_obj.module_id) {
|
||||
Entry::Vacant(e) => e.insert(rel_obj),
|
||||
Entry::Occupied(_) => bail!("Duplicate module ID {}", obj.module_id),
|
||||
@@ -370,52 +595,20 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
|
||||
if !modules.is_empty() {
|
||||
log::info!("Applying module relocations");
|
||||
for (module_id, module_obj) in modules {
|
||||
for rel_reloc in &module_obj.unresolved_relocations {
|
||||
// TODO also apply inter-module relocations
|
||||
if rel_reloc.module_id != 0 {
|
||||
continue;
|
||||
}
|
||||
let target = rel_reloc.addend;
|
||||
if let Some((symbol_index, symbol)) =
|
||||
obj.symbols.for_relocation(target, rel_reloc.kind)?
|
||||
{
|
||||
if symbol.flags.is_local() {
|
||||
bail!(
|
||||
"Module {} relocation to {:#010X} found local symbol {}",
|
||||
module_id,
|
||||
symbol.address,
|
||||
symbol.name
|
||||
);
|
||||
}
|
||||
let addend = target as i64 - symbol.address as i64;
|
||||
if addend != 0 {
|
||||
bail!(
|
||||
"Module {} relocation to {:#010X} for symbol {} has non-zero addend {:#010X}",
|
||||
module_id,
|
||||
symbol.address,
|
||||
symbol.name,
|
||||
addend
|
||||
);
|
||||
}
|
||||
obj.symbols.flags(symbol_index).set_force_active(true);
|
||||
} else {
|
||||
// Add label
|
||||
let target_section = obj.section_at(target)?;
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: format!("lbl_{:08X}", target),
|
||||
demangled_name: None,
|
||||
address: target as u64,
|
||||
section: Some(target_section.index),
|
||||
size: 0,
|
||||
size_known: false,
|
||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::ForceActive.into()),
|
||||
kind: Default::default(),
|
||||
align: None,
|
||||
data_kind: ObjDataKind::Unknown,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1: For each module, create any missing symbols (referenced from other modules) and set FORCEACTIVE
|
||||
update_symbols(&mut obj, &modules)?;
|
||||
for &module_id in &module_ids {
|
||||
let mut module_obj = modules.remove(&module_id).unwrap();
|
||||
update_symbols(&mut module_obj, &modules)?;
|
||||
modules.insert(module_id, module_obj);
|
||||
}
|
||||
|
||||
// Step 2: For each module, create relocations to symbols in other modules
|
||||
for &module_id in &module_ids {
|
||||
let mut module_obj = modules.remove(&module_id).unwrap();
|
||||
create_relocations(&mut module_obj, &modules, &obj)?;
|
||||
modules.insert(module_id, module_obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +660,17 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
if !modules.is_empty() {
|
||||
log::info!("Resolving module relocations");
|
||||
|
||||
resolve_external_relocations(&mut obj, &modules, None)?;
|
||||
for &module_id in &module_ids {
|
||||
let mut module_obj = modules.remove(&module_id).unwrap();
|
||||
resolve_external_relocations(&mut module_obj, &modules, Some(&obj))?;
|
||||
modules.insert(module_id, module_obj);
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Splitting {} objects", obj.link_order.len());
|
||||
let split_objs = split_obj(&obj)?;
|
||||
|
||||
@@ -479,20 +683,9 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
fs::write(include_dir.join("macros.inc"), include_str!("../../assets/macros.inc"))?;
|
||||
|
||||
log::info!("Writing object files");
|
||||
let mut file_map = HashMap::<String, Vec<u8>>::new();
|
||||
let mut out_config = OutputConfig::default();
|
||||
for (unit, split_obj) in obj.link_order.iter().zip(&split_objs) {
|
||||
let out_obj = write_elf(split_obj)?;
|
||||
match file_map.entry(unit.name.clone()) {
|
||||
hash_map::Entry::Vacant(e) => e.insert(out_obj),
|
||||
hash_map::Entry::Occupied(_) => bail!("Duplicate file {}", unit.name),
|
||||
};
|
||||
}
|
||||
|
||||
let mut out_config = OutputConfig::default();
|
||||
for unit in &obj.link_order {
|
||||
let object = file_map
|
||||
.get(&unit.name)
|
||||
.ok_or_else(|| anyhow!("Failed to find object file for unit '{}'", unit.name))?;
|
||||
let out_path = obj_dir.join(obj_path_for_unit(&unit.name));
|
||||
out_config.units.push(OutputUnit {
|
||||
object: out_path.clone(),
|
||||
@@ -502,7 +695,7 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
if let Some(parent) = out_path.parent() {
|
||||
DirBuilder::new().recursive(true).create(parent)?;
|
||||
}
|
||||
fs::write(&out_path, object)
|
||||
fs::write(&out_path, out_obj)
|
||||
.with_context(|| format!("Failed to write '{}'", out_path.display()))?;
|
||||
}
|
||||
{
|
||||
@@ -512,24 +705,46 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
}
|
||||
|
||||
// Generate ldscript.lcf
|
||||
fs::write(
|
||||
args.out_dir.join("ldscript.lcf"),
|
||||
generate_ldscript(&obj, config.auto_force_files)?,
|
||||
)?;
|
||||
let ldscript_path = args.out_dir.join("ldscript.lcf");
|
||||
fs::write(&ldscript_path, generate_ldscript(&obj, config.auto_force_files)?)?;
|
||||
out_config.ldscript = ldscript_path;
|
||||
|
||||
log::info!("Writing disassembly");
|
||||
for (unit, split_obj) in obj.link_order.iter().zip(&split_objs) {
|
||||
let out_path = asm_dir.join(asm_path_for_unit(&unit.name));
|
||||
|
||||
if let Some(parent) = out_path.parent() {
|
||||
DirBuilder::new().recursive(true).create(parent)?;
|
||||
}
|
||||
let mut w = buf_writer(&out_path)?;
|
||||
write_asm(&mut w, split_obj)
|
||||
.with_context(|| format!("Failed to write {}", out_path.display()))?;
|
||||
w.flush()?;
|
||||
}
|
||||
|
||||
// Split and write modules
|
||||
for (config, &module_id) in config.modules.iter().zip(&module_ids) {
|
||||
let obj = modules.get(&module_id).unwrap();
|
||||
|
||||
let out_dir = args.out_dir.join(format!("module_{}", module_id));
|
||||
let asm_dir = out_dir.join("asm");
|
||||
// let obj_dir = out_dir.join("obj");
|
||||
|
||||
if !args.no_update {
|
||||
if let Some(symbols_path) = &config.symbols {
|
||||
write_symbols_file(symbols_path, obj)?;
|
||||
}
|
||||
if let Some(splits_path) = &config.splits {
|
||||
write_splits_file(splits_path, obj)?;
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Writing disassembly");
|
||||
let filename = config.object.file_name().unwrap().to_str().unwrap();
|
||||
let out_path = asm_dir.join(asm_path_for_unit(filename));
|
||||
let mut w = buf_writer(&out_path)?;
|
||||
write_asm(&mut w, obj)
|
||||
.with_context(|| format!("Failed to write {}", out_path.display()))?;
|
||||
w.flush()?;
|
||||
}
|
||||
|
||||
// Write dep file
|
||||
{
|
||||
let dep_path = args.out_dir.join("dep");
|
||||
@@ -549,15 +764,11 @@ fn split(args: SplitArgs) -> Result<()> {
|
||||
#[allow(dead_code)]
|
||||
fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -> Result<()> {
|
||||
let real_obj = process_elf(elf_file)?;
|
||||
for real_section in &real_obj.sections {
|
||||
let obj_section = match obj.sections.get(real_section.index) {
|
||||
for (section_index, real_section) in real_obj.sections.iter() {
|
||||
let obj_section = match obj.sections.get(section_index) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
log::error!(
|
||||
"Section {} {} doesn't exist in DOL",
|
||||
real_section.index,
|
||||
real_section.name
|
||||
);
|
||||
log::error!("Section {} {} doesn't exist in DOL", section_index, real_section.name);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@@ -566,18 +777,15 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||
"Section mismatch: {} {:?} ({}) should be {} {:?}",
|
||||
obj_section.name,
|
||||
obj_section.kind,
|
||||
obj_section.index,
|
||||
section_index,
|
||||
real_section.name,
|
||||
real_section.kind
|
||||
);
|
||||
}
|
||||
}
|
||||
let mut real_functions = BTreeMap::<u32, String>::new();
|
||||
for section in &real_obj.sections {
|
||||
if section.kind != ObjSectionKind::Code {
|
||||
continue;
|
||||
}
|
||||
for (_symbol_idx, symbol) in real_obj.symbols.for_section(section) {
|
||||
for (section_index, _section) in real_obj.sections.by_kind(ObjSectionKind::Code) {
|
||||
for (_symbol_idx, symbol) in real_obj.symbols.for_section(section_index) {
|
||||
real_functions.insert(symbol.address as u32, symbol.name.clone());
|
||||
match state.function_bounds.get(&(symbol.address as u32)) {
|
||||
Some(&end) => {
|
||||
@@ -617,8 +825,8 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||
}
|
||||
// return Ok(()); // TODO
|
||||
|
||||
for real_section in &real_obj.sections {
|
||||
let obj_section = match obj.sections.get(real_section.index) {
|
||||
for (real_section_index, real_section) in real_obj.sections.iter() {
|
||||
let obj_section = match obj.sections.get(real_section_index) {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
@@ -626,7 +834,7 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||
let obj_map = obj_section.build_relocation_map()?;
|
||||
for (&real_addr, &real_reloc_idx) in &real_map {
|
||||
let real_reloc = &real_section.relocations[real_reloc_idx];
|
||||
let real_symbol = real_obj.symbols.at(real_reloc.target_symbol);
|
||||
let real_symbol = &real_obj.symbols[real_reloc.target_symbol];
|
||||
let obj_reloc = match obj_map.get(&real_addr) {
|
||||
Some(v) => &obj_section.relocations[*v],
|
||||
None => {
|
||||
@@ -652,7 +860,7 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let obj_symbol = obj.symbols.at(obj_reloc.target_symbol);
|
||||
let obj_symbol = &obj.symbols[obj_reloc.target_symbol];
|
||||
if real_reloc.kind != obj_reloc.kind {
|
||||
log::warn!(
|
||||
"Relocation type mismatch @ {:#010X}: {:?} != {:?}",
|
||||
@@ -680,7 +888,7 @@ fn validate<P: AsRef<Path>>(obj: &ObjInfo, elf_file: P, state: &AnalyzerState) -
|
||||
}
|
||||
for (&obj_addr, &obj_reloc_idx) in &obj_map {
|
||||
let obj_reloc = &obj_section.relocations[obj_reloc_idx];
|
||||
let obj_symbol = obj.symbols.at(obj_reloc.target_symbol);
|
||||
let obj_symbol = &obj.symbols[obj_reloc.target_symbol];
|
||||
if !real_map.contains_key(&obj_addr) {
|
||||
log::warn!(
|
||||
"Relocation not real @ {:#010X} {:?} to {:#010X}+{:X} ({})",
|
||||
@@ -716,19 +924,20 @@ fn diff(args: DiffArgs) -> Result<()> {
|
||||
log::info!("Loading {}", args.map_file.display());
|
||||
apply_map_file(&args.map_file, &mut linked_obj)?;
|
||||
|
||||
for orig_sym in obj.symbols.iter() {
|
||||
if orig_sym.kind == ObjSymbolKind::Section || orig_sym.section.is_none() {
|
||||
continue;
|
||||
}
|
||||
for orig_sym in obj.symbols.iter().filter(|s| s.kind != ObjSymbolKind::Section) {
|
||||
let Some(orig_section_index) = orig_sym.section else { continue };
|
||||
let orig_section = &obj.sections[orig_section_index];
|
||||
let (linked_section_index, linked_section) =
|
||||
linked_obj.sections.at_address(orig_sym.address as u32)?;
|
||||
|
||||
let linked_sym = linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.name == orig_sym.name)
|
||||
.or_else(|| {
|
||||
linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.kind == orig_sym.kind)
|
||||
});
|
||||
let mut found = false;
|
||||
@@ -746,18 +955,14 @@ fn diff(args: DiffArgs) -> Result<()> {
|
||||
found = true;
|
||||
} else if linked_sym.kind == orig_sym.kind && linked_sym.size == orig_sym.size {
|
||||
// Fuzzy match
|
||||
let orig_data = obj
|
||||
.section_data(
|
||||
orig_sym.address as u32,
|
||||
orig_sym.address as u32 + orig_sym.size as u32,
|
||||
)?
|
||||
.1;
|
||||
let linked_data = linked_obj
|
||||
.section_data(
|
||||
linked_sym.address as u32,
|
||||
linked_sym.address as u32 + linked_sym.size as u32,
|
||||
)?
|
||||
.1;
|
||||
let orig_data = orig_section.data_range(
|
||||
orig_sym.address as u32,
|
||||
orig_sym.address as u32 + orig_sym.size as u32,
|
||||
)?;
|
||||
let linked_data = linked_section.data_range(
|
||||
linked_sym.address as u32,
|
||||
linked_sym.address as u32 + linked_sym.size as u32,
|
||||
)?;
|
||||
if orig_data == linked_data {
|
||||
found = true;
|
||||
}
|
||||
@@ -771,7 +976,9 @@ fn diff(args: DiffArgs) -> Result<()> {
|
||||
orig_sym.size,
|
||||
orig_sym.address
|
||||
);
|
||||
for (_, linked_sym) in linked_obj.symbols.at_address(orig_sym.address as u32) {
|
||||
for (_, linked_sym) in
|
||||
linked_obj.symbols.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
{
|
||||
log::error!(
|
||||
"At {:#010X}, found: {} (type {:?}, size {:#X})",
|
||||
linked_sym.address,
|
||||
@@ -794,32 +1001,30 @@ fn diff(args: DiffArgs) -> Result<()> {
|
||||
}
|
||||
|
||||
// Data diff
|
||||
for orig_sym in obj.symbols.iter() {
|
||||
if orig_sym.kind == ObjSymbolKind::Section || orig_sym.section.is_none() {
|
||||
continue;
|
||||
}
|
||||
for orig_sym in obj.symbols.iter().filter(|s| s.kind != ObjSymbolKind::Section) {
|
||||
let Some(orig_section_index) = orig_sym.section else { continue };
|
||||
let orig_section = &obj.sections[orig_section_index];
|
||||
let (linked_section_index, linked_section) =
|
||||
linked_obj.sections.at_address(orig_sym.address as u32)?;
|
||||
|
||||
let (_, linked_sym) = linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.name == orig_sym.name)
|
||||
.or_else(|| {
|
||||
linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.kind == orig_sym.kind)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let orig_data = obj
|
||||
.section_data(orig_sym.address as u32, orig_sym.address as u32 + orig_sym.size as u32)?
|
||||
.1;
|
||||
let linked_data = linked_obj
|
||||
.section_data(
|
||||
linked_sym.address as u32,
|
||||
linked_sym.address as u32 + linked_sym.size as u32,
|
||||
)?
|
||||
.1;
|
||||
let orig_data = orig_section
|
||||
.data_range(orig_sym.address as u32, orig_sym.address as u32 + orig_sym.size as u32)?;
|
||||
let linked_data = linked_section.data_range(
|
||||
linked_sym.address as u32,
|
||||
linked_sym.address as u32 + linked_sym.size as u32,
|
||||
)?;
|
||||
if orig_data != linked_data {
|
||||
log::error!(
|
||||
"Data mismatch for {} (type {:?}, size {:#X}) at {:#010X}",
|
||||
@@ -861,14 +1066,21 @@ fn apply(args: ApplyArgs) -> Result<()> {
|
||||
|
||||
let mut replacements: Vec<(SymbolIndex, Option<ObjSymbol>)> = vec![];
|
||||
for (orig_idx, orig_sym) in obj.symbols.iter().enumerate() {
|
||||
// skip ABS for now
|
||||
if orig_sym.section.is_none() {
|
||||
continue;
|
||||
}
|
||||
let (linked_section_index, _linked_section) =
|
||||
linked_obj.sections.at_address(orig_sym.address as u32)?;
|
||||
|
||||
let linked_sym = linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.name == orig_sym.name)
|
||||
.or_else(|| {
|
||||
linked_obj
|
||||
.symbols
|
||||
.at_address(orig_sym.address as u32)
|
||||
.at_section_address(linked_section_index, orig_sym.address as u32)
|
||||
.find(|(_, sym)| sym.kind == orig_sym.kind)
|
||||
});
|
||||
if let Some((_, linked_sym)) = linked_sym {
|
||||
@@ -929,18 +1141,21 @@ fn apply(args: ApplyArgs) -> Result<()> {
|
||||
for linked_sym in linked_obj.symbols.iter() {
|
||||
if matches!(linked_sym.kind, ObjSymbolKind::Section)
|
||||
|| is_linker_generated_object(&linked_sym.name)
|
||||
// skip ABS for now
|
||||
|| linked_sym.section.is_none()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let (orig_section_index, _orig_section) =
|
||||
obj.sections.at_address(linked_sym.address as u32)?;
|
||||
let orig_sym = obj
|
||||
.symbols
|
||||
.at_address(linked_sym.address as u32)
|
||||
.at_section_address(orig_section_index, linked_sym.address as u32)
|
||||
.find(|(_, sym)| sym.name == linked_sym.name)
|
||||
.or_else(|| {
|
||||
linked_obj
|
||||
.symbols
|
||||
.at_address(linked_sym.address as u32)
|
||||
obj.symbols
|
||||
.at_section_address(orig_section_index, linked_sym.address as u32)
|
||||
.find(|(_, sym)| sym.kind == linked_sym.kind)
|
||||
});
|
||||
if orig_sym.is_none() {
|
||||
@@ -951,7 +1166,18 @@ fn apply(args: ApplyArgs) -> Result<()> {
|
||||
linked_sym.size,
|
||||
linked_sym.address
|
||||
);
|
||||
obj.symbols.add_direct(linked_sym.clone())?;
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: linked_sym.name.clone(),
|
||||
demangled_name: linked_sym.demangled_name.clone(),
|
||||
address: linked_sym.address,
|
||||
section: Some(orig_section_index),
|
||||
size: linked_sym.size,
|
||||
size_known: linked_sym.size_known,
|
||||
flags: linked_sym.flags,
|
||||
kind: linked_sym.kind,
|
||||
align: linked_sym.align,
|
||||
data_kind: linked_sym.data_kind,
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,14 @@ use object::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
obj::{
|
||||
signatures::{compare_signature, generate_signature, FunctionSignature},
|
||||
split::split_obj,
|
||||
ObjKind,
|
||||
},
|
||||
obj::ObjKind,
|
||||
util::{
|
||||
asm::write_asm,
|
||||
config::{write_splits_file, write_symbols_file},
|
||||
elf::{process_elf, write_elf},
|
||||
file::{buf_writer, process_rsp},
|
||||
signatures::{compare_signature, generate_signature, FunctionSignature},
|
||||
split::split_obj,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -148,9 +146,6 @@ fn disasm(args: DisasmArgs) -> Result<()> {
|
||||
let out_path = asm_dir.join(file_name_from_unit(&unit.name, ".s"));
|
||||
log::info!("Writing {}", out_path.display());
|
||||
|
||||
if let Some(parent) = out_path.parent() {
|
||||
DirBuilder::new().recursive(true).create(parent)?;
|
||||
}
|
||||
let mut w = buf_writer(out_path)?;
|
||||
write_asm(&mut w, split_obj)?;
|
||||
w.flush()?;
|
||||
@@ -160,9 +155,6 @@ fn disasm(args: DisasmArgs) -> Result<()> {
|
||||
files_out.flush()?;
|
||||
}
|
||||
ObjKind::Relocatable => {
|
||||
if let Some(parent) = args.out.parent() {
|
||||
DirBuilder::new().recursive(true).create(parent)?;
|
||||
}
|
||||
let mut w = buf_writer(args.out)?;
|
||||
write_asm(&mut w, &obj)?;
|
||||
w.flush()?;
|
||||
|
||||
@@ -107,25 +107,24 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||
let mut section_map: BTreeMap<u32, BTreeMap<u32, u32>> = BTreeMap::new();
|
||||
let mut offset = align32(arena_lo + 0x2000);
|
||||
for module in module_map.values() {
|
||||
for mod_section in &module.sections {
|
||||
let section_idx = obj.sections.len();
|
||||
for (mod_section_index, mod_section) in module.sections.iter() {
|
||||
ensure!(mod_section.relocations.is_empty(), "Unsupported relocations during merge");
|
||||
obj.sections.push(ObjSection {
|
||||
let section_idx = obj.sections.push(ObjSection {
|
||||
name: format!("{}:{}", mod_section.name, module.module_id),
|
||||
kind: mod_section.kind,
|
||||
address: offset as u64,
|
||||
size: mod_section.size,
|
||||
data: mod_section.data.clone(),
|
||||
align: mod_section.align,
|
||||
index: section_idx,
|
||||
elf_index: mod_section.elf_index,
|
||||
relocations: vec![],
|
||||
original_address: mod_section.original_address,
|
||||
file_offset: mod_section.file_offset,
|
||||
section_known: mod_section.section_known,
|
||||
splits: mod_section.splits.clone(),
|
||||
});
|
||||
section_map.nested_insert(module.module_id, mod_section.elf_index as u32, offset)?;
|
||||
for (_, mod_symbol) in module.symbols.for_section(mod_section) {
|
||||
for (_, mod_symbol) in module.symbols.for_section(mod_section_index) {
|
||||
obj.symbols.add_direct(ObjSymbol {
|
||||
name: mod_symbol.name.clone(),
|
||||
demangled_name: mod_symbol.demangled_name.clone(),
|
||||
@@ -157,8 +156,8 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||
})?;
|
||||
section_map[&(rel_reloc.target_section as u32)] + rel_reloc.addend
|
||||
};
|
||||
let source_section_index = obj.section_at(source_addr)?.index;
|
||||
let target_section_index = obj.section_at(target_addr)?.index;
|
||||
let (source_section_index, _) = obj.sections.at_address(source_addr)?;
|
||||
let (target_section_index, _) = obj.sections.at_address(target_addr)?;
|
||||
|
||||
let (symbol_idx, addend) = if let Some((symbol_idx, symbol)) =
|
||||
obj.symbols.for_relocation(target_addr, rel_reloc.kind)?
|
||||
@@ -185,6 +184,7 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||
address: source_addr as u64,
|
||||
target_symbol: symbol_idx,
|
||||
addend,
|
||||
module: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -217,11 +217,11 @@ fn merge(args: MergeArgs) -> Result<()> {
|
||||
}
|
||||
|
||||
fn link_relocations(obj: &mut ObjInfo) -> Result<()> {
|
||||
for section in &mut obj.sections {
|
||||
for (_, section) in obj.sections.iter_mut() {
|
||||
for reloc in §ion.relocations {
|
||||
let source_address = reloc.address /*& !3*/;
|
||||
let target_address =
|
||||
(obj.symbols.address_of(reloc.target_symbol) as i64 + reloc.addend) as u32;
|
||||
(obj.symbols[reloc.target_symbol].address as i64 + reloc.addend) as u32;
|
||||
let ins_ref =
|
||||
array_ref_mut!(section.data, (source_address - section.address) as usize, 4);
|
||||
let mut ins = u32::from_be_bytes(*ins_ref);
|
||||
|
||||
Reference in New Issue
Block a user