Skip to content

Commit e82bb91

Browse files
committed
Fix dllimports of static data from rlibs
1 parent cefe5f2 commit e82bb91

File tree

4 files changed

+105
-31
lines changed

4 files changed

+105
-31
lines changed

src/librustc_trans/trans/base.rs

+69-31
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,74 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
26232609
}
26242610
}
26252611
}
2612+
}
26262613

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, _reachable: &HashSet<&str>) {
2620+
unsafe {
26272621

2628-
struct ValueIter {
2629-
cur: ValueRef,
2630-
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
2622+
for ccx in cx.iter() {
2623+
let exported: Vec<_> = iter_globals(ccx.llmod())
2624+
.filter(|&val| llvm::LLVMGetLinkage(val) == llvm::ExternalLinkage as c_uint &&
2625+
llvm::LLVMIsDeclaration(val) == 0)
2626+
.collect();
2627+
2628+
let i8p_ty = Type::i8p(&ccx);
2629+
for val in exported {
2630+
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
2631+
let imp_name = String::from("__imp_") +
2632+
str::from_utf8(name.to_bytes()).unwrap();
2633+
let imp_name = CString::new(imp_name).unwrap();
2634+
let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(),
2635+
imp_name.as_ptr() as *const _);
2636+
llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref()));
2637+
llvm::SetLinkage(imp, llvm::ExternalLinkage);
2638+
}
2639+
}
26312640
}
2641+
}
26322642

2633-
impl Iterator for ValueIter {
2634-
type Item = ValueRef;
2643+
struct ValueIter {
2644+
cur: ValueRef,
2645+
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
2646+
}
26352647

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-
}
2648+
impl Iterator for ValueIter {
2649+
type Item = ValueRef;
2650+
2651+
fn next(&mut self) -> Option<ValueRef> {
2652+
let old = self.cur;
2653+
if !old.is_null() {
2654+
self.cur = unsafe {
2655+
let step: unsafe extern "C" fn(ValueRef) -> ValueRef =
2656+
mem::transmute_copy(&self.step);
2657+
step(old)
2658+
};
2659+
Some(old)
2660+
} else {
2661+
None
2662+
}
2663+
}
2664+
}
2665+
2666+
fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
2667+
unsafe {
2668+
ValueIter {
2669+
cur: llvm::LLVMGetFirstGlobal(llmod),
2670+
step: llvm::LLVMGetNextGlobal,
2671+
}
2672+
}
2673+
}
2674+
2675+
fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter {
2676+
unsafe {
2677+
ValueIter {
2678+
cur: llvm::LLVMGetFirstFunction(llmod),
2679+
step: llvm::LLVMGetNextFunction,
26482680
}
26492681
}
26502682
}
@@ -2824,6 +2856,12 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat
28242856
&reachable_symbols.iter().map(|x| &x[..]).collect());
28252857
}
28262858

2859+
if sess.target.target.options.is_like_msvc &&
2860+
sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib ||
2861+
*ct == config::CrateTypeStaticlib) {
2862+
create_imps(&shared_ccx, &reachable_symbols.iter().map(|x| &x[..]).collect());
2863+
}
2864+
28272865
let metadata_module = ModuleTranslation {
28282866
llcx: shared_ccx.metadata_llcx(),
28292867
llmod: shared_ccx.metadata_llmod(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Test that on *-pc-windows-msvc we can link to a rlib containing only data.
2+
# See #26591, #27438
3+
4+
-include ../tools.mk
5+
6+
all:
7+
$(RUSTC) foo.rs
8+
$(RUSTC) bar.rs
+15
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+
extern crate foo;
12+
13+
fn main() {
14+
println!("The answer is {} !", foo::FOO);
15+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
#![crate_type = "rlib"]
12+
13+
pub static FOO: i32 = 42;

0 commit comments

Comments
 (0)