Skip to content

Commit 7bf4c88

Browse files
committed
Auto merge of #28646 - vadimcn:imps, r=alexcrichton
As discussed in the referenced issues, this PR makes rustc emit `__imp_<symbol>` stubs for all public static data to ensure smooth linking in on `-windows-msvc` targets. Resolves #26591, cc #27438
2 parents 6f880ee + 38f1c47 commit 7bf4c88

File tree

3 files changed

+99
-31
lines changed

3 files changed

+99
-31
lines changed

src/librustc_trans/trans/base.rs

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2570,20 +2570,6 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
25702570
unsafe {
25712571
let mut declared = HashSet::new();
25722572

2573-
let iter_globals = |llmod| {
2574-
ValueIter {
2575-
cur: llvm::LLVMGetFirstGlobal(llmod),
2576-
step: llvm::LLVMGetNextGlobal,
2577-
}
2578-
};
2579-
2580-
let iter_functions = |llmod| {
2581-
ValueIter {
2582-
cur: llvm::LLVMGetFirstFunction(llmod),
2583-
step: llvm::LLVMGetNextFunction,
2584-
}
2585-
};
2586-
25872573
// Collect all external declarations in all compilation units.
25882574
for ccx in cx.iter() {
25892575
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
@@ -2623,28 +2609,73 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
26232609
}
26242610
}
26252611
}
2612+
}
2613+
2614+
// Create a `__imp_<symbol> = &symbol` global for every public static `symbol`.
2615+
// This is required to satisfy `dllimport` references to static data in .rlibs
2616+
// when using MSVC linker. We do this only for data, as linker can fix up
2617+
// code references on its own.
2618+
// See #26591, #27438
2619+
fn create_imps(cx: &SharedCrateContext) {
2620+
unsafe {
2621+
for ccx in cx.iter() {
2622+
let exported: Vec<_> = iter_globals(ccx.llmod())
2623+
.filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint &&
2624+
llvm::LLVMIsDeclaration(val) == 0)
2625+
.collect();
2626+
2627+
let i8p_ty = Type::i8p(&ccx);
2628+
for val in exported {
2629+
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
2630+
let imp_name = String::from("__imp_") +
2631+
str::from_utf8(name.to_bytes()).unwrap();
2632+
let imp_name = CString::new(imp_name).unwrap();
2633+
let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(),
2634+
imp_name.as_ptr() as *const _);
2635+
llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref()));
2636+
llvm::SetLinkage(imp, llvm::ExternalLinkage);
2637+
}
2638+
}
2639+
}
2640+
}
2641+
2642+
struct ValueIter {
2643+
cur: ValueRef,
2644+
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
2645+
}
26262646

2647+
impl Iterator for ValueIter {
2648+
type Item = ValueRef;
26272649

2628-
struct ValueIter {
2629-
cur: ValueRef,
2630-
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
2650+
fn next(&mut self) -> Option<ValueRef> {
2651+
let old = self.cur;
2652+
if !old.is_null() {
2653+
self.cur = unsafe {
2654+
let step: unsafe extern "C" fn(ValueRef) -> ValueRef =
2655+
mem::transmute_copy(&self.step);
2656+
step(old)
2657+
};
2658+
Some(old)
2659+
} else {
2660+
None
2661+
}
26312662
}
2663+
}
26322664

2633-
impl Iterator for ValueIter {
2634-
type Item = ValueRef;
2665+
fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
2666+
unsafe {
2667+
ValueIter {
2668+
cur: llvm::LLVMGetFirstGlobal(llmod),
2669+
step: llvm::LLVMGetNextGlobal,
2670+
}
2671+
}
2672+
}
26352673

2636-
fn next(&mut self) -> Option<ValueRef> {
2637-
let old = self.cur;
2638-
if !old.is_null() {
2639-
self.cur = unsafe {
2640-
let step: unsafe extern "C" fn(ValueRef) -> ValueRef =
2641-
mem::transmute_copy(&self.step);
2642-
step(old)
2643-
};
2644-
Some(old)
2645-
} else {
2646-
None
2647-
}
2674+
fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter {
2675+
unsafe {
2676+
ValueIter {
2677+
cur: llvm::LLVMGetFirstFunction(llmod),
2678+
step: llvm::LLVMGetNextFunction,
26482679
}
26492680
}
26502681
}
@@ -2824,6 +2855,11 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
28242855
&reachable_symbols.iter().map(|x| &x[..]).collect());
28252856
}
28262857

2858+
if sess.target.target.options.is_like_msvc &&
2859+
sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
2860+
create_imps(&shared_ccx);
2861+
}
2862+
28272863
let metadata_module = ModuleTranslation {
28282864
llcx: shared_ccx.metadata_llcx(),
28292865
llmod: shared_ccx.metadata_llmod(),
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
13+
#![crate_type = "rlib"]
14+
15+
pub static FOO: i32 = 42;

src/test/run-pass/msvc-data-only.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:msvc-data-only-lib.rs
12+
13+
extern crate msvc_data_only_lib;
14+
15+
fn main() {
16+
println!("The answer is {} !", msvc_data_only_lib::FOO);
17+
}

0 commit comments

Comments
 (0)