Detect _savevr/_restvr + check in RELs
Some games include a copy of MW runtime.c in RELs. Easy to check. Some games also include _savevr/ _restvr for AltiVec. This is weird but we can handle it as well.
This commit is contained in:
parent
3289b2a3aa
commit
eb7c3e9d9f
|
@ -115,7 +115,7 @@ pub struct AnalyzerState {
|
||||||
pub sda_bases: Option<(u32, u32)>,
|
pub sda_bases: Option<(u32, u32)>,
|
||||||
pub functions: BTreeMap<SectionAddress, FunctionInfo>,
|
pub functions: BTreeMap<SectionAddress, FunctionInfo>,
|
||||||
pub jump_tables: BTreeMap<SectionAddress, u32>,
|
pub jump_tables: BTreeMap<SectionAddress, u32>,
|
||||||
pub known_symbols: BTreeMap<SectionAddress, ObjSymbol>,
|
pub known_symbols: BTreeMap<SectionAddress, Vec<ObjSymbol>>,
|
||||||
pub known_sections: BTreeMap<usize, String>,
|
pub known_sections: BTreeMap<usize, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,8 +196,39 @@ impl AnalyzerState {
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
for (&_addr, symbol) in &self.known_symbols {
|
for (&_addr, symbols) in &self.known_symbols {
|
||||||
obj.add_symbol(symbol.clone(), true)?;
|
for symbol in symbols {
|
||||||
|
// Remove overlapping symbols
|
||||||
|
if symbol.size > 0 {
|
||||||
|
let end = symbol.address + symbol.size;
|
||||||
|
let overlapping = obj
|
||||||
|
.symbols
|
||||||
|
.for_section_range(
|
||||||
|
symbol.section.unwrap(),
|
||||||
|
symbol.address as u32 + 1..end as u32,
|
||||||
|
)
|
||||||
|
.filter(|(_, s)| s.kind == symbol.kind)
|
||||||
|
.map(|(a, _)| a)
|
||||||
|
.collect_vec();
|
||||||
|
for index in overlapping {
|
||||||
|
let existing = &obj.symbols[index];
|
||||||
|
let symbol = ObjSymbol {
|
||||||
|
name: format!("__DELETED_{}", existing.name),
|
||||||
|
kind: ObjSymbolKind::Unknown,
|
||||||
|
size: 0,
|
||||||
|
flags: ObjSymbolFlagSet(
|
||||||
|
ObjSymbolFlags::RelocationIgnore
|
||||||
|
| ObjSymbolFlags::NoWrite
|
||||||
|
| ObjSymbolFlags::NoExport
|
||||||
|
| ObjSymbolFlags::Stripped,
|
||||||
|
),
|
||||||
|
..existing.clone()
|
||||||
|
};
|
||||||
|
obj.symbols.replace(index, symbol)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.add_symbol(symbol.clone(), true)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||||
&& data[TRK_TABLE_HEADER.as_bytes().len()] == 0
|
&& data[TRK_TABLE_HEADER.as_bytes().len()] == 0
|
||||||
{
|
{
|
||||||
log::debug!("Found gTRKInterruptVectorTable @ {:#010X}", start);
|
log::debug!("Found gTRKInterruptVectorTable @ {:#010X}", start);
|
||||||
state.known_symbols.insert(start, ObjSymbol {
|
state.known_symbols.entry(start).or_default().push(ObjSymbol {
|
||||||
name: "gTRKInterruptVectorTable".to_string(),
|
name: "gTRKInterruptVectorTable".to_string(),
|
||||||
address: start.address as u64,
|
address: start.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
|
@ -44,7 +44,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
let end = start + TRK_TABLE_SIZE;
|
let end = start + TRK_TABLE_SIZE;
|
||||||
state.known_symbols.insert(end, ObjSymbol {
|
state.known_symbols.entry(end).or_default().push(ObjSymbol {
|
||||||
name: "gTRKInterruptVectorTableEnd".to_string(),
|
name: "gTRKInterruptVectorTableEnd".to_string(),
|
||||||
address: end.address as u64,
|
address: end.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
|
@ -63,42 +63,45 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
|
||||||
|
|
||||||
pub struct FindSaveRestSleds {}
|
pub struct FindSaveRestSleds {}
|
||||||
|
|
||||||
const SLEDS: [([u8; 8], &str, &str); 4] = [
|
#[allow(clippy::type_complexity)]
|
||||||
([0xd9, 0xcb, 0xff, 0x70, 0xd9, 0xeb, 0xff, 0x78], "__save_fpr", "_savefpr_"),
|
const SLEDS: [([u8; 8], &str, &str, u32, u32, u32); 6] = [
|
||||||
([0xc9, 0xcb, 0xff, 0x70, 0xc9, 0xeb, 0xff, 0x78], "__restore_fpr", "_restfpr_"),
|
([0xd9, 0xcb, 0xff, 0x70, 0xd9, 0xeb, 0xff, 0x78], "__save_fpr", "_savefpr_", 14, 32, 4),
|
||||||
([0x91, 0xcb, 0xff, 0xb8, 0x91, 0xeb, 0xff, 0xbc], "__save_gpr", "_savegpr_"),
|
([0xc9, 0xcb, 0xff, 0x70, 0xc9, 0xeb, 0xff, 0x78], "__restore_fpr", "_restfpr_", 14, 32, 4),
|
||||||
([0x81, 0xcb, 0xff, 0xb8, 0x81, 0xeb, 0xff, 0xbc], "__restore_gpr", "_restgpr_"),
|
([0x91, 0xcb, 0xff, 0xb8, 0x91, 0xeb, 0xff, 0xbc], "__save_gpr", "_savegpr_", 14, 32, 4),
|
||||||
|
([0x81, 0xcb, 0xff, 0xb8, 0x81, 0xeb, 0xff, 0xbc], "__restore_gpr", "_restgpr_", 14, 32, 4),
|
||||||
|
([0x39, 0x80, 0xff, 0x40, 0x7e, 0x8c, 0x01, 0xce], "_savevr", "_savev", 20, 32, 8),
|
||||||
|
([0x39, 0x80, 0xff, 0x40, 0x7e, 0x8c, 0x00, 0xce], "_restorevr", "_restv", 20, 32, 8),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Runtime.PPCEABI.H.a runtime.c
|
// Runtime.PPCEABI.H.a runtime.c
|
||||||
impl AnalysisPass for FindSaveRestSleds {
|
impl AnalysisPass for FindSaveRestSleds {
|
||||||
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
||||||
const SLED_SIZE: usize = 19 * 4; // registers 14-31 + blr
|
|
||||||
for (section_index, section) in obj.sections.by_kind(ObjSectionKind::Code) {
|
for (section_index, section) in obj.sections.by_kind(ObjSectionKind::Code) {
|
||||||
for (needle, func, label) in &SLEDS {
|
for (needle, func, label, reg_start, reg_end, step_size) in SLEDS {
|
||||||
let Some(pos) = memmem::find(§ion.data, needle) else {
|
let Some(pos) = memmem::find(§ion.data, &needle) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let start = SectionAddress::new(section_index, section.address as u32 + pos as u32);
|
let start = SectionAddress::new(section_index, section.address as u32 + pos as u32);
|
||||||
log::debug!("Found {} @ {:#010X}", func, start);
|
log::debug!("Found {} @ {:#010X}", func, start);
|
||||||
|
let sled_size = (reg_end - reg_start) * step_size + 4 /* blr */;
|
||||||
state.functions.insert(start, FunctionInfo {
|
state.functions.insert(start, FunctionInfo {
|
||||||
analyzed: false,
|
analyzed: false,
|
||||||
end: Some(start + SLED_SIZE as u32),
|
end: Some(start + sled_size),
|
||||||
slices: None,
|
slices: None,
|
||||||
});
|
});
|
||||||
state.known_symbols.insert(start, ObjSymbol {
|
state.known_symbols.entry(start).or_default().push(ObjSymbol {
|
||||||
name: func.to_string(),
|
name: func.to_string(),
|
||||||
address: start.address as u64,
|
address: start.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
size: SLED_SIZE as u64,
|
size: sled_size as u64,
|
||||||
size_known: true,
|
size_known: true,
|
||||||
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
|
||||||
kind: ObjSymbolKind::Function,
|
kind: ObjSymbolKind::Function,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
for i in 14..=31 {
|
for i in reg_start..reg_end {
|
||||||
let addr = start + (i - 14) * 4;
|
let addr = start + (i - reg_start) * step_size;
|
||||||
state.known_symbols.insert(addr, ObjSymbol {
|
state.known_symbols.entry(addr).or_default().push(ObjSymbol {
|
||||||
name: format!("{}{}", label, i),
|
name: format!("{}{}", label, i),
|
||||||
address: addr.address as u64,
|
address: addr.address as u64,
|
||||||
section: Some(start.section),
|
section: Some(start.section),
|
||||||
|
@ -185,8 +188,9 @@ impl AnalysisPass for FindRelCtorsDtors {
|
||||||
possible_sections[1].0
|
possible_sections[1].0
|
||||||
);
|
);
|
||||||
let ctors_section_index = possible_sections[0].0;
|
let ctors_section_index = possible_sections[0].0;
|
||||||
|
let ctors_address = SectionAddress::new(ctors_section_index, 0);
|
||||||
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
state.known_sections.insert(ctors_section_index, ".ctors".to_string());
|
||||||
state.known_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
|
state.known_symbols.entry(ctors_address).or_default().push(ObjSymbol {
|
||||||
name: "_ctors".to_string(),
|
name: "_ctors".to_string(),
|
||||||
section: Some(ctors_section_index),
|
section: Some(ctors_section_index),
|
||||||
size_known: true,
|
size_known: true,
|
||||||
|
@ -195,8 +199,9 @@ impl AnalysisPass for FindRelCtorsDtors {
|
||||||
});
|
});
|
||||||
|
|
||||||
let dtors_section_index = possible_sections[1].0;
|
let dtors_section_index = possible_sections[1].0;
|
||||||
|
let dtors_address = SectionAddress::new(dtors_section_index, 0);
|
||||||
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
state.known_sections.insert(dtors_section_index, ".dtors".to_string());
|
||||||
state.known_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
|
state.known_symbols.entry(dtors_address).or_default().push(ObjSymbol {
|
||||||
name: "_dtors".to_string(),
|
name: "_dtors".to_string(),
|
||||||
section: Some(dtors_section_index),
|
section: Some(dtors_section_index),
|
||||||
size_known: true,
|
size_known: true,
|
||||||
|
|
|
@ -1056,6 +1056,7 @@ fn load_analyze_rel(config: &ProjectConfig, module_config: &ModuleConfig) -> Res
|
||||||
debug!("Analyzing module {}", module_obj.module_id);
|
debug!("Analyzing module {}", module_obj.module_id);
|
||||||
if !config.quick_analysis {
|
if !config.quick_analysis {
|
||||||
let mut state = AnalyzerState::default();
|
let mut state = AnalyzerState::default();
|
||||||
|
FindSaveRestSleds::execute(&mut state, &module_obj)?;
|
||||||
state.detect_functions(&module_obj)?;
|
state.detect_functions(&module_obj)?;
|
||||||
FindRelCtorsDtors::execute(&mut state, &module_obj)?;
|
FindRelCtorsDtors::execute(&mut state, &module_obj)?;
|
||||||
FindRelRodataData::execute(&mut state, &module_obj)?;
|
FindRelRodataData::execute(&mut state, &module_obj)?;
|
||||||
|
|
|
@ -365,6 +365,7 @@ fn create_gap_splits(obj: &mut ObjInfo) -> Result<()> {
|
||||||
let symbols = obj
|
let symbols = obj
|
||||||
.symbols
|
.symbols
|
||||||
.for_section_range(section_index, current_address.address..split_start.address)
|
.for_section_range(section_index, current_address.address..split_start.address)
|
||||||
|
.filter(|&(_, s)| !s.flags.is_stripped())
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let mut existing_symbols = HashSet::new();
|
let mut existing_symbols = HashSet::new();
|
||||||
for &(_, symbol) in &symbols {
|
for &(_, symbol) in &symbols {
|
||||||
|
|
Loading…
Reference in New Issue