Skip to content

Commit 88cc76d

Browse files
committed
Improve automatic symbol pairing for nameless literals
1 parent 7c424a7 commit 88cc76d

File tree

1 file changed

+74
-19
lines changed

1 file changed

+74
-19
lines changed

objdiff-core/src/diff/mod.rs

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,8 @@ fn matching_symbols(
588588
}
589589
let symbol_match = SymbolMatch {
590590
left: Some(symbol_idx),
591-
right: find_symbol(right, left, symbol, Some(&right_used)),
592-
prev: find_symbol(prev, left, symbol, None),
591+
right: find_symbol(right, left, symbol_idx, Some(&right_used)),
592+
prev: find_symbol(prev, left, symbol_idx, None),
593593
section_kind,
594594
};
595595
matches.push(symbol_match);
@@ -613,7 +613,7 @@ fn matching_symbols(
613613
matches.push(SymbolMatch {
614614
left: None,
615615
right: Some(symbol_idx),
616-
prev: find_symbol(prev, right, symbol, None),
616+
prev: find_symbol(prev, right, symbol_idx, None),
617617
section_kind,
618618
});
619619
}
@@ -645,6 +645,13 @@ fn symbol_section<'obj>(obj: &'obj Object, symbol: &Symbol) -> Option<(&'obj str
645645
}
646646
}
647647

648+
fn symbol_section_name<'obj>(obj: &'obj Object, symbol: &Symbol) -> Option<&'obj str> {
649+
if let Some((name, _kind)) = symbol_section(obj, symbol) {
650+
return Some(name);
651+
}
652+
None
653+
}
654+
648655
fn symbol_section_kind(obj: &Object, symbol: &Symbol) -> SectionKind {
649656
match symbol.section {
650657
Some(section_index) => obj.sections[section_index].kind,
@@ -653,35 +660,81 @@ fn symbol_section_kind(obj: &Object, symbol: &Symbol) -> SectionKind {
653660
}
654661
}
655662

663+
/// Check if a symbol is a compiler-generated literal like @1234.
664+
fn is_symbol_compiler_generated_literal(symbol: &Symbol) -> bool {
665+
if !symbol.name.starts_with('@') {
666+
return false;
667+
}
668+
if !symbol.name[1..].chars().all(char::is_numeric) {
669+
// Exclude @stringBase0, @GUARD@, etc.
670+
return false;
671+
}
672+
return true;
673+
}
674+
656675
fn find_symbol(
657676
obj: Option<&Object>,
658677
in_obj: &Object,
659-
in_symbol: &Symbol,
678+
in_symbol_idx: usize,
660679
used: Option<&BTreeSet<usize>>,
661680
) -> Option<usize> {
681+
let in_symbol = &in_obj.symbols[in_symbol_idx];
662682
let obj = obj?;
663683
let (section_name, section_kind) = symbol_section(in_obj, in_symbol)?;
664-
// Try to find an exact name match
665-
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
666-
symbol.name == in_symbol.name && symbol_section_kind(obj, symbol) == section_kind
667-
}) {
668-
return Some(symbol_idx);
669-
}
684+
670685
// Match compiler-generated symbols against each other (e.g. @251 -> @60)
671-
// If they are at the same address in the same section
672-
if in_symbol.name.starts_with('@')
686+
// If they are in the same section and have the same value
687+
if is_symbol_compiler_generated_literal(in_symbol)
673688
&& matches!(section_kind, SectionKind::Data | SectionKind::Bss)
674-
&& let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
689+
{
690+
let mut closest_match_symbol_idx = None;
691+
let mut closest_match_percent = 0.0;
692+
for (symbol_idx, symbol) in unmatched_symbols(obj, used) {
675693
let Some(section_index) = symbol.section else {
676-
return false;
694+
continue;
677695
};
678-
symbol.name.starts_with('@')
679-
&& symbol.address == in_symbol.address
680-
&& obj.sections[section_index].name == section_name
681-
})
682-
{
696+
if obj.sections[section_index].name != section_name {
697+
continue;
698+
}
699+
if !is_symbol_compiler_generated_literal(symbol) {
700+
continue;
701+
}
702+
match section_kind {
703+
SectionKind::Data => {
704+
// For data, we try to pick the first symbol that matches 100%.
705+
// If no symbol is a perfect match, pick whichever matches the closest.
706+
if let Ok((left_diff, _right_diff)) =
707+
diff_data_symbol(in_obj, obj, in_symbol_idx, symbol_idx)
708+
&& let Some(match_percent) = left_diff.match_percent
709+
&& match_percent > closest_match_percent
710+
{
711+
closest_match_symbol_idx = Some(symbol_idx);
712+
closest_match_percent = match_percent;
713+
if match_percent == 100.0 {
714+
break;
715+
}
716+
}
717+
}
718+
SectionKind::Bss => {
719+
// For BSS, we simply pick the first symbol that has the exact matching size.
720+
if in_symbol.size == symbol.size {
721+
closest_match_symbol_idx = Some(symbol_idx);
722+
break;
723+
}
724+
}
725+
_ => unreachable!(),
726+
}
727+
}
728+
return closest_match_symbol_idx;
729+
}
730+
731+
// Try to find an exact name match
732+
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
733+
symbol.name == in_symbol.name && symbol_section_kind(obj, symbol) == section_kind
734+
}) {
683735
return Some(symbol_idx);
684736
}
737+
685738
// Match Metrowerks symbol$1234 against symbol$2345
686739
if let Some((prefix, suffix)) = in_symbol.name.split_once('$') {
687740
if !suffix.chars().all(char::is_numeric) {
@@ -692,13 +745,15 @@ fn find_symbol(
692745
prefix == p
693746
&& s.chars().all(char::is_numeric)
694747
&& symbol_section_kind(obj, symbol) == section_kind
748+
&& symbol_section_name(obj, symbol) == Some(section_name)
695749
} else {
696750
false
697751
}
698752
}) {
699753
return Some(symbol_idx);
700754
}
701755
}
756+
702757
None
703758
}
704759

0 commit comments

Comments
 (0)