mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-15 16:16:20 +00:00
Support block_relocations and add_relocations in config.yml
This allows more granular control over generated relocations. Also optimizes relocation address validity checks, leading to ~20% faster relocation analysis. Config example: ``` block_relocations: # Block any relocation pointing to this address. - target: .data:0x80130140 # Block any relocation originating from this address. - source: .text:0x80047160 # (optional) End address to make it a range. end: .text:0x800471A8 add_relocations: # Inserts or overwrites a relocation. # From: `subi r3, r3, 0x7657` # To: `li r3, mesWInsert-0x1@sda21` - source: .text:0x800473F4 type: sda21 target: mesWInsert addend: -1 ``` Resolves #33 Resolves #52
This commit is contained in:
100
src/obj/addresses.rs
Normal file
100
src/obj/addresses.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use crate::analysis::cfa::SectionAddress;
|
||||
|
||||
/// A collection of address ranges.
|
||||
/// Slow to insert, but fast to check if an address is contained in any of the ranges.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AddressRanges {
|
||||
/// (start, end) pairs of addresses.
|
||||
inner: Vec<(SectionAddress, u32)>,
|
||||
}
|
||||
|
||||
impl Default for AddressRanges {
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
impl AddressRanges {
|
||||
#[inline]
|
||||
pub fn new() -> Self { Self { inner: vec![] } }
|
||||
|
||||
pub fn insert(&mut self, start: SectionAddress, end: SectionAddress) {
|
||||
debug_assert_eq!(
|
||||
start.section, end.section,
|
||||
"AddressIntervals::insert: start and end must be in the same section"
|
||||
);
|
||||
// TODO: Handle overlapping ranges?
|
||||
match self.inner.binary_search_by_key(&start, |&(start, _)| start) {
|
||||
Ok(pos) => {
|
||||
let (_, end_ref) = &mut self.inner[pos];
|
||||
*end_ref = end.address.max(*end_ref);
|
||||
}
|
||||
Err(pos) => self.inner.insert(pos, (start, end.address)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, address: SectionAddress) -> bool {
|
||||
let pos = match self.inner.binary_search_by_key(&address, |&(start, _)| start) {
|
||||
Ok(_) => return true,
|
||||
Err(pos) => pos,
|
||||
};
|
||||
if pos == 0 {
|
||||
return false;
|
||||
}
|
||||
let (start, end) = &self.inner[pos - 1];
|
||||
start.section == address.section
|
||||
&& address.address >= start.address
|
||||
&& address.address < *end
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
let mut intervals = AddressRanges::new();
|
||||
intervals.insert(SectionAddress { section: 0, address: 0x80000000 }, SectionAddress {
|
||||
section: 0,
|
||||
address: 0x80000004,
|
||||
});
|
||||
intervals.insert(SectionAddress { section: 0, address: 0x80000008 }, SectionAddress {
|
||||
section: 0,
|
||||
address: 0x8000000C,
|
||||
});
|
||||
intervals.insert(SectionAddress { section: 12, address: 0x80004000 }, SectionAddress {
|
||||
section: 12,
|
||||
address: 0x80004004,
|
||||
});
|
||||
intervals.insert(SectionAddress { section: 12, address: 0x80004008 }, SectionAddress {
|
||||
section: 12,
|
||||
address: 0x8000400C,
|
||||
});
|
||||
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000000 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000001 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000002 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000003 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 0, address: 0x80000004 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 0, address: 0x80000005 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 0, address: 0x80000006 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 0, address: 0x80000007 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000008 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x80000009 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x8000000A }));
|
||||
assert!(intervals.contains(SectionAddress { section: 0, address: 0x8000000B }));
|
||||
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004000 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004001 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004002 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004003 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 12, address: 0x80004004 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 12, address: 0x80004005 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 12, address: 0x80004006 }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 12, address: 0x80004007 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004008 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x80004009 }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x8000400A }));
|
||||
assert!(intervals.contains(SectionAddress { section: 12, address: 0x8000400B }));
|
||||
assert!(!intervals.contains(SectionAddress { section: 12, address: 0x8000400C }));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
mod addresses;
|
||||
mod relocations;
|
||||
mod sections;
|
||||
mod splits;
|
||||
@@ -21,6 +22,7 @@ pub use symbols::{
|
||||
|
||||
use crate::{
|
||||
analysis::cfa::SectionAddress,
|
||||
obj::addresses::AddressRanges,
|
||||
util::{comment::MWComment, rel::RelReloc},
|
||||
};
|
||||
|
||||
@@ -69,7 +71,8 @@ pub struct ObjInfo {
|
||||
|
||||
// Extracted
|
||||
pub link_order: Vec<ObjUnit>,
|
||||
pub blocked_ranges: BTreeMap<SectionAddress, u32>, // start -> end
|
||||
pub blocked_relocation_sources: AddressRanges,
|
||||
pub blocked_relocation_targets: AddressRanges,
|
||||
|
||||
// From .ctors, .dtors and extab
|
||||
pub known_functions: BTreeMap<SectionAddress, Option<u32>>,
|
||||
@@ -105,7 +108,8 @@ impl ObjInfo {
|
||||
arena_lo: None,
|
||||
arena_hi: None,
|
||||
link_order: vec![],
|
||||
blocked_ranges: Default::default(),
|
||||
blocked_relocation_sources: Default::default(),
|
||||
blocked_relocation_targets: Default::default(),
|
||||
known_functions: Default::default(),
|
||||
module_id: 0,
|
||||
unresolved_relocations: vec![],
|
||||
|
||||
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::obj::SymbolIndex;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum ObjRelocKind {
|
||||
Absolute,
|
||||
PpcAddr16Hi,
|
||||
@@ -21,6 +21,39 @@ pub enum ObjRelocKind {
|
||||
PpcEmbSda21,
|
||||
}
|
||||
|
||||
impl Serialize for ObjRelocKind {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: serde::Serializer {
|
||||
serializer.serialize_str(match self {
|
||||
ObjRelocKind::Absolute => "abs",
|
||||
ObjRelocKind::PpcAddr16Hi => "hi",
|
||||
ObjRelocKind::PpcAddr16Ha => "ha",
|
||||
ObjRelocKind::PpcAddr16Lo => "l",
|
||||
ObjRelocKind::PpcRel24 => "rel24",
|
||||
ObjRelocKind::PpcRel14 => "rel14",
|
||||
ObjRelocKind::PpcEmbSda21 => "sda21",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ObjRelocKind {
|
||||
fn deserialize<D>(deserializer: D) -> Result<ObjRelocKind, D::Error>
|
||||
where D: serde::Deserializer<'de> {
|
||||
match String::deserialize(deserializer)?.as_str() {
|
||||
"Absolute" | "abs" => Ok(ObjRelocKind::Absolute),
|
||||
"PpcAddr16Hi" | "hi" => Ok(ObjRelocKind::PpcAddr16Hi),
|
||||
"PpcAddr16Ha" | "ha" => Ok(ObjRelocKind::PpcAddr16Ha),
|
||||
"PpcAddr16Lo" | "l" => Ok(ObjRelocKind::PpcAddr16Lo),
|
||||
"PpcRel24" | "rel24" => Ok(ObjRelocKind::PpcRel24),
|
||||
"PpcRel14" | "rel14" => Ok(ObjRelocKind::PpcRel14),
|
||||
"PpcEmbSda21" | "sda21" => Ok(ObjRelocKind::PpcEmbSda21),
|
||||
s => Err(serde::de::Error::unknown_variant(s, &[
|
||||
"abs", "hi", "ha", "l", "rel24", "rel14", "sda21",
|
||||
])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjReloc {
|
||||
pub kind: ObjRelocKind,
|
||||
|
||||
@@ -49,6 +49,8 @@ flags! {
|
||||
Stripped,
|
||||
/// Disable automatic export of symbol
|
||||
NoExport,
|
||||
/// Symbol does not contain any relocations
|
||||
NoReloc,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +101,9 @@ impl ObjSymbolFlagSet {
|
||||
#[inline]
|
||||
pub fn is_no_export(&self) -> bool { self.0.contains(ObjSymbolFlags::NoExport) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_no_reloc(&self) -> bool { self.0.contains(ObjSymbolFlags::NoReloc) }
|
||||
|
||||
#[inline]
|
||||
pub fn set_scope(&mut self, scope: ObjSymbolScope) {
|
||||
match scope {
|
||||
@@ -137,7 +142,8 @@ impl ObjSymbolFlagSet {
|
||||
| ObjSymbolFlags::NoWrite
|
||||
| ObjSymbolFlags::RelocationIgnore
|
||||
| ObjSymbolFlags::Stripped
|
||||
| ObjSymbolFlags::NoExport)
|
||||
| ObjSymbolFlags::NoExport
|
||||
| ObjSymbolFlags::NoReloc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user