Skip to content

Commit 3d32cf5

Browse files
committed
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.
1 parent 9a2415b commit 3d32cf5

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

Diff for: src/librustc_trans/trans/base.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
237237
llvm::set_thread_local(c, true);
238238
}
239239
}
240+
if ccx.use_dll_storage_attrs() {
241+
llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass);
242+
}
240243
ccx.externs().borrow_mut().insert(name.to_string(), c);
241244
return c;
242245
}
@@ -1940,11 +1943,17 @@ pub fn update_linkage(ccx: &CrateContext,
19401943
match id {
19411944
Some(id) if ccx.reachable().contains(&id) => {
19421945
llvm::SetLinkage(llval, llvm::ExternalLinkage);
1946+
if ccx.use_dll_storage_attrs() {
1947+
llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
1948+
}
19431949
},
19441950
_ => {
19451951
// `id` does not refer to an item in `ccx.reachable`.
19461952
if ccx.sess().opts.cg.codegen_units > 1 {
19471953
llvm::SetLinkage(llval, llvm::ExternalLinkage);
1954+
if ccx.use_dll_storage_attrs() {
1955+
llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
1956+
}
19481957
} else {
19491958
llvm::SetLinkage(llval, llvm::InternalLinkage);
19501959
}
@@ -2103,9 +2112,15 @@ fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
21032112
if ccx.tcx().lang_items.stack_exhausted() == Some(def) {
21042113
attributes::split_stack(llfn, false);
21052114
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
2115+
if ccx.use_dll_storage_attrs() {
2116+
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
2117+
}
21062118
}
21072119
if ccx.tcx().lang_items.eh_personality() == Some(def) {
21082120
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
2121+
if ccx.use_dll_storage_attrs() {
2122+
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
2123+
}
21092124
}
21102125
}
21112126

@@ -2172,7 +2187,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
21722187
// FIXME: #16581: Marking a symbol in the executable with `dllexport`
21732188
// linkage forces MinGW's linker to output a `.reloc` section for ASLR
21742189
if ccx.sess().target.target.options.is_like_windows {
2175-
unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
2190+
llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
21762191
}
21772192

21782193
let llbb = unsafe {
@@ -2589,6 +2604,7 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {
25892604
if !declared.contains(&name) &&
25902605
!reachable.contains(str::from_utf8(&name).unwrap()) {
25912606
llvm::SetLinkage(val, llvm::InternalLinkage);
2607+
llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
25922608
}
25932609
}
25942610
}

Diff for: src/librustc_trans/trans/context.rs

+55
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub struct SharedCrateContext<'tcx> {
7575

7676
available_monomorphizations: RefCell<FnvHashSet<String>>,
7777
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
78+
use_dll_storage_attrs: bool,
7879
}
7980

8081
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
@@ -251,6 +252,51 @@ impl<'tcx> SharedCrateContext<'tcx> {
251252
create_context_and_module(&tcx.sess, "metadata")
252253
};
253254

255+
// An interesting part of Windows which MSVC forces our hand on (and
256+
// apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
257+
// attributes in LLVM IR as well as native dependencies (in C these
258+
// correspond to `__declspec(dllimport)`).
259+
//
260+
// Whenever a dynamic library is built by MSVC it must have its public
261+
// interface specified by functions tagged with `dllexport` or otherwise
262+
// they're not available to be linked against. This poses a few problems
263+
// for the compiler, some of which are somewhat fundamental, but we use
264+
// the `use_dll_storage_attrs` variable below to attach the `dllexport`
265+
// attribute to all LLVM functions that are reachable (e.g. they're
266+
// already tagged with external linkage). This is suboptimal for a few
267+
// reasons:
268+
//
269+
// * If an object file will never be included in a dynamic library,
270+
// there's no need to attach the dllexport attribute. Most object
271+
// files in Rust are not destined to become part of a dll as binaries
272+
// are statically linked by default.
273+
// * If the compiler is emitting both an rlib and a dylib, the same
274+
// source object file is currently used but with MSVC this may be less
275+
// feasible. The compiler may be able to get around this, but it may
276+
// involve some invasive changes to deal with this.
277+
//
278+
// The flipside of this situation is that whenever you link to a dll and
279+
// you import a function from it, the import should be tagged with
280+
// `dllimport`. At this time, however, the compiler does not emit
281+
// `dllimport` for any declarations other than constants (where it is
282+
// required), which is again suboptimal for even more reasons!
283+
//
284+
// * Calling a function imported from another dll without using
285+
// `dllimport` causes the linker/compiler to have extra overhead (one
286+
// `jmp` instruction on x86) when calling the function.
287+
// * The same object file may be used in different circumstances, so a
288+
// function may be imported from a dll if the object is linked into a
289+
// dll, but it may be just linked against if linked into an rlib.
290+
// * The compiler has no knowledge about whether native functions should
291+
// be tagged dllimport or not.
292+
//
293+
// For now the compiler takes the perf hit (I do not have any numbers to
294+
// this effect) by marking very little as `dllimport` and praying the
295+
// linker will take care of everything. Fixing this problem will likely
296+
// require adding a few attributes to Rust itself (feature gated at the
297+
// start) and then strongly recommending static linkage on MSVC!
298+
let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
299+
254300
let mut shared_ccx = SharedCrateContext {
255301
local_ccxs: Vec::with_capacity(local_count),
256302
metadata_llmod: metadata_llmod,
@@ -277,6 +323,7 @@ impl<'tcx> SharedCrateContext<'tcx> {
277323
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
278324
available_monomorphizations: RefCell::new(FnvHashSet()),
279325
available_drop_glues: RefCell::new(FnvHashMap()),
326+
use_dll_storage_attrs: use_dll_storage_attrs,
280327
};
281328

282329
for i in 0..local_count {
@@ -365,6 +412,10 @@ impl<'tcx> SharedCrateContext<'tcx> {
365412
pub fn stats<'a>(&'a self) -> &'a Stats {
366413
&self.stats
367414
}
415+
416+
pub fn use_dll_storage_attrs(&self) -> bool {
417+
self.use_dll_storage_attrs
418+
}
368419
}
369420

370421
impl<'tcx> LocalCrateContext<'tcx> {
@@ -733,6 +784,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
733784
// values.
734785
self.shared.check_drop_flag_for_sanity
735786
}
787+
788+
pub fn use_dll_storage_attrs(&self) -> bool {
789+
self.shared.use_dll_storage_attrs()
790+
}
736791
}
737792

738793
/// Declare any llvm intrinsics that you might need

0 commit comments

Comments
 (0)