Skip to content

Commit d3c03d0

Browse files
committed
Auto merge of #26569 - alexcrichton:msvc-llvm-update, r=brson
Now that LLVM has been updated, the only remaining roadblock to implementing unwinding for MSVC is to fill out the runtime support in `std::rt::unwind::seh`. This commit does precisely that, fixing up some other bits and pieces along the way: * The `seh` unwinding module now uses `RaiseException` to initiate a panic. * The `rust_try.ll` file was rewritten for MSVC (as it's quite different) and is located at `rust_try_msvc_64.ll`, only included on MSVC builds for now. * The personality function for all landing pads generated by LLVM is hard-wired to `__C_specific_handler` instead of the standard `rust_eh_personality` lang item. This is required to get LLVM to emit SEH unwinding information instead of DWARF unwinding information. This also means that on MSVC the `rust_eh_personality` function is entirely unused (but is defined as it's a lang item). More details about how panicking works on SEH can be found in the `rust_try_msvc_64.ll` or `seh.rs` files, but I'm always open to adding more comments! A key aspect of this PR is missing, however, which is that **unwinding is still turned off by default for MSVC**. There is a [bug in llvm][llvm-bug] which causes optimizations to inline enough landing pads that LLVM chokes. If the compiler is optimized at `-O1` (where inlining isn't enabled) then it can bootstrap with unwinding enabled, but when optimized at `-O2` (inlining is enabled) then it hits a fatal LLVM error. [llvm-bug]: https://llvm.org/bugs/show_bug.cgi?id=23884
2 parents 773052a + 759a7f1 commit d3c03d0

File tree

10 files changed

+326
-132
lines changed

10 files changed

+326
-132
lines changed

mk/cfg/x86_64-pc-windows-msvc.mk

-58
Original file line numberDiff line numberDiff line change
@@ -23,64 +23,6 @@ CFG_RUN_x86_64-pc-windows-msvc=$(2)
2323
CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2))
2424
CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32
2525

26-
# These two environment variables are scraped by the `./configure` script and
27-
# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
28-
# for `link.exe` to find standard libraries (the LIB variable).
29-
ifdef CFG_MSVC_INCLUDE_PATH
30-
export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
31-
endif
32-
ifdef CFG_MSVC_LIB_PATH
33-
export LIB := $(CFG_MSVC_LIB_PATH)
34-
endif
35-
36-
# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
37-
# but it's not the one that we want. As a result we make sure that our detected
38-
# `link.exe` shows up in PATH first.
39-
ifdef CFG_MSVC_LINK
40-
export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
41-
endif
42-
43-
# There are more comments about this available in the target specification for
44-
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
45-
# instead of `lib.exe` for assembling archives, so we need to inject this custom
46-
# dependency here.
47-
NATIVE_TOOL_DEPS_core_T_x86_64-pc-windows-msvc += llvm-ar.exe
48-
INSTALLED_BINS_x86_64-pc-windows-msvc += llvm-ar.exe
49-
50-
# When working with MSVC on windows, each DLL needs to explicitly declare its
51-
# interface to the outside world through some means. The options for doing so
52-
# include:
53-
#
54-
# 1. A custom attribute on each function itself
55-
# 2. A linker argument saying what to export
56-
# 3. A file which lists all symbols that need to be exported
57-
#
58-
# The Rust compiler takes care (1) for us for all Rust code by annotating all
59-
# public-facing functions with dllexport, but we have a few native dependencies
60-
# which need to cross the DLL boundary. The most important of these dependencies
61-
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
62-
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
63-
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
64-
#
65-
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
66-
# Windows for us, so we're forced to do it ourselves if we want it (which seems
67-
# like the path of least resistance right now). To do this we generate a `.DEF`
68-
# file [1] which we then custom-pass to the linker when building the rustc_llvm
69-
# crate. This DEF file list all symbols that are exported from
70-
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
71-
#
72-
# Fun times!
73-
#
74-
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
75-
RUSTFLAGS_rustc_llvm_T_x86_64-pc-windows-msvc += \
76-
-C link-args="-DEF:x86_64-pc-windows-msvc/rt/rustc_llvm.def"
77-
CUSTOM_DEPS_rustc_llvm_T_x86_64-pc-windows-msvc += \
78-
x86_64-pc-windows-msvc/rt/rustc_llvm.def
79-
80-
x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \
81-
$(S)src/librustc_llvm/lib.rs
82-
$(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA)
83-
8426
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
8527
# bootstrapping from itself. This is relevant during stage0, and other parts of
8628
# the build system take this into account.

