Skip to content

Commit

Permalink
Auto merge of #38117 - michaelwoerister:hidden-symbols, r=alexcrichton
Browse files Browse the repository at this point in the history
Improve symbol visibility handling for dynamic libraries.

This will hopefully fix issue #37530 and maybe also #32887.

I'm relying on @m4b to post some numbers on how awesome the improvement for cdylibs is `:)`

cc @rust-lang/compiler @rust-lang/tools @cuviper @froydnj
r? @alexcrichton
  • Loading branch information
bors committed Dec 5, 2016
2 parents 06b8d1d + 8ecdc4e commit daf8c1d
Show file tree
Hide file tree
Showing 22 changed files with 623 additions and 243 deletions.
7 changes: 5 additions & 2 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,9 @@ pub trait CrateStore<'tcx> {
fn crate_hash(&self, cnum: CrateNum) -> Svh;
fn crate_disambiguator(&self, cnum: CrateNum) -> Symbol;
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>;
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>;
fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>;
fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId>;
fn is_no_builtins(&self, cnum: CrateNum) -> bool;

// resolve
Expand Down Expand Up @@ -491,9 +492,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
-> Symbol { bug!("crate_disambiguator") }
fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{ bug!("plugin_registrar_fn") }
fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{ bug!("derive_registrar_fn") }
fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
{ bug!("native_libraries") }
fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId> { bug!("reachable_ids") }
fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId> { bug!("exported_symbols") }
fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") }

// resolve
Expand Down
19 changes: 11 additions & 8 deletions src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ pub enum Linkage {
CommonLinkage = 10,
}

// LLVMRustVisibility
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[repr(C)]
pub enum Visibility {
Default = 0,
Hidden = 1,
Protected = 2,
}

/// LLVMDiagnosticSeverity
#[derive(Copy, Clone, Debug)]
#[repr(C)]
Expand Down Expand Up @@ -399,13 +408,6 @@ pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;
pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);

/// LLVMVisibility
#[repr(C)]
pub enum Visibility {
Default,
Hidden,
Protected,
}

pub mod debuginfo {
use super::MetadataRef;
Expand Down Expand Up @@ -655,7 +657,8 @@ extern "C" {
pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage);
pub fn LLVMGetSection(Global: ValueRef) -> *const c_char;
pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char);
pub fn LLVMSetVisibility(Global: ValueRef, Viz: Visibility);
pub fn LLVMRustGetVisibility(Global: ValueRef) -> Visibility;
pub fn LLVMRustSetVisibility(Global: ValueRef, Viz: Visibility);
pub fn LLVMGetAlignment(Global: ValueRef) -> c_uint;
pub fn LLVMSetAlignment(Global: ValueRef, Bytes: c_uint);
pub fn LLVMSetDLLStorageClass(V: ValueRef, C: DLLStorageClass);
Expand Down
12 changes: 10 additions & 2 deletions src/librustc_metadata/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,22 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
})
}

fn derive_registrar_fn(&self, cnum: CrateNum) -> Option<DefId>
{
self.get_crate_data(cnum).root.macro_derive_registrar.map(|index| DefId {
krate: cnum,
index: index
})
}

fn native_libraries(&self, cnum: CrateNum) -> Vec<NativeLibrary>
{
self.get_crate_data(cnum).get_native_libraries()
}

fn reachable_ids(&self, cnum: CrateNum) -> Vec<DefId>
fn exported_symbols(&self, cnum: CrateNum) -> Vec<DefId>
{
self.get_crate_data(cnum).get_reachable_ids()
self.get_crate_data(cnum).get_exported_symbols()
}

fn is_no_builtins(&self, cnum: CrateNum) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,8 @@ impl<'a, 'tcx> CrateMetadata {
arg_names.decode(self).collect()
}

