rustc_trans: Apply dllexport attributes for MSVC
This commit modifies the compiler to emit `dllexport` for all reachable functions and data on MSVC targets, regardless of whether a dynamic library is being created or not. More details can be found in the commit itself.
This commit is contained in:
parent
9a2415b822
commit
3d32cf5d9a
@ -237,6 +237,9 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
|
||||
llvm::set_thread_local(c, true);
|
||||
}
|
||||
}
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass);
|
||||
}
|
||||
ccx.externs().borrow_mut().insert(name.to_string(), c);
|
||||
return c;
|
||||
}
|
||||
@ -1940,11 +1943,17 @@ pub fn update_linkage(ccx: &CrateContext,
|
||||
match id {
|
||||
Some(id) if ccx.reachable().contains(&id) => {
|
||||
llvm::SetLinkage(llval, llvm::ExternalLinkage);
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// `id` does not refer to an item in `ccx.reachable`.
|
||||
if ccx.sess().opts.cg.codegen_units > 1 {
|
||||
llvm::SetLinkage(llval, llvm::ExternalLinkage);
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
|
||||
}
|
||||
} else {
|
||||
llvm::SetLinkage(llval, llvm::InternalLinkage);
|
||||
}
|
||||
@ -2103,9 +2112,15 @@ fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
|
||||
if ccx.tcx().lang_items.stack_exhausted() == Some(def) {
|
||||
attributes::split_stack(llfn, false);
|
||||
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
|
||||
}
|
||||
}
|
||||
if ccx.tcx().lang_items.eh_personality() == Some(def) {
|
||||
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
|
||||
if ccx.use_dll_storage_attrs() {
|
||||
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2172,7 +2187,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
|
||||
// FIXME: #16581: Marking a symbol in the executable with `dllexport`
|
||||
// linkage forces MinGW's linker to output a `.reloc` section for ASLR
|
||||
if ccx.sess().target.target.options.is_like_windows {
|
||||
unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
|
||||
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
|
||||
}
|
||||
|
||||
let llbb = unsafe {
|
||||
@ -2589,6 +2604,7 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
|
||||
if !declared.contains(&name) &&
|
||||
!reachable.contains(str::from_utf8(&name).unwrap()) {
|
||||
llvm::SetLinkage(val, llvm::InternalLinkage);
|
||||
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ pub struct SharedCrateContext<'tcx> {
|
||||
|
||||
available_monomorphizations: RefCell<FnvHashSet<String>>,
|
||||
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
|
||||
use_dll_storage_attrs: bool,
|
||||
}
|
||||
|
||||
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
|
||||
@ -251,6 +252,51 @@ impl<'tcx> SharedCrateContext<'tcx> {
|
||||
create_context_and_module(&tcx.sess, "metadata")
|
||||
};
|
||||
|
||||
// An interesting part of Windows which MSVC forces our hand on (and
|
||||
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
|
||||
// attributes in LLVM IR as well as native dependencies (in C these
|
||||
// correspond to `__declspec(dllimport)`).
|
||||
//
|
||||
// Whenever a dynamic library is built by MSVC it must have its public
|
||||
// interface specified by functions tagged with `dllexport` or otherwise
|
||||
// they're not available to be linked against. This poses a few problems
|
||||
// for the compiler, some of which are somewhat fundamental, but we use
|
||||
// the `use_dll_storage_attrs` variable below to attach the `dllexport`
|
||||
// attribute to all LLVM functions that are reachable (e.g. they're
|
||||
// already tagged with external linkage). This is suboptimal for a few
|
||||
// reasons:
|
||||
//
|
||||
// * If an object file will never be included in a dynamic library,
|
||||
// there's no need to attach the dllexport attribute. Most object
|
||||
// files in Rust are not destined to become part of a dll as binaries
|
||||
// are statically linked by default.
|
||||
// * If the compiler is emitting both an rlib and a dylib, the same
|
||||
// source object file is currently used but with MSVC this may be less
|
||||
// feasible. The compiler may be able to get around this, but it may
|
||||
// involve some invasive changes to deal with this.
|
||||
//
|
||||
// The flipside of this situation is that whenever you link to a dll and
|
||||
// you import a function from it, the import should be tagged with
|
||||
// `dllimport`. At this time, however, the compiler does not emit
|
||||
// `dllimport` for any declarations other than constants (where it is
|
||||
// required), which is again suboptimal for even more reasons!
|
||||
//
|
||||
// * Calling a function imported from another dll without using
|
||||
// `dllimport` causes the linker/compiler to have extra overhead (one
|
||||
// `jmp` instruction on x86) when calling the function.
|
||||
// * The same object file may be used in different circumstances, so a
|
||||
// function may be imported from a dll if the object is linked into a
|
||||
// dll, but it may be just linked against if linked into an rlib.
|
||||
// * The compiler has no knowledge about whether native functions should
|
||||
// be tagged dllimport or not.
|
||||
//
|
||||
// For now the compiler takes the perf hit (I do not have any numbers to
|
||||
// this effect) by marking very little as `dllimport` and praying the
|
||||
// linker will take care of everything. Fixing this problem will likely
|
||||
// require adding a few attributes to Rust itself (feature gated at the
|
||||
// start) and then strongly recommending static linkage on MSVC!
|
||||
let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
|
||||
|
||||
let mut shared_ccx = SharedCrateContext {
|
||||
local_ccxs: Vec::with_capacity(local_count),
|
||||
metadata_llmod: metadata_llmod,
|
||||
@ -277,6 +323,7 @@ impl<'tcx> SharedCrateContext<'tcx> {
|
||||
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
|
||||
available_monomorphizations: RefCell::new(FnvHashSet()),
|
||||
available_drop_glues: RefCell::new(FnvHashMap()),
|
||||
use_dll_storage_attrs: use_dll_storage_attrs,
|
||||
};
|
||||
|
||||
for i in 0..local_count {
|
||||
@ -365,6 +412,10 @@ impl<'tcx> SharedCrateContext<'tcx> {
|
||||
pub fn stats<'a>(&'a self) -> &'a Stats {
|
||||
&self.stats
|
||||
}
|
||||
|
||||
pub fn use_dll_storage_attrs(&self) -> bool {
|
||||
self.use_dll_storage_attrs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LocalCrateContext<'tcx> {
|
||||
@ -733,6 +784,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
// values.
|
||||
self.shared.check_drop_flag_for_sanity
|
||||
}
|
||||
|
||||
pub fn use_dll_storage_attrs(&self) -> bool {
|
||||
self.shared.use_dll_storage_attrs()
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare any llvm intrinsics that you might need
|
||||
|
Loading…
Reference in New Issue
Block a user