mk/platform.mk

+69
Original file line numberDiff line numberDiff line change
@@ -238,3 +238,72 @@ endef
238238

239239
$(foreach target,$(CFG_TARGET), \
240240
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))
241+
242+
# These two environment variables are scraped by the `./configure` script and
243+
# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
244+
# for `link.exe` to find standard libraries (the LIB variable).
245+
ifdef CFG_MSVC_INCLUDE_PATH
246+
export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
247+
endif
248+
ifdef CFG_MSVC_LIB_PATH
249+
export LIB := $(CFG_MSVC_LIB_PATH)
250+
endif
251+
252+
# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
253+
# but it's not the one that we want. As a result we make sure that our detected
254+
# `link.exe` shows up in PATH first.
255+
ifdef CFG_MSVC_LINK
256+
export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
257+
endif
258+
259+
# There are more comments about this available in the target specification for
260+
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
261+
# instead of `lib.exe` for assembling archives, so we need to inject this custom
262+
# dependency here.
263+
define ADD_LLVM_AR_TO_MSVC_DEPS
264+
ifeq ($$(findstring msvc,$(1)),msvc)
265+
NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe
266+
INSTALLED_BINS_$(1) += llvm-ar.exe
267+
endif
268+
endef
269+
270+
$(foreach target,$(CFG_TARGET), \
271+
$(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target))))
272+
273+
# When working with MSVC on windows, each DLL needs to explicitly declare its
274+
# interface to the outside world through some means. The options for doing so
275+
# include:
276+
#
277+
# 1. A custom attribute on each function itself
278+
# 2. A linker argument saying what to export
279+
# 3. A file which lists all symbols that need to be exported
280+
#
281+
# The Rust compiler takes care (1) for us for all Rust code by annotating all
282+
# public-facing functions with dllexport, but we have a few native dependencies
283+
# which need to cross the DLL boundary. The most important of these dependencies
284+
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
285+
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
286+
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
287+
#
288+
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
289+
# Windows for us, so we're forced to do it ourselves if we want it (which seems
290+
# like the path of least resistance right now). To do this we generate a `.DEF`
291+
# file [1] which we then custom-pass to the linker when building the rustc_llvm
292+
# crate. This DEF file list all symbols that are exported from
293+
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
294+
#
295+
# Fun times!
296+
#
297+
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
298+
define ADD_RUSTC_LLVM_DEF_TO_MSVC
299+
ifeq ($$(findstring msvc,$(1)),msvc)
300+
RUSTFLAGS_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def"
301+
CUSTOM_DEPS_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def
302+
303+
$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs
304+
$$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA)
305+
endif
306+
endef
307+
308+
$(foreach target,$(CFG_TARGET), \
309+
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))

mk/rt.mk

+6-3
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,12 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
5353
NATIVE_DEPS_miniz_$(1) = miniz.c
5454
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
5555
rust_android_dummy.c
56-
NATIVE_DEPS_rustrt_native_$(1) := \
57-
rust_try.ll \
58-
arch/$$(HOST_$(1))/record_sp.S
56+
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
57+
ifeq ($$(findstring msvc,$(1)),msvc)
58+
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
59+
else
60+
NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
61+
endif
5962
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
6063
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
6164

src/librustc_trans/back/link.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1214,11 +1214,13 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
12141214