pub fn get_reachable_ids(&self) -> Vec<DefId> {
self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect()
pub fn get_exported_symbols(&self) -> Vec<DefId> {
self.root.exported_symbols.decode(self).map(|index| self.local_def_id(index)).collect()
}

pub fn get_macro(&self, id: DefIndex) -> (ast::Name, MacroDef) {
Expand Down
24 changes: 12 additions & 12 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
reexports: &'a def::ExportMap,
link_meta: &'a LinkMeta,
cstore: &'a cstore::CStore,
reachable: &'a NodeSet,
exported_symbols: &'a NodeSet,

lazy_state: LazyState,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
Expand Down Expand Up @@ -1223,16 +1223,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.lazy_seq(all_impls)
}

// Encodes all reachable symbols in this crate into the metadata.
// Encodes all symbols exported from this crate into the metadata.
//
// This pass is seeded off the reachability list calculated in the
// middle::reachable module but filters out items that either don't have a
// symbol associated with them (they weren't translated) or if they're an FFI
// definition (as that's not defined in this crate).
fn encode_reachable(&mut self) -> LazySeq<DefIndex> {
let reachable = self.reachable;
fn encode_exported_symbols(&mut self) -> LazySeq<DefIndex> {
let exported_symbols = self.exported_symbols;
let tcx = self.tcx;
self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index))
self.lazy_seq(exported_symbols.iter().map(|&id| tcx.map.local_def_id(id).index))
}

fn encode_dylib_dependency_formats(&mut self) -> LazySeq<Option<LinkagePreference>> {
Expand Down Expand Up @@ -1278,10 +1278,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let impls = self.encode_impls();
let impl_bytes = self.position() - i;

// Encode reachability info.
// Encode exported symbols info.
i = self.position();
let reachable_ids = self.encode_reachable();
let reachable_bytes = self.position() - i;
let exported_symbols = self.encode_exported_symbols();
let exported_symbols_bytes = self.position() - i;

// Encode and index the items.
i = self.position();
Expand Down Expand Up @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
native_libraries: native_libraries,
codemap: codemap,
impls: impls,
reachable_ids: reachable_ids,
exported_symbols: exported_symbols,
index: index,
});

