From 821fcdb749252021c133199dae9d718779765a1c Mon Sep 17 00:00:00 2001 From: rjkiv <76180273+rjkiv@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:31:43 -0700 Subject: [PATCH 1/4] automatically match MSVC symbols in anonymous namespaces --- objdiff-core/src/obj/read.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index a8aa1dd..d1a02a4 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -6,10 +6,10 @@ use alloc::{ vec, vec::Vec, }; -use core::{cmp::Ordering, num::NonZeroU64}; - use anyhow::{Context, Result, anyhow, bail, ensure}; +use core::{cmp::Ordering, num::NonZeroU64}; use object::{Object as _, ObjectSection as _, ObjectSymbol as _}; +use regex::Regex; use crate::{ arch::{Arch, RelocationOverride, RelocationOverrideTarget, new_arch}, @@ -40,6 +40,7 @@ fn map_section_kind(section: &object::Section) -> SectionKind { /// e.g. symbol$1234 and symbol$2345 will both be replaced with symbol$0000 internally. fn get_normalized_symbol_name(name: &str) -> Option { const DUMMY_UNIQUE_ID: &str = "0000"; + const DUMMY_UNIQUE_MSVC_ID: &str = "00000000"; if let Some((prefix, suffix)) = name.split_once("@class$") && let Some(idx) = suffix.chars().position(|c| !c.is_numeric()) && idx > 0 @@ -59,6 +60,14 @@ fn get_normalized_symbol_name(name: &str) -> Option { { // Match GCC symbol.1234 against symbol.2345 Some(format!("{prefix}.{DUMMY_UNIQUE_ID}")) + } else if name.starts_with('?') { + // We're likely working with an MSVC symbol, so check for anonymous namespaces and zero out the hashes + Some( + Regex::new(r"\?A0x[0-9A-Fa-f]{8}@@") + .unwrap() + .replace_all(name, format!("?Ax{DUMMY_UNIQUE_MSVC_ID}@@")) + .to_string(), + ) } else { None } From 31c1648067c2d1cf8a91eaaf90a9af20892c187a Mon Sep 17 00:00:00 2001 From: rjkiv <76180273+rjkiv@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:43:29 -0700 Subject: [PATCH 2/4] tweak logic for detecting anonymous MSVC symbols --- objdiff-core/src/obj/read.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index d1a02a4..bdd2f04 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -60,16 +60,16 @@ fn get_normalized_symbol_name(name: &str) -> Option { { // Match GCC symbol.1234 against symbol.2345 Some(format!("{prefix}.{DUMMY_UNIQUE_ID}")) - } else if name.starts_with('?') { - // We're likely working with an MSVC symbol, so check for anonymous namespaces and zero out the hashes - Some( - Regex::new(r"\?A0x[0-9A-Fa-f]{8}@@") - .unwrap() - .replace_all(name, format!("?Ax{DUMMY_UNIQUE_MSVC_ID}@@")) - .to_string(), - ) } else { - None + let re = Regex::new(r"\?A0x[0-9A-Fa-f]{8}@@").unwrap(); + // Match MSVC anonymous class symbol names, ignoring the unique ID. + // e.g. ?CheckContextOr@?A0x24773155@@YA_NPBVDataArray@@@Z + // and: ?CheckContextOr@?A0xddf6240c@@YA_NPBVDataArray@@@Z + if name.starts_with('?') && re.is_match(name) { + Some(re.replace_all(name, format!("?Ax{DUMMY_UNIQUE_MSVC_ID}@@")).to_string()) + } else { + None + } } } From 25069e51d8d9743c5d37df32ff30a6fa738c81c3 Mon Sep 17 00:00:00 2001 From: rjkiv <76180273+rjkiv@users.noreply.github.com> Date: Sun, 25 Jan 2026 11:46:45 -0700 Subject: [PATCH 3/4] fix package format --- objdiff-core/src/obj/read.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index bdd2f04..4fa9583 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -6,8 +6,9 @@ use alloc::{ vec, vec::Vec, }; -use anyhow::{Context, Result, anyhow, bail, ensure}; use core::{cmp::Ordering, num::NonZeroU64}; + +use anyhow::{Context, Result, anyhow, bail, ensure}; use object::{Object as _, ObjectSection as _, ObjectSymbol as _}; use regex::Regex; From a63e658298e4c4f66e7a905483d2f5c0f3f6cc48 Mon Sep 17 00:00:00 2001 From: rjkiv <76180273+rjkiv@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:07:52 -0700 Subject: [PATCH 4/4] address feedback --- objdiff-core/src/obj/read.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/objdiff-core/src/obj/read.rs b/objdiff-core/src/obj/read.rs index 4fa9583..e41e46d 100644 --- a/objdiff-core/src/obj/read.rs +++ b/objdiff-core/src/obj/read.rs @@ -61,16 +61,18 @@ fn get_normalized_symbol_name(name: &str) -> Option { { // Match GCC symbol.1234 against symbol.2345 Some(format!("{prefix}.{DUMMY_UNIQUE_ID}")) - } else { - let re = Regex::new(r"\?A0x[0-9A-Fa-f]{8}@@").unwrap(); + } else if name.starts_with('?') { // Match MSVC anonymous class symbol names, ignoring the unique ID. // e.g. ?CheckContextOr@?A0x24773155@@YA_NPBVDataArray@@@Z // and: ?CheckContextOr@?A0xddf6240c@@YA_NPBVDataArray@@@Z - if name.starts_with('?') && re.is_match(name) { - Some(re.replace_all(name, format!("?Ax{DUMMY_UNIQUE_MSVC_ID}@@")).to_string()) + let re = Regex::new(r"\?A0x[0-9A-Fa-f]{8}@@").unwrap(); + if re.is_match(name) { + Some(re.replace_all(name, format!("?A0x{DUMMY_UNIQUE_MSVC_ID}@@")).to_string()) } else { None } + } else { + None } }