fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
+ /// The name of the crate as it is referred to in source code of the current
+ /// crate.
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString;
+ /// The name of the crate as it is stored in the crate's metadata.
+ fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString;
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh;
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString;
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
{ unimplemented!() }
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
+ fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString {
+ unimplemented!()
+ }
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { unimplemented!() }
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
}
fn verify_no_symbol_conflicts(&self,
- crate_name: &str,
span: Span,
metadata: &MetadataBlob) {
let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice());
+ let crate_name = decoder::get_crate_name(metadata.as_slice());
// Check for (potential) conflicts with the local crate
if self.local_crate_name == crate_name &&
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
self.verify_rustc_version(name, span, &lib.metadata);
- self.verify_no_symbol_conflicts(name, span, &lib.metadata);
+ self.verify_no_symbol_conflicts(span, &lib.metadata);
// Claim this crate number and cache it
let cnum = self.next_crate_num;
token::intern_and_get_ident(&self.get_crate_data(cnum).name[..])
}
+ fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
+ {
+ token::intern_and_get_ident(&self.get_crate_data(cnum).name())
+ }
+
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh
{
let cdata = self.get_crate_data(cnum);
impl crate_metadata {
pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
- pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
+ pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) }
pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
pub fn disambiguator(&self) -> &str {
decoder::get_crate_disambiguator(self.data())
Svh::new(hashdoc.as_str_slice())
}
-pub fn maybe_get_crate_name(data: &[u8]) -> Option<String> {
+pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
- doc.as_str_slice().to_string()
+ doc.as_str_slice()
})
}
triple_doc.map(|s| s.as_str().to_string())
}
-pub fn get_crate_name(data: &[u8]) -> String {
+pub fn get_crate_name(data: &[u8]) -> &str {
maybe_get_crate_name(data).expect("no crate name in crate")
}
use session::config;
use syntax::ast;
use trans::CrateTranslation;
+use trans::link_guard;
/// Linker abstraction used by back::link to build up the command to invoke a
/// linker.
for symbol in symbols {
writeln!(f, " {}", symbol)?;
}
+
+ // Add link-guard symbols
+ {
+ // local crate
+ let symbol = link_guard::link_guard_name(&trans.link.crate_name[..],
+ &trans.link.crate_hash);
+ try!(writeln!(f, " {}", symbol));
+ }
+ // statically linked dependencies
+ for (i, format) in formats[&CrateTypeDylib].iter().enumerate() {
+ if *format == Linkage::Static {
+ let cnum = (i + 1) as ast::CrateNum;
+ let crate_name = cstore.original_crate_name(cnum);
+ let svh = cstore.crate_hash(cnum);
+
+ let symbol = link_guard::link_guard_name(&crate_name[..], &svh);
+ try!(writeln!(f, " {}", symbol));
+ }
+ }
+
Ok(())
})();
if let Err(e) = res {
use trans::glue;
use trans::inline;
use trans::intrinsic;
+use trans::link_guard;
use trans::machine;
use trans::machine::{llalign_of_min, llsize_of, llsize_of_real};
use trans::meth;
unsafe {
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
+ link_guard::insert_reference_to_link_guard(ccx, llbb);
debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(ccx);
let (start_fn, args) = if use_start_lang_item {
collector::print_collection_results(&ccx);
}
+ emit_link_guard_if_necessary(&shared_ccx);
+
for ccx in shared_ccx.iter() {
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
if sess.entry_fn.borrow().is_some() {
reachable_symbols.push("main".to_string());
}
+ reachable_symbols.push(link_guard::link_guard_name(&link_meta.crate_name,
+ &link_meta.crate_hash));
// For the purposes of LTO, we add to the reachable set all of the upstream
// reachable extern fns. These functions are all part of the public ABI of
}
}
+fn emit_link_guard_if_necessary(shared_ccx: &SharedCrateContext) {
+ let link_meta = shared_ccx.link_meta();
+ let link_guard_name = link_guard::link_guard_name(&link_meta.crate_name,
+ &link_meta.crate_hash);
+ let link_guard_name = CString::new(link_guard_name).unwrap();
+
+ // Check if the link-guard has already been emitted in a codegen unit
+ let link_guard_already_emitted = shared_ccx.iter().any(|ccx| {
+ let link_guard = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(),
+ link_guard_name.as_ptr()) };
+ !link_guard.is_null()
+ });
+
+ if !link_guard_already_emitted {
+ link_guard::get_or_insert_link_guard(&shared_ccx.get_ccx(0));
+ }
+}
+
/// We visit all the items in the krate and translate them. We do
/// this in two walks. The first walk just finds module items. It then
/// walks the full contents of those module items and translates all
--- /dev/null
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use back::svh::Svh;
+use libc::c_uint;
+use llvm;
+use std::ffi::CString;
+use std::ptr;
+use trans::attributes;
+use trans::builder;
+use trans::CrateContext;
+use trans::declare;
+use trans::type_::Type;
+
+const GUARD_PREFIX: &'static str = "__rustc_link_guard_";
+
+pub fn link_guard_name(crate_name: &str, crate_svh: &Svh) -> String {
+
+ let mut guard_name = String::new();
+
+ guard_name.push_str(GUARD_PREFIX);
+ guard_name.push_str(crate_name);
+ guard_name.push_str("_");
+ guard_name.push_str(crate_svh.as_str());
+
+ guard_name
+}
+
+pub fn get_or_insert_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>)
+ -> llvm::ValueRef {
+
+ let guard_name = link_guard_name(&ccx.tcx().crate_name[..],
+ &ccx.link_meta().crate_hash);
+
+ let guard_function = unsafe {
+ let guard_name_c_string = CString::new(&guard_name[..]).unwrap();
+ llvm::LLVMGetNamedValue(ccx.llmod(), guard_name_c_string.as_ptr())
+ };
+
+ if guard_function != ptr::null_mut() {
+ return guard_function;
+ }
+
+ let llfty = Type::func(&[], &Type::void(ccx));
+ let guard_function = declare::define_cfn(ccx,
+ &guard_name[..],
+ llfty,
+ ccx.tcx().mk_nil()).unwrap_or_else(|| {
+ ccx.sess().bug("Link guard already defined.");
+ });
+
+ attributes::emit_uwtable(guard_function, true);
+ attributes::unwind(guard_function, false);
+
+ let bld = ccx.raw_builder();
+ unsafe {
+ let llbb = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(),
+ guard_function,
+ "link_guard_top\0".as_ptr() as *const _);
+ llvm::LLVMPositionBuilderAtEnd(bld, llbb);
+
+ for crate_num in ccx.sess().cstore.crates() {
+ if !ccx.sess().cstore.is_explicitly_linked(crate_num) {
+ continue;
+ }
+
+ let crate_name = ccx.sess().cstore.original_crate_name(crate_num);
+ let svh = ccx.sess().cstore.crate_hash(crate_num);
+
+ let dependency_guard_name = link_guard_name(&crate_name[..], &svh);
+
+ let decl = declare::declare_cfn(ccx,
+ &dependency_guard_name[..],
+ llfty,
+ ccx.tcx().mk_nil());
+ attributes::unwind(decl, false);
+
+ llvm::LLVMPositionBuilderAtEnd(bld, llbb);
+
+ let args: &[llvm::ValueRef] = &[];
+ llvm::LLVMRustBuildCall(bld,
+ decl,
+ args.as_ptr(),
+ args.len() as c_uint,
+ 0 as *mut _,
+ builder::noname());
+ }
+
+ llvm::LLVMBuildRetVoid(bld);
+ }
+
+ guard_function
+}
+
+pub fn insert_reference_to_link_guard<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ llbb: llvm::BasicBlockRef) {
+ let guard_function = get_or_insert_link_guard(ccx);
+
+ unsafe {
+ llvm::LLVMPositionBuilderAtEnd(ccx.raw_builder(), llbb);
+ let args: &[llvm::ValueRef] = &[];
+ llvm::LLVMRustBuildCall(ccx.raw_builder(),
+ guard_function,
+ args.as_ptr(),
+ args.len() as c_uint,
+ 0 as *mut _,
+ builder::noname());
+ }
+}
mod glue;
mod inline;
mod intrinsic;
+pub mod link_guard;
mod machine;
mod _match;
mod meth;
--- /dev/null
+-include ../tools.mk
+
+all:
+ -mkdir -p $(TMPDIR)/good
+ -mkdir -p $(TMPDIR)/bad
+ $(BARE_RUSTC) ./good/lib.rs -C prefer-dynamic --out-dir="$(TMPDIR)/good"
+ $(BARE_RUSTC) ./bad/lib.rs -C prefer-dynamic --out-dir="$(TMPDIR)/bad"
+ $(BARE_RUSTC) -L "$(TMPDIR)/good" -C prefer-dynamic -Crpath ./main.rs --out-dir="$(TMPDIR)"
+ # This should succeed because the correct library is in LD_LIBRARY_PATH
+ $(LD_LIB_PATH_ENVVAR)="$(TMPDIR)/good:$($(LD_LIB_PATH_ENVVAR))" $(TMPDIR)/main
+ # This should fail because the wrong library is in LD_LIBRARY_PATH
+ OUTPUT=`$(LD_LIB_PATH_ENVVAR)="$(TMPDIR)/bad:$($(LD_LIB_PATH_ENVVAR))" $(TMPDIR)/main || exit 0`
+ if ["$(OUTPUT)" == "bad"]; then exit 1; fi
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="thelibrary"]
+#![crate_type="dylib"]
+
+pub fn some_library_function() {
+ println!("bad");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name="thelibrary"]
+#![crate_type="dylib"]
+
+pub fn some_library_function() {
+ println!("bad");
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate thelibrary;
+
+fn main() {
+ thelibrary::some_library_function();
+}
$(RUSTC) -C relocation-model=default foo.rs
$(call RUN,foo)
- $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs
- $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs
+ $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs --emit=link,obj
ifdef IS_MSVC
# FIXME(#28026)
others:
$(RUSTC) -C relocation-model=static foo.rs
$(call RUN,foo)
- $(RUSTC) -C relocation-model=static --crate-type=dylib foo.rs
endif