Expand All @@ -1339,7 +1339,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
println!(" native bytes: {}", native_lib_bytes);
println!(" codemap bytes: {}", codemap_bytes);
println!(" impl bytes: {}", impl_bytes);
println!(" reachable bytes: {}", reachable_bytes);
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
println!(" item bytes: {}", item_bytes);
println!(" index bytes: {}", index_bytes);
println!(" zero bytes: {}", zero_bytes);
Expand Down Expand Up @@ -1377,7 +1377,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cstore: &cstore::CStore,
reexports: &def::ExportMap,
link_meta: &LinkMeta,
reachable: &NodeSet)
exported_symbols: &NodeSet)
-> Vec<u8> {
let mut cursor = Cursor::new(vec![]);
cursor.write_all(METADATA_HEADER).unwrap();
Expand All @@ -1392,7 +1392,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
reexports: reexports,
link_meta: link_meta,
cstore: cstore,
reachable: reachable,
exported_symbols: exported_symbols,
lazy_state: LazyState::NoNode,
type_shorthands: Default::default(),
predicate_shorthands: Default::default(),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ pub struct CrateRoot {
pub native_libraries: LazySeq<NativeLibrary>,
pub codemap: LazySeq<syntax_pos::FileMap>,
pub impls: LazySeq<TraitImpls>,
pub reachable_ids: LazySeq<DefIndex>,
pub exported_symbols: LazySeq<DefIndex>,
pub index: LazySeq<index::Index>,
}

Expand Down
99 changes: 43 additions & 56 deletions src/librustc_trans/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ use std::path::{Path, PathBuf};
use std::process::Command;

use context::SharedCrateContext;
use monomorphize::Instance;

use back::archive;
use back::symbol_export::{self, ExportedSymbols};
use middle::dependency_format::Linkage;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use session::Session;
use session::config::CrateType;
use session::config;
Expand All @@ -34,10 +34,10 @@ pub struct LinkerInfo {

impl<'a, 'tcx> LinkerInfo {
pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
reachable: &[String]) -> LinkerInfo {
exports: &ExportedSymbols) -> LinkerInfo {
LinkerInfo {
exports: scx.sess().crate_types.borrow().iter().map(|&c| {
(c, exported_symbols(scx, reachable, c))
(c, exported_symbols(scx, exports, c))
}).collect(),
}
}
Expand Down Expand Up @@ -253,46 +253,47 @@ impl<'a> Linker for GnuLinker<'a> {
let mut arg = OsString::new();
let path = tmpdir.join("list");

if self.sess.target.target.options.is_like_solaris {
debug!("EXPORTED SYMBOLS:");

if self.sess.target.target.options.is_like_osx {
// Write a plain, newline-separated list of symbols
let res = (|| -> io::Result<()> {
let mut f = BufWriter::new(File::create(&path)?);
writeln!(f, "{{\n global:")?;
for sym in self.info.exports[&crate_type].iter() {
writeln!(f, " {};", sym)?;
debug!(" _{}", sym);
writeln!(f, "_{}", sym)?;
}
writeln!(f, "\n local:\n *;\n}};")?;
Ok(())
})();
if let Err(e) = res {
self.sess.fatal(&format!("failed to write version script: {}", e));
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
}

arg.push("-Wl,-M,");
arg.push(&path);
} else {
let prefix = if self.sess.target.target.options.is_like_osx {
"_"
} else {
""
};
// Write an LD version script
let res = (|| -> io::Result<()> {
let mut f = BufWriter::new(File::create(&path)?);
writeln!(f, "{{\n global:")?;
for sym in self.info.exports[&crate_type].iter() {
writeln!(f, "{}{}", prefix, sym)?;
debug!(" {};", sym);
writeln!(f, " {};", sym)?;
}
writeln!(f, "\n local:\n *;\n}};")?;
Ok(())
})();
if let Err(e) = res {
self.sess.fatal(&format!("failed to write lib.def file: {}", e));
}
if self.sess.target.target.options.is_like_osx {
arg.push("-Wl,-exported_symbols_list,");
} else {
arg.push("-Wl,--retain-symbols-file=");
self.sess.fatal(&format!("failed to write version script: {}", e));
}
arg.push(&path);
}

if self.sess.target.target.options.is_like_osx {
arg.push("-Wl,-exported_symbols_list,");
} else if self.sess.target.target.options.is_like_solaris {
arg.push("-Wl,-M,");
} else {
arg.push("-Wl,--version-script=");
}

arg.push(&path);
self.cmd.arg(arg);
}

Expand Down Expand Up @@ -473,43 +474,29 @@ impl<'a> Linker for MsvcLinker<'a> {
}

fn exported_symbols(scx: &SharedCrateContext,
reachable: &[String],
exported_symbols: &ExportedSymbols,
crate_type: CrateType)
-> Vec<String> {
// See explanation in GnuLinker::export_symbols, for
// why we don't ever need dylib symbols on non-MSVC.
if crate_type == CrateType::CrateTypeDylib ||
crate_type == CrateType::CrateTypeProcMacro {
if !scx.sess().target.target.options.is_like_msvc {
return vec![];
}
}
let export_threshold = symbol_export::crate_export_threshold(crate_type);

let mut symbols = reachable.to_vec();
let mut symbols = Vec::new();
exported_symbols.for_each_exported_symbol(LOCAL_CRATE, export_threshold, |name, _| {
symbols.push(name.to_owned());
});

// If we're producing anything other than a dylib then the `reachable` array
// above is the exhaustive set of symbols we should be exporting.
//
// For dylibs, however, we need to take a look at how all upstream crates
// are linked into this dynamic library. For all statically linked
// libraries we take all their reachable symbols and emit them as well.
if crate_type != CrateType::CrateTypeDylib {
return symbols
}

let cstore = &scx.sess().cstore;
let formats = scx.sess().dependency_formats.borrow();
let deps = formats[&crate_type].iter();
symbols.extend(deps.enumerate().filter_map(|(i, f)| {
if *f == Linkage::Static {
Some(CrateNum::new(i + 1))
} else {
None

for (index, dep_format) in deps.enumerate() {
let cnum = CrateNum::new(index + 1);
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
// ... we add its symbol list to our export list.
exported_symbols.for_each_exported_symbol(cnum, export_threshold, |name, _| {
symbols.push(name.to_owned());
})
}
}).flat_map(|cnum| {
cstore.reachable_ids(cnum)
}).map(|did| -> String {
Instance::mono(scx, did).symbol_name(scx)
}));
}

symbols
}
Loading

0 comments on commit daf8c1d

Please sign in to comment.