From 57020e7c64fb9d2f9c00f35e88bff3b9d6d4baea Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Wed, 17 Dec 2025 23:29:29 -0500 Subject: [PATCH 1/3] Fix `__arraydtor$1234`s sometimes being swapped The list of symbols is not necessarily sorted by address, so if there are multiple `__arraydtor$1234` functions it's possible that they're in reverse order on the right, which would cause them to be paired up incorrectly. To fix this we sort by section index and symbol address after filtering down the list of symbols to ones that have matching names. --- objdiff-core/src/diff/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index efbe2c2b..2cbf7abf 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -7,6 +7,7 @@ use alloc::{ use core::{num::NonZeroU32, ops::Range}; use anyhow::Result; +use itertools::Itertools; use crate::{ diff::{ @@ -766,11 +767,15 @@ fn find_symbol( return Some(symbol_idx); } - if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|&(_, symbol)| { - symbol_name_matches(&in_symbol.name, &symbol.name) - && symbol_section_kind(obj, symbol) == section_kind - && symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name) - }) { + if let Some((symbol_idx, _)) = unmatched_symbols(obj, used) + .filter(|&(_, symbol)| { + symbol_name_matches(&in_symbol.name, &symbol.name) + && symbol_section_kind(obj, symbol) == section_kind + && symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name) + }) + .sorted_unstable_by_key(|&(_, symbol)| (symbol.section, symbol.address)) + .next() + { return Some(symbol_idx); } From cb625443ae397b42860a90aba8b8b5a6a4e43b74 Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Wed, 17 Dec 2025 23:32:40 -0500 Subject: [PATCH 2/3] Support pairing up symbols for anonymous classes --- objdiff-core/src/diff/data.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index 73b9175e..cfaabb81 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -36,9 +36,23 @@ pub fn diff_bss_symbol( } pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool { - // Match Metrowerks symbol$1234 against symbol$2345 - // and GCC symbol.1234 against symbol.2345 - if let Some((prefix, suffix)) = left_name.split_once(['$', '.']) { + if let Some((left_prefix, left_suffix)) = left_name.split_once("@class$") + && let Some((right_prefix, right_suffix)) = right_name.split_once("@class$") + { + // Match Metrowerks anonymous class symbol names, ignoring the unique ID. + // e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv + if left_prefix == right_prefix + && let Some(left_idx) = left_suffix.chars().position(|c| !c.is_numeric()) + && let Some(right_idx) = right_suffix.chars().position(|c| !c.is_numeric()) + { + // e.g. d_camera_cppFv (after the unique ID) + left_suffix[left_idx..] == right_suffix[right_idx..] + } else { + false + } + } else if let Some((prefix, suffix)) = left_name.split_once(['$', '.']) { + // Match Metrowerks symbol$1234 against symbol$2345 + // and GCC symbol.1234 against symbol.2345 if !suffix.chars().all(char::is_numeric) { return false; } From 23421bed8ababcb2c8f90d3af96498c341d7bb9b Mon Sep 17 00:00:00 2001 From: LagoLunatic Date: Fri, 19 Dec 2025 21:38:57 -0500 Subject: [PATCH 3/3] Disallow exact-name pairups for compiler-generated symbols --- objdiff-core/src/diff/data.rs | 7 +++---- objdiff-core/src/diff/mod.rs | 8 +------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/objdiff-core/src/diff/data.rs b/objdiff-core/src/diff/data.rs index cfaabb81..5eeed55f 100644 --- a/objdiff-core/src/diff/data.rs +++ b/objdiff-core/src/diff/data.rs @@ -50,12 +50,11 @@ pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool { } else { false } - } else if let Some((prefix, suffix)) = left_name.split_once(['$', '.']) { + } else if let Some((prefix, suffix)) = left_name.split_once(['$', '.']) + && suffix.chars().all(char::is_numeric) + { // Match Metrowerks symbol$1234 against symbol$2345 // and GCC symbol.1234 against symbol.2345 - if !suffix.chars().all(char::is_numeric) { - return false; - } right_name .split_once(['$', '.']) .is_some_and(|(p, s)| p == prefix && s.chars().all(char::is_numeric)) diff --git a/objdiff-core/src/diff/mod.rs b/objdiff-core/src/diff/mod.rs index 2cbf7abf..c8c9c316 100644 --- a/objdiff-core/src/diff/mod.rs +++ b/objdiff-core/src/diff/mod.rs @@ -760,13 +760,7 @@ fn find_symbol( return closest_match_symbol_idx; } - // Try to find an exact name match - if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| { - symbol.name == in_symbol.name && symbol_section_kind(obj, symbol) == section_kind - }) { - return Some(symbol_idx); - } - + // Try to find a symbol with a matching name if let Some((symbol_idx, _)) = unmatched_symbols(obj, used) .filter(|&(_, symbol)| { symbol_name_matches(&in_symbol.name, &symbol.name)