]> git.lizzy.rs Git - rust.git/commitdiff
Fix dllimports of static data from rlibs
authorVadim Chugunov <vadimcn@gmail.com>
Fri, 21 Aug 2015 07:41:07 +0000 (00:41 -0700)
committerVadim Chugunov <vadimcn@gmail.com>
Fri, 25 Sep 2015 05:07:12 +0000 (22:07 -0700)
src/librustc_trans/trans/base.rs
src/test/run-make/msvc-data-only/Makefile [new file with mode: 0644]
src/test/run-make/msvc-data-only/bar.rs [new file with mode: 0644]
src/test/run-make/msvc-data-only/foo.rs [new file with mode: 0644]

index dd0c06c9142e60b62af197a1626dc032e21c294d..02aeb1103539a3df8969d95ae13dcafb5fdde495 100644 (file)
@@ -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,28 +2609,74 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
             }
         }
     }
+}
 
+// Create a `__imp_<symbol> = &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();
+
+            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);
+            }
+        }
     }
+}
 
-    impl Iterator for ValueIter {
-        type Item = ValueRef;
+struct ValueIter {
+    cur: ValueRef,
+    step: unsafe extern "C" fn(ValueRef) -> ValueRef,
+}
 
-        fn next(&mut self) -> Option<ValueRef> {
-            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
-            }
+impl Iterator for ValueIter {
+    type Item = ValueRef;
+
+    fn next(&mut self) -> Option<ValueRef> {
+        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,
         }
     }
 }
@@ -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 (file)
index 0000000..251a3a9
--- /dev/null
@@ -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 (file)
index 0000000..0e3af9f
--- /dev/null
@@ -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 <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 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 (file)
index 0000000..38bff8b
--- /dev/null
@@ -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 <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_type = "rlib"]
+
+pub static FOO: i32 = 42;