From e82bb915e4daede832b3dcb45df6b8f4cc3569c4 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 21 Aug 2015 00:41:07 -0700 Subject: [PATCH 1/3] Fix dllimports of static data from rlibs --- src/librustc_trans/trans/base.rs | 102 +++++++++++++++------- src/test/run-make/msvc-data-only/Makefile | 8 ++ src/test/run-make/msvc-data-only/bar.rs | 15 ++++ src/test/run-make/msvc-data-only/foo.rs | 13 +++ 4 files changed, 106 insertions(+), 32 deletions(-) create mode 100644 src/test/run-make/msvc-data-only/Makefile create mode 100644 src/test/run-make/msvc-data-only/bar.rs create mode 100644 src/test/run-make/msvc-data-only/foo.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index dd0c06c9142..02aeb110353 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2570,20 +2570,6 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { unsafe { let mut declared = HashSet::new(); - let iter_globals = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstGlobal(llmod), - step: llvm::LLVMGetNextGlobal, - } - }; - - let iter_functions = |llmod| { - ValueIter { - cur: llvm::LLVMGetFirstFunction(llmod), - step: llvm::LLVMGetNextFunction, - } - }; - // Collect all external declarations in all compilation units. for ccx in cx.iter() { for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) { @@ -2623,32 +2609,78 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { } } } +} +// Create a `__imp_ = &symbol` global for every public static `symbol`. +// This is required to satisfy `dllimport` references to static data in .rlibs +// when using MSVC linker. We do this only for data, as linker can fix up +// code references on its own. +// See #26591, #27438 +fn create_imps(cx: &SharedCrateContext, _reachable: &HashSet<&str>) { + unsafe { - struct ValueIter { - cur: ValueRef, - step: unsafe extern "C" fn(ValueRef) -> ValueRef, - } + for ccx in cx.iter() { + let exported: Vec<_> = iter_globals(ccx.llmod()) + .filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && + llvm::LLVMIsDeclaration(val) == 0) + .collect(); - impl Iterator for ValueIter { - type Item = ValueRef; - - fn next(&mut self) -> Option { - let old = self.cur; - if !old.is_null() { - self.cur = unsafe { - let step: unsafe extern "C" fn(ValueRef) -> ValueRef = - mem::transmute_copy(&self.step); - step(old) - }; - Some(old) - } else { - None + let i8p_ty = Type::i8p(&ccx); + for val in exported { + let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + let imp_name = String::from("__imp_") + + str::from_utf8(name.to_bytes()).unwrap(); + let imp_name = CString::new(imp_name).unwrap(); + let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(), + imp_name.as_ptr() as *const _); + llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref())); + llvm::SetLinkage(imp, llvm::ExternalLinkage); } } } } +struct ValueIter { + cur: ValueRef, + step: unsafe extern "C" fn(ValueRef) -> ValueRef, +} + +impl Iterator for ValueIter { + type Item = ValueRef; + + fn next(&mut self) -> Option { + let old = self.cur; + if !old.is_null() { + self.cur = unsafe { + let step: unsafe extern "C" fn(ValueRef) -> ValueRef = + mem::transmute_copy(&self.step); + step(old) + }; + Some(old) + } else { + None + } + } +} + +fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstGlobal(llmod), + step: llvm::LLVMGetNextGlobal, + } + } +} + +fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { + unsafe { + ValueIter { + cur: llvm::LLVMGetFirstFunction(llmod), + step: llvm::LLVMGetNextFunction, + } + } +} + /// The context provided lists a set of reachable ids as calculated by /// middle::reachable, but this contains far more ids and symbols than we're /// actually exposing from the object file. This function will filter the set in @@ -2824,6 +2856,12 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat &reachable_symbols.iter().map(|x| &x[..]).collect()); } + if sess.target.target.options.is_like_msvc && + sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib || + *ct == config::CrateTypeStaticlib) { + create_imps(&shared_ccx, &reachable_symbols.iter().map(|x| &x[..]).collect()); + } + let metadata_module = ModuleTranslation { llcx: shared_ccx.metadata_llcx(), llmod: shared_ccx.metadata_llmod(), diff --git a/src/test/run-make/msvc-data-only/Makefile b/src/test/run-make/msvc-data-only/Makefile new file mode 100644 index 00000000000..251a3a9768d --- /dev/null +++ b/src/test/run-make/msvc-data-only/Makefile @@ -0,0 +1,8 @@ +# Test that on *-pc-windows-msvc we can link to a rlib containing only data. +# See #26591, #27438 + +-include ../tools.mk + +all: + $(RUSTC) foo.rs + $(RUSTC) bar.rs diff --git a/src/test/run-make/msvc-data-only/bar.rs b/src/test/run-make/msvc-data-only/bar.rs new file mode 100644 index 00000000000..0e3af9ff3fd --- /dev/null +++ b/src/test/run-make/msvc-data-only/bar.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate foo; + +fn main() { + println!("The answer is {} !", foo::FOO); +} diff --git a/src/test/run-make/msvc-data-only/foo.rs b/src/test/run-make/msvc-data-only/foo.rs new file mode 100644 index 00000000000..38bff8be125 --- /dev/null +++ b/src/test/run-make/msvc-data-only/foo.rs @@ -0,0 +1,13 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] + +pub static FOO: i32 = 42; From c21fcac29320c065b184cc30973308982a417445 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 25 Sep 2015 18:48:54 -0700 Subject: [PATCH 2/3] Converted test to rpass. --- .../foo.rs => auxiliary/msvc-data-only-lib.rs} | 2 ++ src/test/run-make/msvc-data-only/Makefile | 8 -------- .../msvc-data-only/bar.rs => run-pass/msvc-data-only.rs} | 6 ++++-- 3 files changed, 6 insertions(+), 10 deletions(-) rename src/test/{run-make/msvc-data-only/foo.rs => auxiliary/msvc-data-only-lib.rs} (95%) delete mode 100644 src/test/run-make/msvc-data-only/Makefile rename src/test/{run-make/msvc-data-only/bar.rs => run-pass/msvc-data-only.rs} (78%) diff --git a/src/test/run-make/msvc-data-only/foo.rs b/src/test/auxiliary/msvc-data-only-lib.rs similarity index 95% rename from src/test/run-make/msvc-data-only/foo.rs rename to src/test/auxiliary/msvc-data-only-lib.rs index 38bff8be125..71fb9a51948 100644 --- a/src/test/run-make/msvc-data-only/foo.rs +++ b/src/test/auxiliary/msvc-data-only-lib.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// no-prefer-dynamic + #![crate_type = "rlib"] pub static FOO: i32 = 42; diff --git a/src/test/run-make/msvc-data-only/Makefile b/src/test/run-make/msvc-data-only/Makefile deleted file mode 100644 index 251a3a9768d..00000000000 --- a/src/test/run-make/msvc-data-only/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# Test that on *-pc-windows-msvc we can link to a rlib containing only data. -# See #26591, #27438 - --include ../tools.mk - -all: - $(RUSTC) foo.rs - $(RUSTC) bar.rs diff --git a/src/test/run-make/msvc-data-only/bar.rs b/src/test/run-pass/msvc-data-only.rs similarity index 78% rename from src/test/run-make/msvc-data-only/bar.rs rename to src/test/run-pass/msvc-data-only.rs index 0e3af9ff3fd..ad6888c4d30 100644 --- a/src/test/run-make/msvc-data-only/bar.rs +++ b/src/test/run-pass/msvc-data-only.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate foo; +// aux-build:msvc-data-only-lib.rs + +extern crate msvc_data_only_lib; fn main() { - println!("The answer is {} !", foo::FOO); + println!("The answer is {} !", msvc_data_only_lib::FOO); } From 38f1c47d18761414cbe69e76b4d76c71afc24789 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Fri, 25 Sep 2015 18:53:14 -0700 Subject: [PATCH 3/3] Removed unused parameter. --- src/librustc_trans/trans/base.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 02aeb110353..69268f1fde2 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2616,9 +2616,8 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) { // when using MSVC linker. We do this only for data, as linker can fix up // code references on its own. // See #26591, #27438 -fn create_imps(cx: &SharedCrateContext, _reachable: &HashSet<&str>) { +fn create_imps(cx: &SharedCrateContext) { unsafe { - for ccx in cx.iter() { let exported: Vec<_> = iter_globals(ccx.llmod()) .filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint && @@ -2857,9 +2856,8 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat } if sess.target.target.options.is_like_msvc && - sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib || - *ct == config::CrateTypeStaticlib) { - create_imps(&shared_ccx, &reachable_symbols.iter().map(|x| &x[..]).collect()); + sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) { + create_imps(&shared_ccx); } let metadata_module = ModuleTranslation {