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 use context::SharedCrateContext;
12 use monomorphize::Instance;
13 use symbol_map::SymbolMap;
14 use back::symbol_names::symbol_name;
15 use util::nodemap::FxHashMap;
16 use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
17 use rustc::session::config;
18 use rustc::ty::TyCtxt;
20 use trans_item::TransItem;
22 /// The SymbolExportLevel of a symbols specifies from which kinds of crates
23 /// the symbol will be exported. `C` symbols will be exported from any
24 /// kind of crate, including cdylibs which export very few things.
25 /// `Rust` will only be exported if the crate produced is a Rust
27 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
28 pub enum SymbolExportLevel {
33 /// The set of symbols exported from each crate in the crate graph.
34 pub struct ExportedSymbols {
35 exports: FxHashMap<CrateNum, Vec<(String, SymbolExportLevel)>>,
38 impl ExportedSymbols {
40 pub fn empty() -> ExportedSymbols {
46 pub fn compute_from<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
47 symbol_map: &SymbolMap<'tcx>)
49 let mut local_crate: Vec<_> = scx
53 scx.tcx().hir.local_def_id(node_id)
56 let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map);
57 let export_level = export_level(scx, def_id);
58 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
63 if scx.sess().entry_fn.borrow().is_some() {
64 local_crate.push(("main".to_string(), SymbolExportLevel::C));
67 if let Some(id) = scx.sess().derive_registrar_fn.get() {
68 let def_id = scx.tcx().hir.local_def_id(id);
69 let idx = def_id.index;
70 let disambiguator = scx.sess().local_crate_disambiguator();
71 let registrar = scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
72 local_crate.push((registrar, SymbolExportLevel::C));
75 if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
76 local_crate.push((metadata_symbol_name(scx.tcx()),
77 SymbolExportLevel::Rust));
80 let mut exports = FxHashMap();
81 exports.insert(LOCAL_CRATE, local_crate);
83 for cnum in scx.sess().cstore.crates() {
84 debug_assert!(cnum != LOCAL_CRATE);
86 // If this crate is a plugin and/or a custom derive crate, then
87 // we're not even going to link those in so we skip those crates.
88 if scx.sess().cstore.plugin_registrar_fn(cnum).is_some() ||
89 scx.sess().cstore.derive_registrar_fn(cnum).is_some() {
93 // Check to see if this crate is a "special runtime crate". These
94 // crates, implementation details of the standard library, typically
95 // have a bunch of `pub extern` and `#[no_mangle]` functions as the
96 // ABI between them. We don't want their symbols to have a `C`
97 // export level, however, as they're just implementation details.
98 // Down below we'll hardwire all of the symbols to the `Rust` export
100 let special_runtime_crate =
101 scx.sess().cstore.is_allocator(cnum) ||
102 scx.sess().cstore.is_panic_runtime(cnum) ||
103 scx.sess().cstore.is_compiler_builtins(cnum);
105 let crate_exports = scx
108 .exported_symbols(cnum)
111 let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx());
112 let export_level = if special_runtime_crate {
113 // We can probably do better here by just ensuring that
114 // it has hidden visibility rather than public
115 // visibility, as this is primarily here to ensure it's
116 // not stripped during LTO.
118 // In general though we won't link right if these
119 // symbols are stripped, and LTO currently strips them.
120 if name == "rust_eh_personality" ||
121 name == "rust_eh_register_frames" ||
122 name == "rust_eh_unregister_frames" {
125 SymbolExportLevel::Rust
128 export_level(scx, def_id)
130 debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
135 exports.insert(cnum, crate_exports);
138 return ExportedSymbols {
142 fn export_level(scx: &SharedCrateContext,
144 -> SymbolExportLevel {
145 let attrs = scx.tcx().get_attrs(sym_def_id);
146 if attr::contains_extern_indicator(scx.sess().diagnostic(), &attrs) {
149 SymbolExportLevel::Rust
154 pub fn exported_symbols(&self,
156 -> &[(String, SymbolExportLevel)] {
157 match self.exports.get(&cnum) {
158 Some(exports) => exports,
163 pub fn for_each_exported_symbol<F>(&self,
165 export_threshold: SymbolExportLevel,
167 where F: FnMut(&str, SymbolExportLevel)
169 for &(ref name, export_level) in self.exported_symbols(cnum) {
170 if is_below_threshold(export_level, export_threshold) {
171 f(&name, export_level)
177 pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
178 format!("rust_metadata_{}_{}",
179 tcx.crate_name(LOCAL_CRATE),
180 tcx.crate_disambiguator(LOCAL_CRATE))
183 pub fn crate_export_threshold(crate_type: config::CrateType)
184 -> SymbolExportLevel {
186 config::CrateTypeExecutable |
187 config::CrateTypeStaticlib |
188 config::CrateTypeProcMacro |
189 config::CrateTypeCdylib => SymbolExportLevel::C,
190 config::CrateTypeRlib |
191 config::CrateTypeDylib => SymbolExportLevel::Rust,
195 pub fn crates_export_threshold(crate_types: &[config::CrateType])
196 -> SymbolExportLevel {
197 if crate_types.iter().any(|&crate_type| {
198 crate_export_threshold(crate_type) == SymbolExportLevel::Rust
200 SymbolExportLevel::Rust
206 pub fn is_below_threshold(level: SymbolExportLevel,
207 threshold: SymbolExportLevel)
209 if threshold == SymbolExportLevel::Rust {
210 // We export everything from Rust dylibs
213 level == SymbolExportLevel::C
217 fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
219 symbol_map: &SymbolMap<'tcx>)
221 // Just try to look things up in the symbol map. If nothing's there, we
223 if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
224 if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
225 return sym.to_owned();
229 let instance = Instance::mono(tcx, def_id);
231 symbol_map.get(TransItem::Fn(instance))
233 .unwrap_or_else(|| symbol_name(instance, tcx))