diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 20e64f0c48851..d58d9b91c73ac 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 0baa37ae9f1ab..d8c5ddf586f45 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 3a5957892b59c..ebe901e4f274d 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 9f95a1a6f44fc..8652d1051ad05 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 517368e6a23e9..b7fcda63db00b 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 6363469d92925..340090fd43b7c 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 e26d0ae50b26d..c7062e1ca5196 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 fc252b6d43d26..d2a087ab62f9f 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 046388e9be8f4..4060b126cddb7 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 1ddab7be180e0..3d7ae6c302d9c 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 3f9dad689fd59..b9f94023e7a79 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 650219c21ac40..1f9b195e2e698 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 2091902d7ce21..d12afe5a40bcc 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 ffb66afc76182..9d0922b8ce5a9 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 e299f92fdeb63..221d5f0785cd2 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 93f396de0a051..4e582fb8c63ab 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 b712dcae89970..5caad10161d8e 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 a5d7f8e07c443..52892fc35924e 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 fae44836fa821..4a900d1b02cbf 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 1bc2bf12fad9e..6ff812754aa7d 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, - /// 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 0000000000000..817a322a9e4da --- /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 eb359b920463b..95c4749f9c74c 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 b66c56e1a7aea..cadd14df69352 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 6398fa91f0253..18cafe654d17f 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 98a2a0fbc9cc1..8d3a3563f4164 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 0000000000000..4cf186bdd7c1a --- /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 99ab996be959d..eca095b594289 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 ab0f7791e2cda..21d62d252e09a 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 d09da9478fb2b..0000000000000 --- 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 0000000000000..3f7c78c8e7d47 --- /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 1763c9139b1bf..1b25c51278d4a 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 similarity index 99% rename from src/librustc_target/spec/windows_base.rs rename to src/librustc_target/spec/windows_gnu_base.rs index 097ee09f1ea8c..33ecb1d0d48ce 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 52b166df93996..77171f8672e8a 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 similarity index 60% rename from src/librustc_target/spec/windows_uwp_base.rs rename to src/librustc_target/spec/windows_uwp_gnu_base.rs index f19bd10dc0bbd..dd3b60344be22 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 3d639b6b628b3..04ffa1a0addbe 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 3d3acc682dea4..eb97fa56814d8 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 7660b68aae62e..12edc29330a49 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 48366e24a39e4..ad6002f6b89e4 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);