12151215
// Just need to tell the linker about where the library lives and
12161216
// what its name is
1217-
if let Some(dir) = cratepath.parent() {
1217+
let parent = cratepath.parent();
1218+
if let Some(dir) = parent {
12181219
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
12191220
}
12201221
let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
1221-
cmd.link_dylib(&unlib(&sess.target, filestem));
1222+
cmd.link_rust_dylib(&unlib(&sess.target, filestem),
1223+
parent.unwrap_or(Path::new("")));
12221224
}
12231225
}
12241226

src/librustc_trans/back/linker.rs

+18
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use std::ffi::OsString;
1212
use std::path::{Path, PathBuf};
1313
use std::process::Command;
14+
use std::fs;
1415

1516
use rustc_back::archive;
1617
use session::Session;
@@ -25,6 +26,7 @@ use session::config;
2526
/// MSVC linker (e.g. `link.exe`) is being used.
2627
pub trait Linker {
2728
fn link_dylib(&mut self, lib: &str);
29+
fn link_rust_dylib(&mut self, lib: &str, path: &Path);
2830
fn link_framework(&mut self, framework: &str);
2931
fn link_staticlib(&mut self, lib: &str);
3032
fn link_rlib(&mut self, lib: &Path);
@@ -67,6 +69,10 @@ impl<'a> Linker for GnuLinker<'a> {
6769
fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
6870
fn args(&mut self, args: &[String]) { self.cmd.args(args); }
6971

72+
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
73+
self.cmd.arg("-l").arg(lib);
74+
}
75+
7076
fn link_framework(&mut self, framework: &str) {
7177
self.cmd.arg("-framework").arg(framework);
7278
}
@@ -189,6 +195,18 @@ impl<'a> Linker for MsvcLinker<'a> {
189195
fn link_dylib(&mut self, lib: &str) {
190196
self.cmd.arg(&format!("{}.lib", lib));
191197
}
198+
199+
fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
200+
// When producing a dll, the MSVC linker may not actually emit a
201+
// `foo.lib` file if the dll doesn't actually export any symbols, so we
202+
// check to see if the file is there and just omit linking to it if it's
203+
// not present.
204+
let name = format!("{}.lib", lib);
205+
if fs::metadata(&path.join(&name)).is_ok() {
206+
self.cmd.arg(name);
207+
}
208+
}
209+
192210
fn link_staticlib(&mut self, lib: &str) {
193211
self.cmd.arg(&format!("{}.lib", lib));
194212
}

src/librustc_trans/trans/cleanup.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -856,18 +856,36 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
856856
// this function, so we just codegen a generic reference to it. We don't
857857
// specify any of the types for the function, we just make it a symbol
858858
// that LLVM can later use.
859+
//
860+
// Note that MSVC is a little special here in that we don't use the
861+
// `eh_personality` lang item at all. Currently LLVM has support for
862+
// both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
863+
// *name of the personality function* to decide what kind of unwind side
864+
// tables/landing pads to emit. It looks like Dwarf is used by default,
865+
// injecting a dependency on the `_Unwind_Resume` symbol for resuming
866+
// an "exception", but for MSVC we want to force SEH. This means that we
867+
// can't actually have the personality function be our standard
868+
// `rust_eh_personality` function, but rather we wired it up to the
869+
// CRT's custom `__C_specific_handler` personality funciton, which
870+
// forces LLVM to consider landing pads as "landing pads for SEH".
871+
let target = &self.ccx.sess().target.target;
859872
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
860-
Some(def_id) => {
873+
Some(def_id) if !target.options.is_like_msvc => {
861874
callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
862875
pad_bcx.fcx.param_substs).val
863876
}
864-
None => {
877+
_ => {
865878
let mut personality = self.ccx.eh_personality().borrow_mut();
866879
match *personality {
867880
Some(llpersonality) => llpersonality,
868881
None => {
882+
let name = if target.options.is_like_msvc {
883+
"__C_specific_handler"
884+
} else {
885+
"rust_eh_personality"
886+
};
869887
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
870-
let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty,
888+
let f = declare::declare_cfn(self.ccx, name, fty,
871889
self.ccx.tcx().types.i32);
872890
*personality = Some(f);
873891
f

0 commit comments

Comments
 (0)