From 52b777e498ebd8710d970ba117fcf3139024e3bc Mon Sep 17 00:00:00 2001 From: h1467792822 <1467792822@qq.com> Date: Tue, 5 Dec 2023 12:42:57 +0800 Subject: [PATCH] MCP #705: Provide the option `-Zsymbol-mangling-version=hashed` to shorten symbol names by replacing them with a digest. Enrich test cases --- compiler/rustc_session/src/config.rs | 37 +++++++++++++-- compiler/rustc_session/src/options.rs | 9 +++- compiler/rustc_symbol_mangling/src/hashed.rs | 27 +++++++++++ compiler/rustc_symbol_mangling/src/lib.rs | 4 ++ .../run-make/symbol-mangling-version/Makefile | 47 +++++++++++++++++++ .../symbol-mangling-version/a_dylib.rs | 4 ++ .../symbol-mangling-version/a_rlib.rs | 5 ++ .../run-make/symbol-mangling-version/b_bin.rs | 9 ++++ .../symbol-mangling-version/b_dylib.rs | 9 ++++ .../bad-value.bad.stderr | 2 +- .../bad-value.blank.stderr | 2 +- .../bad-value.no-value.stderr | 2 +- .../unstable.hashed.stderr | 2 + tests/ui/symbol-mangling-version/unstable.rs | 5 +- 14 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_symbol_mangling/src/hashed.rs create mode 100644 tests/run-make/symbol-mangling-version/Makefile create mode 100644 tests/run-make/symbol-mangling-version/a_dylib.rs create mode 100644 tests/run-make/symbol-mangling-version/a_rlib.rs create mode 100644 tests/run-make/symbol-mangling-version/b_bin.rs create mode 100644 tests/run-make/symbol-mangling-version/b_dylib.rs create mode 100644 tests/ui/symbol-mangling-version/unstable.hashed.stderr diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ac15c3b407b27..93eea88261f0a 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -347,6 +347,7 @@ impl SwitchWithOptPath { pub enum SymbolManglingVersion { Legacy, V0, + Hashed, } #[derive(Clone, Copy, Debug, PartialEq, Hash)] @@ -2689,17 +2690,37 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M // Check for unstable values of `-C symbol-mangling-version`. // This is what prevents them from being used on stable compilers. - match cg.symbol_mangling_version { - // Stable values: - None | Some(SymbolManglingVersion::V0) => {} - // Unstable values: - Some(SymbolManglingVersion::Legacy) => { + match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) { + (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { + early_dcx.early_fatal( + "incompatible values passed for `-C symbol-mangling-version` \ + and `-Z symbol-mangling-version`", + ); + } + + (Some(SymbolManglingVersion::Legacy), _) => { if !unstable_opts.unstable_options { early_dcx.early_fatal( "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", ); } } + (Some(SymbolManglingVersion::Hashed), _) => { + if !unstable_opts.unstable_options { + early_dcx.early_fatal( + "`-C symbol-mangling-version=hashed` requires `-Z unstable-options`", + ); + } + } + + // Stable values: + (Some(SymbolManglingVersion::V0), _) => {} + (None, None) => {} + + // Unstable values: + (None, smv) => { + cg.symbol_mangling_version = smv; + } } // Check for unstable values of `-C instrument-coverage`. @@ -2741,6 +2762,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ); } Some(SymbolManglingVersion::V0) => {} + Some(SymbolManglingVersion::Hashed) => { + early_dcx.early_warn( + "-C instrument-coverage requires symbol mangling version `v0`, \ + but `-Z symbol-mangling-version=hashed` was specified", + ); + } } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f4bf79f93f287..23d81ff18316b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -406,7 +406,8 @@ mod desc { pub const parse_switch_with_opt_path: &str = "an optional path to the profiling data output directory"; pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`"; - pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)"; + pub const parse_symbol_mangling_version: &str = + "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; @@ -1179,6 +1180,7 @@ mod parse { *slot = match v { Some("legacy") => Some(SymbolManglingVersion::Legacy), Some("v0") => Some(SymbolManglingVersion::V0), + Some("hashed") => Some(SymbolManglingVersion::Hashed), _ => return false, }; true @@ -1490,7 +1492,7 @@ options! { "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option = (None, parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), + "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"), target_cpu: Option = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], @@ -1880,6 +1882,9 @@ written to standard error output)"), "prefer dynamic linking to static linking for staticlibs (default: no)"), strict_init_checks: bool = (false, parse_bool, [TRACKED], "control if mem::uninitialized and mem::zeroed panic on more UB"), + symbol_mangling_version: Option = (None, + parse_symbol_mangling_version, [TRACKED], + "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"), #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), diff --git a/compiler/rustc_symbol_mangling/src/hashed.rs b/compiler/rustc_symbol_mangling/src/hashed.rs new file mode 100644 index 0000000000000..272980520c732 --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/hashed.rs @@ -0,0 +1,27 @@ +use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; +use rustc_hir::def_id::CrateNum; +use rustc_middle::ty::{Instance, TyCtxt}; + +pub(super) fn mangle<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + instantiating_crate: Option, + full_mangling_name: impl FnOnce() -> String, +) -> String { + // A generic function of an upstream library can be included in a dylib that depends on it. + // In this case, `instantiating-crate name` is used to replace `crate name`. + // If hash conflicats with other APIs in dylib, the method can be detected immediately. + // Based on `instantiating-crate name`, symbol conflicts with other dylibs are avoided. + let crate_num = + if let Some(krate) = instantiating_crate { krate } else { instance.def_id().krate }; + let crate_name = tcx.crate_name(crate_num); + let crate_name = crate_name.as_str(); + + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + full_mangling_name().hash_stable(&mut hcx, &mut hasher); + hasher.finish::().as_u64() + }); + + format!("_RNxC{}{crate_name}19H{hash:016x}", crate_name.len()) +} diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 8c035ba948b15..bf4ea0003abb4 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -111,6 +111,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; +mod hashed; mod legacy; mod v0; @@ -265,6 +266,9 @@ fn compute_symbol_name<'tcx>( let symbol = match mangling_version { SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || { + v0::mangle(tcx, instance, instantiating_crate) + }), }; debug_assert!( diff --git a/tests/run-make/symbol-mangling-version/Makefile b/tests/run-make/symbol-mangling-version/Makefile new file mode 100644 index 0000000000000..1f46900f36bb5 --- /dev/null +++ b/tests/run-make/symbol-mangling-version/Makefile @@ -0,0 +1,47 @@ +# ignore-cross-compile +include ../tools.mk + +# ignore-windows-msvc + +NM=nm -D +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.so +SO_NAME=libb_dylib.so +BIN_NAME=b_bin + +ifeq ($(UNAME),Darwin) +NM=nm -gU +RLIB_NAME=liba_rlib.rlib +DYLIB_NAME=liba_dylib.dylib +SO_NAME=libb_dylib.dylib +BIN_NAME=b_bin +endif + +ifdef IS_WINDOWS +NM=nm -g +RLIB_NAME=liba_rlib.dll.a +DYLIB_NAME=liba_dylib.dll +SO_NAME=libb_dylib.dll +BIN_NAME=b_bin.exe +endif + +all: + $(RUSTC) -C prefer-dynamic -Z symbol-mangling-version=hashed -C metadata=foo a_dylib.rs + $(RUSTC) -C prefer-dynamic -Z symbol-mangling-version=hashed -C metadata=bar a_rlib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_dylib.rs + $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_bin.rs + + # Check hashed symbol name + + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep -c hello)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep a_dylib19H | grep -c ' T ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep b_dylib | grep -c hello)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep a_rlib19H | grep -c ' T ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep a_dylib19H | grep -c ' U ')" -eq "1" ] + + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep a_rlib19H | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep a_dylib19H | grep -c ' U ')" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep b_dylib | grep hello | grep -c ' U ')" -eq "1" ] + + $(call RUN,$(BIN_NAME)) diff --git a/tests/run-make/symbol-mangling-version/a_dylib.rs b/tests/run-make/symbol-mangling-version/a_dylib.rs new file mode 100644 index 0000000000000..8aec8fd82a53f --- /dev/null +++ b/tests/run-make/symbol-mangling-version/a_dylib.rs @@ -0,0 +1,4 @@ +#![crate_type="dylib"] +pub fn hello() { + println!("hello dylib"); +} diff --git a/tests/run-make/symbol-mangling-version/a_rlib.rs b/tests/run-make/symbol-mangling-version/a_rlib.rs new file mode 100644 index 0000000000000..873c86c5d0b4c --- /dev/null +++ b/tests/run-make/symbol-mangling-version/a_rlib.rs @@ -0,0 +1,5 @@ +#![crate_type="rlib"] + +pub fn hello() { + println!("hello rlib"); +} diff --git a/tests/run-make/symbol-mangling-version/b_bin.rs b/tests/run-make/symbol-mangling-version/b_bin.rs new file mode 100644 index 0000000000000..bcc53c37e122a --- /dev/null +++ b/tests/run-make/symbol-mangling-version/b_bin.rs @@ -0,0 +1,9 @@ +extern crate a_rlib; +extern crate a_dylib; +extern crate b_dylib; + +fn main() { + a_rlib::hello(); + a_dylib::hello(); + b_dylib::hello(); +} diff --git a/tests/run-make/symbol-mangling-version/b_dylib.rs b/tests/run-make/symbol-mangling-version/b_dylib.rs new file mode 100644 index 0000000000000..c26a04b39ec32 --- /dev/null +++ b/tests/run-make/symbol-mangling-version/b_dylib.rs @@ -0,0 +1,9 @@ +#![crate_type="dylib"] + +extern crate a_rlib; +extern crate a_dylib; + +pub fn hello() { + a_rlib::hello(); + a_dylib::hello(); +} diff --git a/tests/ui/symbol-mangling-version/bad-value.bad.stderr b/tests/ui/symbol-mangling-version/bad-value.bad.stderr index c36c73c6069f1..a12e5e241c022 100644 --- a/tests/ui/symbol-mangling-version/bad-value.bad.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `bad-value` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.blank.stderr b/tests/ui/symbol-mangling-version/bad-value.blank.stderr index 0e70af5b8ffbe..95456587781e6 100644 --- a/tests/ui/symbol-mangling-version/bad-value.blank.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.blank.stderr @@ -1,2 +1,2 @@ -error: incorrect value `` for codegen option `symbol-mangling-version` - either `legacy` or `v0` (RFC 2603) was expected +error: incorrect value `` for codegen option `symbol-mangling-version` - one of: `legacy`, `v0` (RFC 2603), or `hashed` was expected diff --git a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr index 77013b72b6c1d..325e47a281fae 100644 --- a/tests/ui/symbol-mangling-version/bad-value.no-value.stderr +++ b/tests/ui/symbol-mangling-version/bad-value.no-value.stderr @@ -1,2 +1,2 @@ -error: codegen option `symbol-mangling-version` requires either `legacy` or `v0` (RFC 2603) (C symbol-mangling-version=) +error: codegen option `symbol-mangling-version` requires one of: `legacy`, `v0` (RFC 2603), or `hashed` (C symbol-mangling-version=) diff --git a/tests/ui/symbol-mangling-version/unstable.hashed.stderr b/tests/ui/symbol-mangling-version/unstable.hashed.stderr new file mode 100644 index 0000000000000..f2ae18290f261 --- /dev/null +++ b/tests/ui/symbol-mangling-version/unstable.hashed.stderr @@ -0,0 +1,2 @@ +error: `-C symbol-mangling-version=hashed` requires `-Z unstable-options` + diff --git a/tests/ui/symbol-mangling-version/unstable.rs b/tests/ui/symbol-mangling-version/unstable.rs index df87a39cdfbd1..42750a64574dc 100644 --- a/tests/ui/symbol-mangling-version/unstable.rs +++ b/tests/ui/symbol-mangling-version/unstable.rs @@ -1,6 +1,9 @@ -// revisions: legacy legacy-ok +// revisions: legacy legacy-ok hashed hashed-ok // [legacy] compile-flags: -Csymbol-mangling-version=legacy // [legacy-ok] check-pass // [legacy-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy +// [hashed] compile-flags: -Csymbol-mangling-version=hashed +// [hashed-ok] check-pass +// [hashed-ok] compile-flags: -Zunstable-options -Csymbol-mangling-version=hashed fn main() {}