@@ -13,7 +13,7 @@ use crate::{
13
13
code:: { diff_code, no_diff_code} ,
14
14
data:: {
15
15
diff_bss_section, diff_bss_symbol, diff_data_section, diff_data_symbol,
16
- diff_generic_section, no_diff_bss_section, no_diff_data_section,
16
+ diff_generic_section, no_diff_bss_section, no_diff_data_section, symbol_name_matches ,
17
17
} ,
18
18
} ,
19
19
obj:: { InstructionRef , Object , Relocation , SectionKind , Symbol , SymbolFlag } ,
@@ -575,47 +575,60 @@ fn matching_symbols(
575
575
& mut matches,
576
576
) ?;
577
577
}
578
- for ( symbol_idx, symbol) in left. symbols . iter ( ) . enumerate ( ) {
579
- if symbol. size == 0 || symbol. flags . contains ( SymbolFlag :: Ignored ) {
580
- continue ;
581
- }
582
- let section_kind = symbol_section_kind ( left, symbol) ;
583
- if section_kind == SectionKind :: Unknown {
584
- continue ;
585
- }
586
- if left_used. contains ( & symbol_idx) {
587
- continue ;
588
- }
589
- let symbol_match = SymbolMatch {
590
- left : Some ( symbol_idx) ,
591
- right : find_symbol ( right, left, symbol, Some ( & right_used) ) ,
592
- prev : find_symbol ( prev, left, symbol, None ) ,
593
- section_kind,
594
- } ;
595
- matches. push ( symbol_match) ;
596
- if let Some ( right) = symbol_match. right {
597
- right_used. insert ( right) ;
578
+ // Do two passes for nameless literals. The first only pairs up perfect matches to ensure
579
+ // those are correct first, while the second pass catches near matches.
580
+ for fuzzy_literals in [ false , true ] {
581
+ for ( symbol_idx, symbol) in left. symbols . iter ( ) . enumerate ( ) {
582
+ if symbol. size == 0 || symbol. flags . contains ( SymbolFlag :: Ignored ) {
583
+ continue ;
584
+ }
585
+ let section_kind = symbol_section_kind ( left, symbol) ;
586
+ if section_kind == SectionKind :: Unknown {
587
+ continue ;
588
+ }
589
+ if left_used. contains ( & symbol_idx) {
590
+ continue ;
591
+ }
592
+ let symbol_match = SymbolMatch {
593
+ left : Some ( symbol_idx) ,
594
+ right : find_symbol ( right, left, symbol_idx, Some ( & right_used) , fuzzy_literals) ,
595
+ prev : find_symbol ( prev, left, symbol_idx, None , fuzzy_literals) ,
596
+ section_kind,
597
+ } ;
598
+ matches. push ( symbol_match) ;
599
+ if let Some ( right) = symbol_match. right {
600
+ left_used. insert ( symbol_idx) ;
601
+ right_used. insert ( right) ;
602
+ }
598
603
}
599
604
}
600
605
}
601
606
if let Some ( right) = right {
602
- for ( symbol_idx, symbol) in right. symbols . iter ( ) . enumerate ( ) {
603
- if symbol. size == 0 || symbol. flags . contains ( SymbolFlag :: Ignored ) {
604
- continue ;
605
- }
606
- let section_kind = symbol_section_kind ( right, symbol) ;
607
- if section_kind == SectionKind :: Unknown {
608
- continue ;
609
- }
610
- if right_used. contains ( & symbol_idx) {
611
- continue ;
607
+ // Do two passes for nameless literals. The first only pairs up perfect matches to ensure
608
+ // those are correct first, while the second pass catches near matches.
609
+ for fuzzy_literals in [ false , true ] {
610
+ for ( symbol_idx, symbol) in right. symbols . iter ( ) . enumerate ( ) {
611
+ if symbol. size == 0 || symbol. flags . contains ( SymbolFlag :: Ignored ) {
612
+ continue ;
613
+ }
614
+ let section_kind = symbol_section_kind ( right, symbol) ;
615
+ if section_kind == SectionKind :: Unknown {
616
+ continue ;
617
+ }
618
+ if right_used. contains ( & symbol_idx) {
619
+ continue ;
620
+ }
621
+ let symbol_match = SymbolMatch {
622
+ left : None ,
623
+ right : Some ( symbol_idx) ,
624
+ prev : find_symbol ( prev, right, symbol_idx, None , fuzzy_literals) ,
625
+ section_kind,
626
+ } ;
627
+ matches. push ( symbol_match) ;
628
+ if symbol_match. prev . is_some ( ) {
629
+ right_used. insert ( symbol_idx) ;
630
+ }
612
631
}
613
- matches. push ( SymbolMatch {
614
- left : None ,
615
- right : Some ( symbol_idx) ,
616
- prev : find_symbol ( prev, right, symbol, None ) ,
617
- section_kind,
618
- } ) ;
619
632
}
620
633
}
621
634
Ok ( matches)
@@ -637,7 +650,10 @@ where
637
650
638
651
fn symbol_section < ' obj > ( obj : & ' obj Object , symbol : & Symbol ) -> Option < ( & ' obj str , SectionKind ) > {
639
652
if let Some ( section) = symbol. section . and_then ( |section_idx| obj. sections . get ( section_idx) ) {
640
- Some ( ( section. name . as_str ( ) , section. kind ) )
653
+ // Match x86 .rdata$r against .rdata$rs
654
+ let section_name =
655
+ section. name . split_once ( '$' ) . map_or ( section. name . as_str ( ) , |( prefix, _) | prefix) ;
656
+ Some ( ( section_name, section. kind ) )
641
657
} else if symbol. flags . contains ( SymbolFlag :: Common ) {
642
658
Some ( ( ".comm" , SectionKind :: Common ) )
643
659
} else {
@@ -653,52 +669,94 @@ fn symbol_section_kind(obj: &Object, symbol: &Symbol) -> SectionKind {
653
669
}
654
670
}
655
671
672
+ /// Check if a symbol is a compiler-generated literal like @1234.
673
+ fn is_symbol_compiler_generated_literal ( symbol : & Symbol ) -> bool {
674
+ if !symbol. name . starts_with ( '@' ) {
675
+ return false ;
676
+ }
677
+ if !symbol. name [ 1 ..] . chars ( ) . all ( char:: is_numeric) {
678
+ // Exclude @stringBase0, @GUARD@, etc.
679
+ return false ;
680
+ }
681
+ true
682
+ }
683
+
656
684
fn find_symbol (
657
685
obj : Option < & Object > ,
658
686
in_obj : & Object ,
659
- in_symbol : & Symbol ,
687
+ in_symbol_idx : usize ,
660
688
used : Option < & BTreeSet < usize > > ,
689
+ fuzzy_literals : bool ,
661
690
) -> Option < usize > {
691
+ let in_symbol = & in_obj. symbols [ in_symbol_idx] ;
662
692
let obj = obj?;
663
693
let ( section_name, section_kind) = symbol_section ( in_obj, in_symbol) ?;
694
+
695
+ // Match compiler-generated symbols against each other (e.g. @251 -> @60)
696
+ // If they are in the same section and have the same value
697
+ if is_symbol_compiler_generated_literal ( in_symbol)
698
+ && matches ! ( section_kind, SectionKind :: Data | SectionKind :: Bss )
699
+ {
700
+ let mut closest_match_symbol_idx = None ;
701
+ let mut closest_match_percent = 0.0 ;
702
+ for ( symbol_idx, symbol) in unmatched_symbols ( obj, used) {
703
+ let Some ( section_index) = symbol. section else {
704
+ continue ;
705
+ } ;
706
+ if obj. sections [ section_index] . name != section_name {
707
+ continue ;
708
+ }
709
+ if !is_symbol_compiler_generated_literal ( symbol) {
710
+ continue ;
711
+ }
712
+ match section_kind {
713
+ SectionKind :: Data => {
714
+ // For data, pick the first symbol with exactly matching bytes and relocations.
715
+ // If no symbols match exactly, and `fuzzy_literals` is true, pick the closest
716
+ // plausible match instead.
717
+ if let Ok ( ( left_diff, _right_diff) ) =
718
+ diff_data_symbol ( in_obj, obj, in_symbol_idx, symbol_idx)
719
+ && let Some ( match_percent) = left_diff. match_percent
720
+ && ( match_percent == 100.0
721
+ || ( fuzzy_literals
722
+ && match_percent >= 50.0
723
+ && match_percent > closest_match_percent) )
724
+ {
725
+ closest_match_symbol_idx = Some ( symbol_idx) ;
726
+ closest_match_percent = match_percent;
727
+ if match_percent == 100.0 {
728
+ break ;
729
+ }
730
+ }
731
+ }
732
+ SectionKind :: Bss => {
733
+ // For BSS, pick the first symbol that has the exact matching size.
734
+ if in_symbol. size == symbol. size {
735
+ closest_match_symbol_idx = Some ( symbol_idx) ;
736
+ break ;
737
+ }
738
+ }
739
+ _ => unreachable ! ( ) ,
740
+ }
741
+ }
742
+ return closest_match_symbol_idx;
743
+ }
744
+
664
745
// Try to find an exact name match
665
746
if let Some ( ( symbol_idx, _) ) = unmatched_symbols ( obj, used) . find ( |( _, symbol) | {
666
747
symbol. name == in_symbol. name && symbol_section_kind ( obj, symbol) == section_kind
667
748
} ) {
668
749
return Some ( symbol_idx) ;
669
750
}
670
- // 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 ( '@' )
673
- && matches ! ( section_kind, SectionKind :: Data | SectionKind :: Bss )
674
- && let Some ( ( symbol_idx, _) ) = unmatched_symbols ( obj, used) . find ( |( _, symbol) | {
675
- let Some ( section_index) = symbol. section else {
676
- return false ;
677
- } ;
678
- symbol. name . starts_with ( '@' )
679
- && symbol. address == in_symbol. address
680
- && obj. sections [ section_index] . name == section_name
681
- } )
682
- {
751
+
752
+ if let Some ( ( symbol_idx, _) ) = unmatched_symbols ( obj, used) . find ( |& ( _, symbol) | {
753
+ symbol_name_matches ( & in_symbol. name , & symbol. name )
754
+ && symbol_section_kind ( obj, symbol) == section_kind
755
+ && symbol_section ( obj, symbol) . is_some_and ( |( name, _) | name == section_name)
756
+ } ) {
683
757
return Some ( symbol_idx) ;
684
758
}
685
- // Match Metrowerks symbol$1234 against symbol$2345
686
- if let Some ( ( prefix, suffix) ) = in_symbol. name . split_once ( '$' ) {
687
- if !suffix. chars ( ) . all ( char:: is_numeric) {
688
- return None ;
689
- }
690
- if let Some ( ( symbol_idx, _) ) = unmatched_symbols ( obj, used) . find ( |& ( _, symbol) | {
691
- if let Some ( ( p, s) ) = symbol. name . split_once ( '$' ) {
692
- prefix == p
693
- && s. chars ( ) . all ( char:: is_numeric)
694
- && symbol_section_kind ( obj, symbol) == section_kind
695
- } else {
696
- false
697
- }
698
- } ) {
699
- return Some ( symbol_idx) ;
700
- }
701
- }
759
+
702
760
None
703
761
}
704
762
0 commit comments