Skip to content

Commit

Permalink
MCP rust-lang#705: Provide the option `-Zsymbol-mangling-version=hash…
Browse files Browse the repository at this point in the history
…ed` to shorten symbol names by replacing them with a digest.

Enrich test cases
  • Loading branch information
h1467792822 committed Jan 16, 2024
1 parent 714b29a commit 52b777e
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 11 deletions.
37 changes: 32 additions & 5 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ impl SwitchWithOptPath {
pub enum SymbolManglingVersion {
Legacy,
V0,
Hashed,
}

#[derive(Clone, Copy, Debug, PartialEq, Hash)]
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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",
);
}
}
}

Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`)";
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1490,7 +1492,7 @@ options! {
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
symbol_mangling_version: Option<SymbolManglingVersion> = (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<String> = (None, parse_opt_string, [TRACKED],
"select target processor (`rustc --print target-cpus` for details)"),
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
Expand Down Expand Up @@ -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<SymbolManglingVersion> = (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)"),
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_symbol_mangling/src/hashed.rs
Original file line number Diff line number Diff line change
@@ -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<CrateNum>,
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::<Hash64>().as_u64()
});

format!("_RNxC{}{crate_name}19H{hash:016x}", crate_name.len())
}
4 changes: 4 additions & 0 deletions compiler/rustc_symbol_mangling/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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!(
Expand Down
47 changes: 47 additions & 0 deletions tests/run-make/symbol-mangling-version/Makefile
Original file line number Diff line number Diff line change
@@ -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))
4 changes: 4 additions & 0 deletions tests/run-make/symbol-mangling-version/a_dylib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#![crate_type="dylib"]
pub fn hello() {
println!("hello dylib");
}
5 changes: 5 additions & 0 deletions tests/run-make/symbol-mangling-version/a_rlib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![crate_type="rlib"]

pub fn hello() {
println!("hello rlib");
}
9 changes: 9 additions & 0 deletions tests/run-make/symbol-mangling-version/b_bin.rs
Original file line number Diff line number Diff line change
@@ -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();
}
9 changes: 9 additions & 0 deletions tests/run-make/symbol-mangling-version/b_dylib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![crate_type="dylib"]

extern crate a_rlib;
extern crate a_dylib;

pub fn hello() {
a_rlib::hello();
a_dylib::hello();
}
2 changes: 1 addition & 1 deletion tests/ui/symbol-mangling-version/bad-value.bad.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/symbol-mangling-version/bad-value.blank.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/ui/symbol-mangling-version/bad-value.no-value.stderr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: codegen option `symbol-mangling-version` requires either `legacy` or `v0` (RFC 2603) (C symbol-mangling-version=<value>)
error: codegen option `symbol-mangling-version` requires one of: `legacy`, `v0` (RFC 2603), or `hashed` (C symbol-mangling-version=<value>)

2 changes: 2 additions & 0 deletions tests/ui/symbol-mangling-version/unstable.hashed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: `-C symbol-mangling-version=hashed` requires `-Z unstable-options`

5 changes: 4 additions & 1 deletion tests/ui/symbol-mangling-version/unstable.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 52b777e

Please sign in to comment.