about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-04-15 09:10:02 +0200
committerGitHub <noreply@github.com>2020-04-15 09:10:02 +0200
commitffafd1528094cc9355e751d4b0595a89a11a9a8e (patch)
tree449efb380fe5fc1bd494da17254789e220559ea5
parent629e51b7619c99e5810d399146110556a051597a (diff)
parent8392e477e73c12566803411396b0ff18a0864c81 (diff)
downloadrust-ffafd1528094cc9355e751d4b0595a89a11a9a8e.tar.gz
rust-ffafd1528094cc9355e751d4b0595a89a11a9a8e.zip
Rollup merge of #71030 - petrochenkov:linkorder2, r=nagisa
rustc_target: Refactor target specifications related to Windows and UEFI

- LLD support is improved.
- Code is cleaned up.
- Target specs are organized in a more hierarchical way.
- Possible issues in UWP and UEFI platforms are identified (see FIXMEs).

The code is better read per-commit.
-rw-r--r--src/librustc_codegen_ssa/back/link.rs15
-rw-r--r--src/librustc_codegen_ssa/back/linker.rs10
-rw-r--r--src/librustc_target/spec/armebv7r_none_eabi.rs1
-rw-r--r--src/librustc_target/spec/armebv7r_none_eabihf.rs1
-rw-r--r--src/librustc_target/spec/armv7r_none_eabi.rs1
-rw-r--r--src/librustc_target/spec/armv7r_none_eabihf.rs1
-rw-r--r--src/librustc_target/spec/dragonfly_base.rs1
-rw-r--r--src/librustc_target/spec/freebsd_base.rs1
-rw-r--r--src/librustc_target/spec/fuchsia_base.rs1
-rw-r--r--src/librustc_target/spec/haiku_base.rs1
-rw-r--r--src/librustc_target/spec/hermit_base.rs1
-rw-r--r--src/librustc_target/spec/hermit_kernel_base.rs1
-rw-r--r--src/librustc_target/spec/i686_pc_windows_gnu.rs2
-rw-r--r--src/librustc_target/spec/i686_pc_windows_msvc.rs24
-rw-r--r--src/librustc_target/spec/i686_unknown_uefi.rs7
-rw-r--r--src/librustc_target/spec/i686_uwp_windows_gnu.rs2
-rw-r--r--src/librustc_target/spec/l4re_base.rs1
-rw-r--r--src/librustc_target/spec/linux_base.rs1
-rw-r--r--src/librustc_target/spec/linux_kernel_base.rs1
-rw-r--r--src/librustc_target/spec/mod.rs33
-rw-r--r--src/librustc_target/spec/msvc_base.rs35
-rw-r--r--src/librustc_target/spec/netbsd_base.rs1
-rw-r--r--src/librustc_target/spec/openbsd_base.rs1
-rw-r--r--src/librustc_target/spec/redox_base.rs1
-rw-r--r--src/librustc_target/spec/solaris_base.rs1
-rw-r--r--src/librustc_target/spec/tests/tests_impl.rs43
-rw-r--r--src/librustc_target/spec/thumb_base.rs1
-rw-r--r--src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs9
-rw-r--r--src/librustc_target/spec/uefi_base.rs67
-rw-r--r--src/librustc_target/spec/uefi_msvc_base.rs58
-rw-r--r--src/librustc_target/spec/vxworks_base.rs1
-rw-r--r--src/librustc_target/spec/windows_gnu_base.rs (renamed from src/librustc_target/spec/windows_base.rs)1
-rw-r--r--src/librustc_target/spec/windows_msvc_base.rs32
-rw-r--r--src/librustc_target/spec/windows_uwp_gnu_base.rs (renamed from src/librustc_target/spec/windows_uwp_base.rs)35
-rw-r--r--src/librustc_target/spec/windows_uwp_msvc_base.rs41
-rw-r--r--src/librustc_target/spec/x86_64_pc_windows_gnu.rs2
-rw-r--r--src/librustc_target/spec/x86_64_unknown_uefi.rs7
-rw-r--r--src/librustc_target/spec/x86_64_uwp_windows_gnu.rs2
38 files changed, 219 insertions, 225 deletions
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 20e64f0c488..d58d9b91c73 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -12,7 +12,7 @@ use rustc_session::search_paths::PathKind;
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
+use rustc_target::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelroLevel};
 
 use super::archive::ArchiveBuilder;
 use super::command::Command;
