1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! The Rust Linkage Model and Symbol Names
12 //! =======================================
14 //! The semantic model of Rust linkage is, broadly, that "there's no global
15 //! namespace" between crates. Our aim is to preserve the illusion of this
16 //! model despite the fact that it's not *quite* possible to implement on
17 //! modern linkers. We initially didn't use system linkers at all, but have
18 //! been convinced of their utility.
20 //! There are a few issues to handle:
22 //! - Linkers operate on a flat namespace, so we have to flatten names.
23 //! We do this using the C++ namespace-mangling technique. Foo::bar
26 //! - Symbols for distinct items with the same *name* need to get different
27 //! linkage-names. Examples of this are monomorphizations of functions or
28 //! items within anonymous scopes that end up having the same path.
30 //! - Symbols in different crates but with same names "within" the crate need
31 //! to get different linkage-names.
33 //! - Symbol names should be deterministic: Two consecutive runs of the
34 //! compiler over the same code base should produce the same symbol names for
37 //! - Symbol names should not depend on any global properties of the code base,
38 //! so that small modifications to the code base do not result in all symbols
39 //! changing. In previous versions of the compiler, symbol names incorporated
40 //! the SVH (Stable Version Hash) of the crate. This scheme turned out to be
41 //! infeasible when used in conjunction with incremental compilation because
42 //! small code changes would invalidate all symbols generated previously.
44 //! - Even symbols from different versions of the same crate should be able to
45 //! live next to each other without conflict.
47 //! In order to fulfill the above requirements the following scheme is used by
50 //! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
51 //! hash value into every exported symbol name. Anything that makes a difference
52 //! to the symbol being named, but does not show up in the regular path needs to
53 //! be fed into this hash:
55 //! - Different monomorphizations of the same item have the same path but differ
56 //! in their concrete type parameters, so these parameters are part of the
57 //! data being digested for the symbol hash.
59 //! - Rust allows items to be defined in anonymous scopes, such as in
60 //! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
61 //! the path `foo::bar`, since the anonymous scopes do not contribute to the
62 //! path of an item. The compiler already handles this case via so-called
63 //! disambiguating `DefPaths` which use indices to distinguish items with the
64 //! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
65 //! and `foo[0]::bar[1]`. In order to incorporate this disambiguation
66 //! information into the symbol name too, these indices are fed into the
67 //! symbol hash, so that the above two symbols would end up with different
70 //! The two measures described above suffice to avoid intra-crate conflicts. In
71 //! order to also avoid inter-crate conflicts two more measures are taken:
73 //! - The name of the crate containing the symbol is prepended to the symbol
74 //! name, i.e. symbols are "crate qualified". For example, a function `foo` in
75 //! module `bar` in crate `baz` would get a symbol name like
76 //! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
77 //! simple conflicts between functions from different crates.
79 //! - In order to be able to also use symbols from two versions of the same
80 //! crate (which naturally also have the same name), a stronger measure is
81 //! required: The compiler accepts an arbitrary "disambiguator" value via the
82 //! `-C metadata` commandline argument. This disambiguator is then fed into
83 //! the symbol hash of every exported item. Consequently, the symbols in two
84 //! identical crates but with different disambiguators are not in conflict
85 //! with each other. This facility is mainly intended to be used by build
88 //! A note on symbol name stability
89 //! -------------------------------
90 //! Previous versions of the compiler resorted to feeding NodeIds into the
91 //! symbol hash in order to disambiguate between items with the same path. The
92 //! current version of the name generation algorithm takes great care not to do
93 //! that, since NodeIds are notoriously unstable: A small change to the
94 //! code base will offset all NodeIds after the change and thus, much as using
95 //! the SVH in the hash, invalidate an unbounded number of symbol names. This
96 //! makes re-using previously compiled code for incremental compilation
97 //! virtually impossible. Thus, symbol hash generation exclusively relies on
98 //! DefPaths which are much more robust in the face of changes to the code base.
100 use trans::{CrateContext, Instance, gensym_name};
101 use util::sha2::{Digest, Sha256};
103 use rustc::middle::cstore;
104 use rustc::middle::def_id::DefId;
105 use rustc::middle::ty::{self, TypeFoldable};
106 use rustc::front::map::definitions::DefPath;
110 use syntax::parse::token;
111 use serialize::hex::ToHex;
114 pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String {
116 let def_path = tcx.def_path(def_id);
117 let mut s = String::with_capacity(def_path.len() * 16);
119 let def_path = if def_id.is_local() {
120 s.push_str(&tcx.crate_name[..]);
122 s.push_str(&tcx.sess.crate_disambiguator.borrow()[..]);
125 s.push_str(&tcx.sess.cstore.crate_name(def_id.krate)[..]);
127 s.push_str(&tcx.sess.cstore.crate_disambiguator(def_id.krate));
131 for component in def_path {
134 component.data.as_interned_str(),
135 component.disambiguator)
142 fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
144 originating_crate: ast::CrateNum,
145 parameters: &[ty::Ty<'tcx>])
149 let mut hash_state = ccx.symbol_hasher().borrow_mut();
153 if originating_crate == cstore::LOCAL_CRATE {
154 hash_state.input_str(&tcx.sess.crate_disambiguator.borrow()[..]);
156 hash_state.input_str(&tcx.sess.cstore.crate_disambiguator(originating_crate));
159 for component in def_path {
160 let disambiguator_bytes = [(component.disambiguator >> 0) as u8,
161 (component.disambiguator >> 8) as u8,
162 (component.disambiguator >> 16) as u8,
163 (component.disambiguator >> 24) as u8];
164 hash_state.input(&disambiguator_bytes);
167 for t in parameters {
168 assert!(!t.has_erasable_regions());
169 assert!(!t.needs_subst());
170 let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
171 hash_state.input(&encoded_type[..]);
174 return format!("h{}", truncated_hash_result(&mut *hash_state));
176 fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
177 let output = symbol_hasher.result_bytes();
178 // 64 bits should be enough to avoid collisions.
179 output[.. 8].to_hex()
183 fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
184 instance: &Instance<'tcx>,
185 suffix: Option<&str>)
187 let &Instance { def: mut def_id, params: parameters } = instance;
189 if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
190 if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) {
195 let def_path = ccx.tcx().def_path(def_id);
196 let hash = get_symbol_hash(ccx, &def_path, def_id.krate, parameters.as_slice());
198 let mut path = Vec::with_capacity(16);
200 if def_id.is_local() {
201 path.push(ccx.tcx().crate_name.clone());
204 path.extend(def_path.into_iter().map(|e| e.data.as_interned_str()));
206 if let Some(suffix) = suffix {
207 path.push(token::intern_and_get_ident(suffix));
210 link::mangle(path.into_iter(), Some(&hash[..]))
213 pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
214 instance: &Instance<'tcx>)
216 exported_name_with_opt_suffix(ccx, instance, None)
219 pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
220 instance: &Instance<'tcx>,
223 exported_name_with_opt_suffix(ccx, instance, Some(suffix))
226 /// Only symbols that are invisible outside their compilation unit should use a
227 /// name generated by this function.
228 pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
232 let path = [token::intern(&t.to_string()).as_str(),
233 gensym_name(suffix).as_str()];
234 let hash = get_symbol_hash(ccx, &Vec::new(), cstore::LOCAL_CRATE, &[t]);
235 link::mangle(path.iter().cloned(), Some(&hash[..]))