Skip to content

Commit 1535ecb

Browse files
committed
Mangle #[rustc_std_internal_symbol] to include the rustc version unless #[no_mangle] is used
1 parent 683ca74 commit 1535ecb

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

compiler/rustc_symbol_mangling/src/lib.rs

+37
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ mod v0;
112112
pub mod errors;
113113
pub mod test;
114114

115+
pub use v0::mangle_internal_symbol;
116+
115117
/// This function computes the symbol name for the given `instance` and the
116118
/// given instantiating crate. That is, if you know that instance X is
117119
/// instantiated in crate Y, this is the symbol name this instance would have.
@@ -183,6 +185,39 @@ fn compute_symbol_name<'tcx>(
183185
CodegenFnAttrs::EMPTY
184186
};
185187

188+
if attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
189+
// Items marked as #[rustc_std_internal_symbol] need to have a fixed
190+
// symbol name because it is used to import items from another crate
191+
// without a direct dependency. As such it is not possible to look up
192+
// the mangled name for the `Instance` from the crate metadata of the
193+
// defining crate.
194+
// Weak lang items automatically get #[rustc_std_internal_symbol]
195+
// applied by the code computing the CodegenFnAttrs.
196+
// We are mangling all #[rustc_std_internal_symbol] items that don't
197+
// also have #[no_mangle] as a combination of the rustc version and the
198+
// unmangled linkage name. This is to ensure that if we link against a
199+
// staticlib compiled by a different rustc version, we don't get symbol
200+
// conflicts or even UB due to a different implementation/ABI. Rust
201+
// staticlibs currently export all symbols, including those that are
202+
// hidden in cdylibs.
203+
// We are using the v0 symbol mangling scheme here as we need to be
204+
// consistent across all crates and in some contexts the legacy symbol
205+
// mangling scheme can't be used. For example both the GCC backend and
206+
// Rust-for-Linux don't support some of the characters used by the
207+
// legacy symbol mangling scheme.
208+
let name = if tcx.is_foreign_item(def_id) {
209+
if let Some(name) = attrs.link_name { name } else { tcx.item_name(def_id) }
210+
} else {
211+
if let Some(name) = attrs.export_name { name } else { tcx.item_name(def_id) }
212+
};
213+
214+
if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
215+
return name.to_string();
216+
} else {
217+
return v0::mangle_internal_symbol(tcx, name.as_str());
218+
}
219+
}
220+
186221
// Foreign items by default use no mangling for their symbol name. There's a
187222
// few exceptions to this rule though:
188223
//
@@ -198,6 +233,8 @@ fn compute_symbol_name<'tcx>(
198233
// is present we mangle everything on wasm because the demangled form will
199234
// show up in the `wasm-import-name` custom attribute in LLVM IR.
200235
//
236+
// * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
237+
// both for exports and imports through foreign items. This is handled above.
201238
// [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
202239
if tcx.is_foreign_item(def_id)
203240
&& (!tcx.sess.target.is_like_wasm

compiler/rustc_symbol_mangling/src/v0.rs

+45
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_data_structures::base_n::ToBaseN;
22
use rustc_data_structures::fx::FxHashMap;
33
use rustc_data_structures::intern::Interned;
4+
use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
45
use rustc_hir as hir;
56
use rustc_hir::def::CtorKind;
67
use rustc_hir::def_id::{CrateNum, DefId};
@@ -18,6 +19,7 @@ use rustc_target::abi::Integer;
1819
use rustc_target::spec::abi::Abi;
1920

2021
use std::fmt::Write;
22+
use std::hash::Hasher;
2123
use std::iter;
2224
use std::ops::Range;
2325

@@ -66,6 +68,49 @@ pub(super) fn mangle<'tcx>(
6668
std::mem::take(&mut cx.out)
6769
}
6870

71+
pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String {
72+
let prefix = "_R";
73+
let mut cx: SymbolMangler<'_> = SymbolMangler {
74+
tcx,
75+
start_offset: prefix.len(),
76+
paths: FxHashMap::default(),
77+
types: FxHashMap::default(),
78+
consts: FxHashMap::default(),
79+
binders: vec![],
80+
out: String::from(prefix),
81+
};
82+
83+
cx.path_append_ns(
84+
|cx| {
85+
cx.push("C");
86+
cx.push_disambiguator({
87+
let mut hasher = StableHasher::new();
88+
// Incorporate the rustc version to ensure #[rustc_std_internal_symbol] functions
89+
// get a different symbol name depending on the rustc version.
90+
//
91+
// RUSTC_FORCE_RUSTC_VERSION is used to inject rustc version information
92+
// during testing.
93+
if let Some(val) = /* FIXME */ option_env!("RUSTC_FORCE_RUSTC_VERSION") {
94+
hasher.write(val.as_bytes())
95+
} else {
96+
hasher.write(tcx.sess.cfg_version.as_bytes())
97+
}
98+
99+
let hash: Hash64 = hasher.finish();
100+
hash.as_u64()
101+
});
102+
cx.push_ident("__rustc");
103+
Ok(())
104+
},
105+
'v',
106+
0,
107+
item_name,
108+
)
109+
.unwrap();
110+
111+
std::mem::take(&mut cx.out)
112+
}
113+
69114
pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
70115
tcx: TyCtxt<'tcx>,
71116
trait_ref: ty::PolyExistentialTraitRef<'tcx>,

0 commit comments

Comments
 (0)