@@ -182,7 +182,9 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
     // To comply with the Windows App Certification Kit,
     // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
     let t = &sess.target.target;
-    if flavor == LinkerFlavor::Msvc && t.target_vendor == "uwp" {
+    if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
+        && t.target_vendor == "uwp"
+    {
         if let Some(ref tool) = msvc_tool {
             let original_path = tool.path();
             if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
@@ -1530,13 +1532,8 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     cmd.debuginfo();
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    // We want to, by default, prevent the compiler from accidentally leaking in
-    // any system libraries, so we may explicitly ask linkers to not link to any
-    // libraries by default. Note that this does not happen for windows because
-    // windows pulls in some large number of libraries and I couldn't quite
-    // figure out which subset we wanted.
-    //
-    // This is all naturally configurable via the standard methods as well.
+    // We want to prevent the compiler from accidentally leaking in any system libraries,
+    // so by default we tell linkers not to link to any default libraries.
     if !sess.opts.cg.default_linker_libraries.unwrap_or(false)
         && sess.target.target.options.no_default_libraries
     {
diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs
index 0baa37ae9f1..d8c5ddf586f 100644
--- a/src/librustc_codegen_ssa/back/linker.rs
+++ b/src/librustc_codegen_ssa/back/linker.rs
@@ -631,15 +631,7 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn no_default_libraries(&mut self) {
-        // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
-        // as there's been trouble in the past of linking the C++ standard
-        // library required by LLVM. This likely needs to happen one day, but
-        // in general Windows is also a more controlled environment than
-        // Unix, so it's not necessarily as critical that this be implemented.
-        //
-        // Note that there are also some licensing worries about statically
-        // linking some libraries which require a specific agreement, so it may
-        // not ever be possible for us to pass this flag.
+        self.cmd.arg("/NODEFAULTLIB");
     }
 
     fn include_path(&mut self, path: &Path) {
diff --git a/src/librustc_target/spec/armebv7r_none_eabi.rs b/src/librustc_target/spec/armebv7r_none_eabi.rs
index 3a5957892b5..ebe901e4f27 100644
--- a/src/librustc_target/spec/armebv7r_none_eabi.rs
+++ b/src/librustc_target/spec/armebv7r_none_eabi.rs
@@ -1,7 +1,6 @@
 // Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
-use std::default::Default;
 
 pub fn target() -> TargetResult {
     Ok(Target {
diff --git a/src/librustc_target/spec/armebv7r_none_eabihf.rs b/src/librustc_target/spec/armebv7r_none_eabihf.rs
index 9f95a1a6f44..8652d1051ad 100644
--- a/src/librustc_target/spec/armebv7r_none_eabihf.rs
+++ b/src/librustc_target/spec/armebv7r_none_eabihf.rs
@@ -1,7 +1,6 @@
 // Targets the Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
-use std::default::Default;
 
 pub fn target() -> TargetResult {
     Ok(Target {
diff --git a/src/librustc_target/spec/armv7r_none_eabi.rs b/src/librustc_target/spec/armv7r_none_eabi.rs
index 517368e6a23..b7fcda63db0 100644
--- a/src/librustc_target/spec/armv7r_none_eabi.rs
+++ b/src/librustc_target/spec/armv7r_none_eabi.rs
@@ -1,7 +1,6 @@
 // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
-use std::default::Default;
 
 pub fn target() -> TargetResult {
     Ok(Target {
diff --git a/src/librustc_target/spec/armv7r_none_eabihf.rs b/src/librustc_target/spec/armv7r_none_eabihf.rs
index 6363469d929..340090fd43b 100644
--- a/src/librustc_target/spec/armv7r_none_eabihf.rs
+++ b/src/librustc_target/spec/armv7r_none_eabihf.rs
@@ -1,7 +1,6 @@
 // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
-use std::default::Default;
 
 pub fn target() -> TargetResult {
     Ok(Target {
diff --git a/src/librustc_target/spec/dragonfly_base.rs b/src/librustc_target/spec/dragonfly_base.rs
index e26d0ae50b2..c7062e1ca51 100644
--- a/src/librustc_target/spec/dragonfly_base.rs
+++ b/src/librustc_target/spec/dragonfly_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/freebsd_base.rs b/src/librustc_target/spec/freebsd_base.rs
index fc252b6d43d..d2a087ab62f 100644
--- a/src/librustc_target/spec/freebsd_base.rs
+++ b/src/librustc_target/spec/freebsd_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs
index 046388e9be8..4060b126cdd 100644
--- a/src/librustc_target/spec/fuchsia_base.rs
+++ b/src/librustc_target/spec/fuchsia_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
diff --git a/src/librustc_target/spec/haiku_base.rs b/src/librustc_target/spec/haiku_base.rs
index 1ddab7be180..3d7ae6c302d 100644
--- a/src/librustc_target/spec/haiku_base.rs
+++ b/src/librustc_target/spec/haiku_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs
index 3f9dad689fd..b9f94023e7a 100644
--- a/src/librustc_target/spec/hermit_base.rs
+++ b/src/librustc_target/spec/hermit_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/src/librustc_target/spec/hermit_kernel_base.rs
index 650219c21ac..1f9b195e2e6 100644
--- a/src/librustc_target/spec/hermit_kernel_base.rs
+++ b/src/librustc_target/spec/hermit_kernel_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
diff --git a/src/librustc_target/spec/i686_pc_windows_gnu.rs b/src/librustc_target/spec/i686_pc_windows_gnu.rs
index 2091902d7ce..d12afe5a40b 100644
--- a/src/librustc_target/spec/i686_pc_windows_gnu.rs
+++ b/src/librustc_target/spec/i686_pc_windows_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::windows_base::opts();
+    let mut base = super::windows_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.eliminate_frame_pointer = false; // Required for backtraces
diff --git a/src/librustc_target/spec/i686_pc_windows_msvc.rs b/src/librustc_target/spec/i686_pc_windows_msvc.rs
index ffb66afc761..9d0922b8ce5 100644
--- a/src/librustc_target/spec/i686_pc_windows_msvc.rs
+++ b/src/librustc_target/spec/i686_pc_windows_msvc.rs
@@ -1,18 +1,24 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
 
-    // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
-    // space available to x86 Windows binaries on x86_64.
-    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string());
-
-    // Ensure the linker will only produce an image if it can also produce a table of
-    // the image's safe exception handlers.
-    // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers
-    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string());
+    let pre_link_args_msvc = vec![
+        // Mark all dynamic libraries and executables as compatible with the larger 4GiB address
+        // space available to x86 Windows binaries on x86_64.
+        "/LARGEADDRESSAWARE".to_string(),
+        // Ensure the linker will only produce an image if it can also produce a table of
+        // the image's safe exception handlers.
+        // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers
+        "/SAFESEH".to_string(),
+    ];
+    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
+        .unwrap()
+        .extend(pre_link_args_msvc);
 
     Ok(Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
diff --git a/src/librustc_target/spec/i686_unknown_uefi.rs b/src/librustc_target/spec/i686_unknown_uefi.rs
index e299f92fdeb..221d5f0785c 100644
--- a/src/librustc_target/spec/i686_unknown_uefi.rs
+++ b/src/librustc_target/spec/i686_unknown_uefi.rs
@@ -8,7 +8,7 @@
 use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::uefi_base::opts();
+    let mut base = super::uefi_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
 
@@ -23,11 +23,6 @@ pub fn target() -> TargetResult {
     // arguments, thus giving you access to full MMX/SSE acceleration.
     base.features = "-mmx,-sse,+soft-float".to_string();
 
-    // UEFI mirrors the calling-conventions used on windows. In case of i686 this means small
-    // structs will be returned as int. This shouldn't matter much, since the restrictions placed
-    // by the UEFI specifications forbid any ABI to return structures.
-    base.abi_return_struct_as_int = true;
-
     // Use -GNU here, because of the reason below:
     // Background and Problem:
     //   If we use i686-unknown-windows, the LLVM IA32 MSVC generates compiler intrinsic
diff --git a/src/librustc_target/spec/i686_uwp_windows_gnu.rs b/src/librustc_target/spec/i686_uwp_windows_gnu.rs
index 93f396de0a0..4e582fb8c63 100644
--- a/src/librustc_target/spec/i686_uwp_windows_gnu.rs
+++ b/src/librustc_target/spec/i686_uwp_windows_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::windows_uwp_base::opts();
+    let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.eliminate_frame_pointer = false; // Required for backtraces
diff --git a/src/librustc_target/spec/l4re_base.rs b/src/librustc_target/spec/l4re_base.rs
index b712dcae899..5caad10161d 100644
--- a/src/librustc_target/spec/l4re_base.rs
+++ b/src/librustc_target/spec/l4re_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
-use std::default::Default;
 //use std::process::Command;
 
 // Use GCC to locate code for crt* libraries from the host, not from L4Re. Note
diff --git a/src/librustc_target/spec/linux_base.rs b/src/librustc_target/spec/linux_base.rs
index a5d7f8e07c4..52892fc3592 100644
--- a/src/librustc_target/spec/linux_base.rs
+++ b/src/librustc_target/spec/linux_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/src/librustc_target/spec/linux_kernel_base.rs
index fae44836fa8..4a900d1b02c 100644
--- a/src/librustc_target/spec/linux_kernel_base.rs
+++ b/src/librustc_target/spec/linux_kernel_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 1bc2bf12fad..6ff812754aa 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -37,7 +37,6 @@
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use rustc_serialize::json::{Json, ToJson};
 use std::collections::BTreeMap;
-use std::default::Default;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
@@ -60,18 +59,19 @@ mod l4re_base;
 mod linux_base;
 mod linux_kernel_base;
 mod linux_musl_base;
+mod msvc_base;
 mod netbsd_base;
 mod openbsd_base;
 mod redox_base;
 mod riscv_base;
 mod solaris_base;
 mod thumb_base;
-mod uefi_base;
+mod uefi_msvc_base;
 mod vxworks_base;
 mod wasm32_base;
-mod windows_base;
+mod windows_gnu_base;
 mod windows_msvc_base;
-mod windows_uwp_base;
+mod windows_uwp_gnu_base;
 mod windows_uwp_msvc_base;
 
 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -309,23 +309,14 @@ macro_rules! supported_targets {
         }
 
         #[cfg(test)]
-        mod test_json_encode_decode {
-            use rustc_serialize::json::ToJson;
-            use super::Target;
-            $(use super::$module;)+
+        mod tests {
+            mod tests_impl;
 
+            // Cannot put this into a separate file without duplication, make an exception.
             $(
-                #[test] // `#[test]` - this is hard to put into a separate file, make an exception
+                #[test] // `#[test]`
                 fn $module() {
-                    // Grab the TargetResult struct. If we successfully retrieved
-                    // a Target, then the test JSON encoding/decoding can run for this
-                    // Target on this testing platform (i.e., checking the iOS targets
-                    // only on a Mac test platform).
-                    let _ = $module::target().map(|original| {
-                        let as_json = original.to_json();
-                        let parsed = Target::from_json(as_json).unwrap();
-                        assert_eq!(original, parsed);
-                    });
+                    tests_impl::test_target(super::$module::target());
                 }
             )+
         }
@@ -538,7 +529,8 @@ pub struct Target {
     pub arch: String,
     /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
     pub data_layout: String,
-    /// Linker flavor
+    /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
+    /// on the command line.
     pub linker_flavor: LinkerFlavor,
     /// Optional settings with defaults.
     pub options: TargetOptions,
@@ -566,7 +558,8 @@ pub struct TargetOptions {
     /// Linker to invoke
     pub linker: Option<String>,
 
-    /// LLD flavor
+    /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
+    /// without clarifying its flavor in any way.
     pub lld_flavor: LldFlavor,
 
     /// Linker arguments that are passed *before* any user-defined libraries.
diff --git a/src/librustc_target/spec/msvc_base.rs b/src/librustc_target/spec/msvc_base.rs
new file mode 100644
index 00000000000..817a322a9e4
--- /dev/null
+++ b/src/librustc_target/spec/msvc_base.rs
@@ -0,0 +1,35 @@
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    let pre_link_args_msvc = vec![
+        // Suppress the verbose logo and authorship debugging output, which would needlessly
+        // clog any log files.
+        "/NOLOGO".to_string(),
+        // Tell the compiler that non-code sections can be marked as non-executable,
+        // including stack pages.
+        // UEFI is fully compatible to non-executable data pages.
+        // In fact, firmware might enforce this, so we better let the linker know about this,
+        // so it will fail if the compiler ever tries placing code on the stack
+        // (e.g., trampoline constructs and alike).
+        "/NXCOMPAT".to_string(),
+    ];
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
+    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
+
+    TargetOptions {
+        executables: true,
+        is_like_windows: true,
+        is_like_msvc: true,
+        // set VSLANG to 1033 can prevent link.exe from using
+        // language packs, and avoid generating Non-UTF-8 error
+        // messages if a link error occurred.
+        link_env: vec![("VSLANG".to_string(), "1033".to_string())],
+        lld_flavor: LldFlavor::Link,
+        pre_link_args,
+        abi_return_struct_as_int: true,
+        emit_debug_gdb_scripts: false,
+
+        ..Default::default()
+    }
+}
diff --git a/src/librustc_target/spec/netbsd_base.rs b/src/librustc_target/spec/netbsd_base.rs
index eb359b92046..95c4749f9c7 100644
--- a/src/librustc_target/spec/netbsd_base.rs
+++ b/src/librustc_target/spec/netbsd_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/openbsd_base.rs b/src/librustc_target/spec/openbsd_base.rs
index b66c56e1a7a..cadd14df693 100644
--- a/src/librustc_target/spec/openbsd_base.rs
+++ b/src/librustc_target/spec/openbsd_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/redox_base.rs b/src/librustc_target/spec/redox_base.rs
index 6398fa91f02..18cafe654d1 100644
--- a/src/librustc_target/spec/redox_base.rs
+++ b/src/librustc_target/spec/redox_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args = LinkArgs::new();
diff --git a/src/librustc_target/spec/solaris_base.rs b/src/librustc_target/spec/solaris_base.rs
index 98a2a0fbc9c..8d3a3563f41 100644
--- a/src/librustc_target/spec/solaris_base.rs
+++ b/src/librustc_target/spec/solaris_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::TargetOptions;
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
diff --git a/src/librustc_target/spec/tests/tests_impl.rs b/src/librustc_target/spec/tests/tests_impl.rs
new file mode 100644
index 00000000000..4cf186bdd7c
--- /dev/null
+++ b/src/librustc_target/spec/tests/tests_impl.rs
@@ -0,0 +1,43 @@
+use super::super::*;
+
+pub(super) fn test_target(target: TargetResult) {
+    // Grab the TargetResult struct. If we successfully retrieved
+    // a Target, then the test JSON encoding/decoding can run for this
+    // Target on this testing platform (i.e., checking the iOS targets
+    // only on a Mac test platform).
+    if let Ok(original) = target {
+        original.check_consistency();
+        let as_json = original.to_json();
+        let parsed = Target::from_json(as_json).unwrap();
+        assert_eq!(original, parsed);
+    }
+}
+
+impl Target {
+    fn check_consistency(&self) {
+        // Check that LLD with the given flavor is treated identically to the linker it emulates.
+        // If you target really needs to deviate from the rules below, whitelist it
+        // and document the reasons.
+        assert_eq!(
+            self.linker_flavor == LinkerFlavor::Msvc
+                || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link),
+            self.options.lld_flavor == LldFlavor::Link,
+        );
+        for args in &[
+            &self.options.pre_link_args,
+            &self.options.pre_link_args_crt,
+            &self.options.late_link_args,
+            &self.options.late_link_args_dynamic,
+            &self.options.late_link_args_static,
+            &self.options.post_link_args,
+        ] {
+            assert_eq!(
+                args.get(&LinkerFlavor::Msvc),
+                args.get(&LinkerFlavor::Lld(LldFlavor::Link)),
+            );
+            if args.contains_key(&LinkerFlavor::Msvc) {
+                assert_eq!(self.options.lld_flavor, LldFlavor::Link);
+            }
+        }
+    }
+}
diff --git a/src/librustc_target/spec/thumb_base.rs b/src/librustc_target/spec/thumb_base.rs
index 99ab996be95..eca095b5942 100644
--- a/src/librustc_target/spec/thumb_base.rs
+++ b/src/librustc_target/spec/thumb_base.rs
@@ -28,7 +28,6 @@
 // build scripts / gcc flags.
 
 use crate::spec::{PanicStrategy, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
diff --git a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs b/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs
index ab0f7791e2c..21d62d252e0 100644
--- a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs
+++ b/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::windows_msvc_base::opts();
@@ -10,7 +10,12 @@ pub fn target() -> TargetResult {
     // should be smart enough to insert branch islands only
     // where necessary, but this is not the observed behavior.
     // Disabling the LBR optimization works around the issue.
-    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/OPT:NOLBR".to_string());
+    let pre_link_args_msvc = "/OPT:NOLBR".to_string();
+    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(pre_link_args_msvc.clone());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
+        .unwrap()
+        .push(pre_link_args_msvc);
 
     // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
     // implemented for windows/arm in LLVM
diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs
deleted file mode 100644
index d09da9478fb..00000000000
--- a/src/librustc_target/spec/uefi_base.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// This defines a base target-configuration for native UEFI systems. The UEFI specification has
-// quite detailed sections on the ABI of all the supported target architectures. In almost all
-// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
-// documentation.
-// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
-// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
-// by the loader if the pre-chosen memory location is already in use.
-// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
-// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
-// code runs in the same environment, no process separation is supported.
-
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
-use std::default::Default;
-
-pub fn opts() -> TargetOptions {
-    let mut pre_link_args = LinkArgs::new();
-
-    pre_link_args.insert(
-        LinkerFlavor::Lld(LldFlavor::Link),
-        vec![
-            // Suppress the verbose logo and authorship debugging output, which would needlessly
-            // clog any log files.
-            "/NOLOGO".to_string(),
-            // UEFI is fully compatible to non-executable data pages. Tell the compiler that
-            // non-code sections can be marked as non-executable, including stack pages. In fact,
-            // firmware might enforce this, so we better let the linker know about this, so it
-            // will fail if the compiler ever tries placing code on the stack (e.g., trampoline
-            // constructs and alike).
-            "/NXCOMPAT".to_string(),
-            // There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
-            // must be freestanding.
-            "/nodefaultlib".to_string(),
-            // Non-standard subsystems have no default entry-point in PE+ files. We have to define
-            // one. "efi_main" seems to be a common choice amongst other implementations and the
-            // spec.
-            "/entry:efi_main".to_string(),
-            // COFF images have a "Subsystem" field in their header, which defines what kind of
-            // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
-            // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
-            // which is very likely the most common option. Individual projects can override this
-            // with custom linker flags.
-            // The subsystem-type only has minor effects on the application. It defines the memory
-            // regions the application is loaded into (runtime-drivers need to be put into
-            // reserved areas), as well as whether a return from the entry-point is treated as
-            // exit (default for applications).
-            "/subsystem:efi_application".to_string(),
-        ],
-    );
-
-    TargetOptions {
-        dynamic_linking: false,
-        executables: true,
-        disable_redzone: true,
-        exe_suffix: ".efi".to_string(),
-        allows_weak_linkage: false,
-        panic_strategy: PanicStrategy::Abort,
-        stack_probes: true,
-        singlethread: true,
-        emit_debug_gdb_scripts: false,
-
-        linker: Some("rust-lld".to_string()),
-        lld_flavor: LldFlavor::Link,
-        pre_link_args,
-
-        ..Default::default()
-    }
-}
diff --git a/src/librustc_target/spec/uefi_msvc_base.rs b/src/librustc_target/spec/uefi_msvc_base.rs
new file mode 100644
index 00000000000..3f7c78c8e7d
--- /dev/null
+++ b/src/librustc_target/spec/uefi_msvc_base.rs
@@ -0,0 +1,58 @@
+// This defines a base target-configuration for native UEFI systems. The UEFI specification has
+// quite detailed sections on the ABI of all the supported target architectures. In almost all
+// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
+// documentation.
+// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
+// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
+// by the loader if the pre-chosen memory location is already in use.
+// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
+// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
+// code runs in the same environment, no process separation is supported.
+
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
+
+pub fn opts() -> TargetOptions {
+    let mut base = super::msvc_base::opts();
+
+    let pre_link_args_msvc = vec![
+        // Non-standard subsystems have no default entry-point in PE+ files. We have to define
+        // one. "efi_main" seems to be a common choice amongst other implementations and the
+        // spec.
+        "/entry:efi_main".to_string(),
+        // COFF images have a "Subsystem" field in their header, which defines what kind of
+        // program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
+        // EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
+        // which is very likely the most common option. Individual projects can override this
+        // with custom linker flags.
+        // The subsystem-type only has minor effects on the application. It defines the memory
+        // regions the application is loaded into (runtime-drivers need to be put into
+        // reserved areas), as well as whether a return from the entry-point is treated as
+        // exit (default for applications).
+        "/subsystem:efi_application".to_string(),
+    ];
+    base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
+    base.pre_link_args
+        .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
+        .unwrap()
+        .extend(pre_link_args_msvc);
+
+    TargetOptions {
+        disable_redzone: true,
+        exe_suffix: ".efi".to_string(),
+        allows_weak_linkage: false,
+        panic_strategy: PanicStrategy::Abort,
+        stack_probes: true,
+        singlethread: true,
+        linker: Some("rust-lld".to_string()),
+        // FIXME: This should likely be `true` inherited from `msvc_base`
+        // because UEFI follows Windows ABI and uses PE/COFF.
+        // The `false` is probably causing ABI bugs right now.
+        is_like_windows: false,
+        // FIXME: This should likely be `true` inherited from `msvc_base`
+        // because UEFI follows Windows ABI and uses PE/COFF.
+        // The `false` is probably causing ABI bugs right now.
+        is_like_msvc: false,
+
+        ..base
+    }
+}
diff --git a/src/librustc_target/spec/vxworks_base.rs b/src/librustc_target/spec/vxworks_base.rs
index 1763c9139b1..1b25c51278d 100644
--- a/src/librustc_target/spec/vxworks_base.rs
+++ b/src/librustc_target/spec/vxworks_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut args_crt = LinkArgs::new();
diff --git a/src/librustc_target/spec/windows_base.rs b/src/librustc_target/spec/windows_gnu_base.rs
index 097ee09f1ea..33ecb1d0d48 100644
--- a/src/librustc_target/spec/windows_base.rs
+++ b/src/librustc_target/spec/windows_gnu_base.rs
@@ -1,5 +1,4 @@
 use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     let mut pre_link_args = LinkArgs::new();
diff --git a/src/librustc_target/spec/windows_msvc_base.rs b/src/librustc_target/spec/windows_msvc_base.rs
index 52b166df939..77171f8672e 100644
--- a/src/librustc_target/spec/windows_msvc_base.rs
+++ b/src/librustc_target/spec/windows_msvc_base.rs
@@ -1,36 +1,30 @@
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
-use std::default::Default;
+use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
-    let pre_args = vec!["/NOLOGO".to_string(), "/NXCOMPAT".to_string()];
-    let mut args = LinkArgs::new();
-    args.insert(LinkerFlavor::Msvc, pre_args.clone());
-    args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_args);
+    let base = super::msvc_base::opts();
 
     TargetOptions {
-        function_sections: true,
         dynamic_linking: true,
-        executables: true,
         dll_prefix: String::new(),
         dll_suffix: ".dll".to_string(),
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: String::new(),
         staticlib_suffix: ".lib".to_string(),
         target_family: Some("windows".to_string()),
-        is_like_windows: true,
-        is_like_msvc: true,
-        // set VSLANG to 1033 can prevent link.exe from using
-        // language packs, and avoid generating Non-UTF-8 error
-        // messages if a link error occurred.
-        link_env: vec![("VSLANG".to_string(), "1033".to_string())],
-        lld_flavor: LldFlavor::Link,
-        pre_link_args: args,
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
-        abi_return_struct_as_int: true,
-        emit_debug_gdb_scripts: false,
         requires_uwtable: true,
+        // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
+        // as there's been trouble in the past of linking the C++ standard
+        // library required by LLVM. This likely needs to happen one day, but
+        // in general Windows is also a more controlled environment than
+        // Unix, so it's not necessarily as critical that this be implemented.
+        //
+        // Note that there are also some licensing worries about statically
+        // linking some libraries which require a specific agreement, so it may
+        // not ever be possible for us to pass this flag.
+        no_default_libraries: false,
 
-        ..Default::default()
+        ..base
     }
 }
diff --git a/src/librustc_target/spec/windows_uwp_base.rs b/src/librustc_target/spec/windows_uwp_gnu_base.rs
index f19bd10dc0b..dd3b60344be 100644
--- a/src/librustc_target/spec/windows_uwp_base.rs
+++ b/src/librustc_target/spec/windows_uwp_gnu_base.rs
@@ -1,7 +1,9 @@
 use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
-use std::default::Default;
 
 pub fn opts() -> TargetOptions {
+    let base = super::windows_gnu_base::opts();
+
+    // FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
     let mut pre_link_args = LinkArgs::new();
     pre_link_args.insert(
         LinkerFlavor::Gcc,
@@ -14,7 +16,10 @@ pub fn opts() -> TargetOptions {
         ],
     );
 
+    // FIXME: This should be updated for the exception machinery changes from #67502.
     let mut late_link_args = LinkArgs::new();
+    let late_link_args_dynamic = LinkArgs::new();
+    let late_link_args_static = LinkArgs::new();
     late_link_args.insert(
         LinkerFlavor::Gcc,
         vec![
@@ -33,31 +38,17 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        // FIXME(#13846) this should be enabled for windows
-        function_sections: false,
-        linker: Some("gcc".to_string()),
-        dynamic_linking: true,
         executables: false,
-        dll_prefix: String::new(),
-        dll_suffix: ".dll".to_string(),
-        exe_suffix: ".exe".to_string(),
-        staticlib_prefix: "lib".to_string(),
-        staticlib_suffix: ".a".to_string(),
-        target_family: Some("windows".to_string()),
-        is_like_windows: true,
-        allows_weak_linkage: false,
+        limit_rdylib_exports: false,
         pre_link_args,
-        pre_link_objects_exe: vec![
-            "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
-        ],
+        // FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
+        pre_link_objects_exe: vec!["rsbegin.o".to_string()],
+        // FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
         pre_link_objects_dll: vec!["rsbegin.o".to_string()],
         late_link_args,
-        post_link_objects: vec!["rsend.o".to_string()],
-        abi_return_struct_as_int: true,
-        emit_debug_gdb_scripts: false,
-        requires_uwtable: true,
-        limit_rdylib_exports: false,
+        late_link_args_dynamic,
+        late_link_args_static,
 
-        ..Default::default()
+        ..base
     }
 }
diff --git a/src/librustc_target/spec/windows_uwp_msvc_base.rs b/src/librustc_target/spec/windows_uwp_msvc_base.rs
index 3d639b6b628..04ffa1a0add 100644
--- a/src/librustc_target/spec/windows_uwp_msvc_base.rs
+++ b/src/librustc_target/spec/windows_uwp_msvc_base.rs
@@ -1,37 +1,14 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
-use std::default::Default;
+use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
-    let mut args = LinkArgs::new();
-    args.insert(
-        LinkerFlavor::Msvc,
-        vec![
-            "/NOLOGO".to_string(),
-            "/NXCOMPAT".to_string(),
-            "/APPCONTAINER".to_string(),
-            "mincore.lib".to_string(),
-        ],
-    );
+    let mut opts = super::windows_msvc_base::opts();
 
-    TargetOptions {
-        function_sections: true,
-        dynamic_linking: true,
-        executables: true,
-        dll_prefix: String::new(),
-        dll_suffix: ".dll".to_string(),
-        exe_suffix: ".exe".to_string(),
-        staticlib_prefix: String::new(),
-        staticlib_suffix: ".lib".to_string(),
-        target_family: Some("windows".to_string()),
-        is_like_windows: true,
-        is_like_msvc: true,
-        pre_link_args: args,
-        crt_static_allows_dylibs: true,
-        crt_static_respected: true,
-        abi_return_struct_as_int: true,
-        emit_debug_gdb_scripts: false,
-        requires_uwtable: true,
+    let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()];
+    opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
+    opts.pre_link_args
+        .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
+        .unwrap()
+        .extend(pre_link_args_msvc);
 
-        ..Default::default()
-    }
+    opts
 }
diff --git a/src/librustc_target/spec/x86_64_pc_windows_gnu.rs b/src/librustc_target/spec/x86_64_pc_windows_gnu.rs
index 3d3acc682de..eb97fa56814 100644
--- a/src/librustc_target/spec/x86_64_pc_windows_gnu.rs
+++ b/src/librustc_target/spec/x86_64_pc_windows_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::windows_base::opts();
+    let mut base = super::windows_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/src/librustc_target/spec/x86_64_unknown_uefi.rs
index 7660b68aae6..12edc29330a 100644
--- a/src/librustc_target/spec/x86_64_unknown_uefi.rs
+++ b/src/librustc_target/spec/x86_64_unknown_uefi.rs
@@ -8,7 +8,7 @@
 use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::uefi_base::opts();
+    let mut base = super::uefi_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
@@ -28,11 +28,6 @@ pub fn target() -> TargetResult {
     // places no locality-restrictions, so it fits well here.
     base.code_model = Some("large".to_string());
 
-    // UEFI mirrors the calling-conventions used on windows. In case of x86-64 this means small
-    // structs will be returned as int. This shouldn't matter much, since the restrictions placed
-    // by the UEFI specifications forbid any ABI to return structures.
-    base.abi_return_struct_as_int = true;
-
     Ok(Target {
         llvm_target: "x86_64-unknown-windows".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs b/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs
index 48366e24a39..ad6002f6b89 100644
--- a/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs
+++ b/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
-    let mut base = super::windows_uwp_base::opts();
+    let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);