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:
Luke Street 2024-06-10 00:43:00 -06:00
parent 3289b2a3aa
commit eb7c3e9d9f
4 changed files with 59 additions and 21 deletions

View File

@ -115,7 +115,7 @@ pub struct AnalyzerState {
pub sda_bases: Option<(u32, u32)>,
pub functions: BTreeMap<SectionAddress, FunctionInfo>,
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>,
}
@ -196,8 +196,39 @@ impl AnalyzerState {
false,
)?;
}
for (&_addr, symbol) in &self.known_symbols {
obj.add_symbol(symbol.clone(), true)?;
for (&_addr, symbols) in &self.known_symbols {
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(())
}

View File

@ -35,7 +35,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
&& data[TRK_TABLE_HEADER.as_bytes().len()] == 0
{
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(),
address: start.address as u64,
section: Some(start.section),
@ -44,7 +44,7 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
..Default::default()
});
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(),
address: end.address as u64,
section: Some(start.section),
@ -63,42 +63,45 @@ impl AnalysisPass for FindTRKInterruptVectorTable {
pub struct FindSaveRestSleds {}
const SLEDS: [([u8; 8], &str, &str); 4] = [
([0xd9, 0xcb, 0xff, 0x70, 0xd9, 0xeb, 0xff, 0x78], "__save_fpr", "_savefpr_"),
([0xc9, 0xcb, 0xff, 0x70, 0xc9, 0xeb, 0xff, 0x78], "__restore_fpr", "_restfpr_"),
([0x91, 0xcb, 0xff, 0xb8, 0x91, 0xeb, 0xff, 0xbc], "__save_gpr", "_savegpr_"),
([0x81, 0xcb, 0xff, 0xb8, 0x81, 0xeb, 0xff, 0xbc], "__restore_gpr", "_restgpr_"),
#[allow(clippy::type_complexity)]
const SLEDS: [([u8; 8], &str, &str, u32, u32, u32); 6] = [
([0xd9, 0xcb, 0xff, 0x70, 0xd9, 0xeb, 0xff, 0x78], "__save_fpr", "_savefpr_", 14, 32, 4),
([0xc9, 0xcb, 0xff, 0x70, 0xc9, 0xeb, 0xff, 0x78], "__restore_fpr", "_restfpr_", 14, 32, 4),
([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
impl AnalysisPass for FindSaveRestSleds {
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 (needle, func, label) in &SLEDS {
let Some(pos) = memmem::find(&section.data, needle) else {
for (needle, func, label, reg_start, reg_end, step_size) in SLEDS {
let Some(pos) = memmem::find(&section.data, &needle) else {
continue;
};
let start = SectionAddress::new(section_index, section.address as u32 + pos as u32);
log::debug!("Found {} @ {:#010X}", func, start);
let sled_size = (reg_end - reg_start) * step_size + 4 /* blr */;
state.functions.insert(start, FunctionInfo {
analyzed: false,
end: Some(start + SLED_SIZE as u32),
end: Some(start + sled_size),
slices: None,
});
state.known_symbols.insert(start, ObjSymbol {
state.known_symbols.entry(start).or_default().push(ObjSymbol {
name: func.to_string(),
address: start.address as u64,
section: Some(start.section),
size: SLED_SIZE as u64,
size: sled_size as u64,
size_known: true,
flags: ObjSymbolFlagSet(ObjSymbolFlags::Global.into()),
kind: ObjSymbolKind::Function,
..Default::default()
});
for i in 14..=31 {
let addr = start + (i - 14) * 4;
state.known_symbols.insert(addr, ObjSymbol {
for i in reg_start..reg_end {
let addr = start + (i - reg_start) * step_size;
state.known_symbols.entry(addr).or_default().push(ObjSymbol {
name: format!("{}{}", label, i),
address: addr.address as u64,
section: Some(start.section),
@ -185,8 +188,9 @@ impl AnalysisPass for FindRelCtorsDtors {
possible_sections[1].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_symbols.insert(SectionAddress::new(ctors_section_index, 0), ObjSymbol {
state.known_symbols.entry(ctors_address).or_default().push(ObjSymbol {
name: "_ctors".to_string(),
section: Some(ctors_section_index),
size_known: true,
@ -195,8 +199,9 @@ impl AnalysisPass for FindRelCtorsDtors {
});
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_symbols.insert(SectionAddress::new(dtors_section_index, 0), ObjSymbol {
state.known_symbols.entry(dtors_address).or_default().push(ObjSymbol {
name: "_dtors".to_string(),
section: Some(dtors_section_index),
size_known: true,

View File

@ -1056,6 +1056,7 @@ fn load_analyze_rel(config: &ProjectConfig, module_config: &ModuleConfig) -> Res
debug!("Analyzing module {}", module_obj.module_id);
if !config.quick_analysis {
let mut state = AnalyzerState::default();
FindSaveRestSleds::execute(&mut state, &module_obj)?;
state.detect_functions(&module_obj)?;
FindRelCtorsDtors::execute(&mut state, &module_obj)?;
FindRelRodataData::execute(&mut state, &module_obj)?;

View File

@ -365,6 +365,7 @@ fn create_gap_splits(obj: &mut ObjInfo) -> Result<()> {
let symbols = obj
.symbols
.for_section_range(section_index, current_address.address..split_start.address)
.filter(|&(_, s)| !s.flags.is_stripped())
.collect_vec();
let mut existing_symbols = HashSet::new();
for &(_, symbol) in &symbols {