mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-12 09:57:43 +00:00
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 {
|
unsafe {
|
||||||
let mut declared = HashSet::new();
|
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.
|
// Collect all external declarations in all compilation units.
|
||||||
for ccx in cx.iter() {
|
for ccx in cx.iter() {
|
||||||
for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
|
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 {
|
let i8p_ty = Type::i8p(&ccx);
|
||||||
cur: ValueRef,
|
for val in exported {
|
||||||
step: unsafe extern "C" fn(ValueRef) -> ValueRef,
|
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
|
||||||
}
|
let imp_name = String::from("__imp_") +
|
||||||
|
str::from_utf8(name.to_bytes()).unwrap();
|
||||||
impl Iterator for ValueIter {
|
let imp_name = CString::new(imp_name).unwrap();
|
||||||
type Item = ValueRef;
|
let imp = llvm::LLVMAddGlobal(ccx.llmod(), i8p_ty.to_ref(),
|
||||||
|
imp_name.as_ptr() as *const _);
|
||||||
fn next(&mut self) -> Option<ValueRef> {
|
llvm::LLVMSetInitializer(imp, llvm::LLVMConstBitCast(val, i8p_ty.to_ref()));
|
||||||
let old = self.cur;
|
llvm::SetLinkage(imp, llvm::ExternalLinkage);
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
/// 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
|
/// 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
|
/// 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());
|
&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 {
|
let metadata_module = ModuleTranslation {
|
||||||
llcx: shared_ccx.metadata_llcx(),
|
llcx: shared_ccx.metadata_llcx(),
|
||||||
llmod: shared_ccx.metadata_llmod(),
|
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…
Reference in New Issue
Block a user