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
This commit is contained in:
commit
7bf4c885fc
@ -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,77 @@ 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) {
|
||||
unsafe {
|
||||
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();
|
||||
|
||||
struct ValueIter {
|
||||
cur: ValueRef,
|
||||
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
|
||||
}
|
||||
|
||||
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
|
||||
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<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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 +2855,11 @@ 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) {
|
||||
create_imps(&shared_ccx);
|
||||
}
|
||||
|
||||
let metadata_module = ModuleTranslation {
|
||||
llcx: shared_ccx.metadata_llcx(),
|
||||
llmod: shared_ccx.metadata_llmod(),
|
||||
|
15
src/test/auxiliary/msvc-data-only-lib.rs
Normal file
15
src/test/auxiliary/msvc-data-only-lib.rs
Normal file
@ -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.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
pub static FOO: i32 = 42;
|
17
src/test/run-pass/msvc-data-only.rs
Normal file
17
src/test/run-pass/msvc-data-only.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:msvc-data-only-lib.rs
|
||||
|
||||
extern crate msvc_data_only_lib;
|
||||
|
||||
fn main() {
|
||||
println!("The answer is {} !", msvc_data_only_lib::FOO);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user