Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve symbol visibility handling for dynamic libraries. #38117

Merged
merged 9 commits into from
Dec 6, 2016
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