diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index f3420f9a9f9fd..2d41279147ca6 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1109,7 +1109,8 @@ fn link_args<'a, B: ArchiveBuilder<'a>>( if crate_type == config::CrateType::Executable && sess.target.target.options.is_like_windows { if let Some(ref s) = codegen_results.windows_subsystem { - cmd.subsystem(s); + let version = s.version.as_ref().map(|v| &**v); + cmd.subsystem(&s.name, version); } } diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index a3e60f861996a..bb9dc285c5706 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -111,7 +111,7 @@ pub trait Linker { fn build_static_executable(&mut self); fn args(&mut self, args: &[String]); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); - fn subsystem(&mut self, subsystem: &str); + fn subsystem(&mut self, subsystem: &str, version: Option<&str>); fn group_start(&mut self); fn group_end(&mut self); fn linker_plugin_lto(&mut self); @@ -494,9 +494,13 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg(arg); } - fn subsystem(&mut self, subsystem: &str) { + fn subsystem(&mut self, subsystem: &str, version: Option<&str>) { self.linker_arg("--subsystem"); - self.linker_arg(&subsystem); + if let Some(ver) = version { + self.linker_arg(&format!("{}:{}", subsystem, ver)); + } else { + self.linker_arg(&subsystem); + } } fn finalize(&mut self) -> Command { @@ -724,10 +728,14 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(&arg); } - fn subsystem(&mut self, subsystem: &str) { + fn subsystem(&mut self, subsystem: &str, version: Option<&str>) { // Note that previous passes of the compiler validated this subsystem, // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); + let arg = match version { + Some(ver) => format!("/SUBSYSTEM:{},{}", subsystem, ver), + None => format!("/SUBSYSTEM:{}", subsystem), + }; + self.cmd.arg(&arg); // Windows has two subsystems we're interested in right now, the console // and windows subsystems. These both implicitly have different entry @@ -910,7 +918,7 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg(arg); } - fn subsystem(&mut self, _subsystem: &str) { + fn subsystem(&mut self, _subsystem: &str, _version: Option<&str>) { // noop } @@ -1076,7 +1084,7 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("--export=__data_end"); } - fn subsystem(&mut self, _subsystem: &str) {} + fn subsystem(&mut self, _subsystem: &str, _version: Option<&str>) {} fn no_position_independent_executable(&mut self) {} @@ -1237,7 +1245,7 @@ impl<'a> Linker for PtxLinker<'a> { fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {} - fn subsystem(&mut self, _subsystem: &str) {} + fn subsystem(&mut self, _subsystem: &str, _version: Option<&str>) {} fn no_position_independent_executable(&mut self) {} diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index a5a90980c3a23..433f9cb3cb6b7 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -5,7 +5,7 @@ use super::lto::{self, SerializedModule}; use super::symbol_export::ExportedSymbols; use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, - RLIB_BYTECODE_EXTENSION, + WindowsSubsystem, RLIB_BYTECODE_EXTENSION, }; use crate::traits::*; @@ -339,16 +339,35 @@ pub fn start_async_codegen( let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); let subsystem = attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs, sym::windows_subsystem); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != sym::windows && subsystem != sym::console { - tcx.sess.fatal(&format!( - "invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem - )); + let windows_subsystem = { + let name = subsystem.map(|subsystem| { + if subsystem != sym::windows && subsystem != sym::console { + tcx.sess.fatal(&format!( + "invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem + )); + } + subsystem.to_string() + }); + let t = &sess.target.target; + if t.target_vendor == "xp" && t.target_os == "windows" { + // For Windows XP the subsystem version needs to be set. + let name = name.unwrap_or("console".to_string()); + let version = match t.arch.as_str() { + "x86" => Some("5.01".to_string()), + "x86_64" => Some("5.02".to_string()), + arch => tcx.sess.fatal(&format!( + "invalid Windows XP arch `{}`, only \ + `x86` and `x86_64` are supported", + arch + )), + }; + Some(WindowsSubsystem { name, version }) + } else { + name.and_then(|name| Some(WindowsSubsystem { name, version: None })) } - subsystem.to_string() - }); + }; let linker_info = LinkerInfo::new(tcx); let crate_info = CrateInfo::new(tcx); @@ -1716,7 +1735,7 @@ pub struct OngoingCodegen { pub crate_name: Symbol, pub crate_hash: Svh, pub metadata: EncodedMetadata, - pub windows_subsystem: Option, + pub windows_subsystem: Option, pub linker_info: LinkerInfo, pub crate_info: CrateInfo, pub coordinator_send: Sender>, diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 02385bdab7b19..3321a2a6f239b 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -138,6 +138,12 @@ pub struct CrateInfo { pub dependency_formats: Lrc, } +#[derive(Debug)] +pub struct WindowsSubsystem { + pub name: String, + pub version: Option, +} + pub struct CodegenResults { pub crate_name: Symbol, pub modules: Vec, @@ -145,7 +151,7 @@ pub struct CodegenResults { pub metadata_module: Option, pub crate_hash: Svh, pub metadata: rustc::middle::cstore::EncodedMetadata, - pub windows_subsystem: Option, + pub windows_subsystem: Option, pub linker_info: back::linker::LinkerInfo, pub crate_info: CrateInfo, } diff --git a/src/librustc_target/spec/i686_xp_windows_msvc.rs b/src/librustc_target/spec/i686_xp_windows_msvc.rs new file mode 100644 index 0000000000000..89356abdcdc58 --- /dev/null +++ b/src/librustc_target/spec/i686_xp_windows_msvc.rs @@ -0,0 +1,30 @@ +use crate::spec::{LinkerFlavor, 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://msdn.microsoft.com/en-us/library/9a89h429.aspx + base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string()); + + Ok(Target { + llvm_target: "i686-pc-windows-msvc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32".to_string(), + arch: "x86".to_string(), + target_os: "windows".to_string(), + target_env: "msvc".to_string(), + target_vendor: "xp".to_string(), + linker_flavor: LinkerFlavor::Msvc, + options: base, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index f08634cc770e0..6110659f85c0d 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -454,8 +454,10 @@ supported_targets! { ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc), ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), ("x86_64-uwp-windows-msvc", x86_64_uwp_windows_msvc), + ("x86_64-xp-windows-msvc", x86_64_xp_windows_msvc), ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), + ("i686-xp-windows-msvc", i686_xp_windows_msvc), ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), diff --git a/src/librustc_target/spec/x86_64_xp_windows_msvc.rs b/src/librustc_target/spec/x86_64_xp_windows_msvc.rs new file mode 100644 index 0000000000000..0a8a296df3a61 --- /dev/null +++ b/src/librustc_target/spec/x86_64_xp_windows_msvc.rs @@ -0,0 +1,22 @@ +use crate::spec::{LinkerFlavor, Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::windows_msvc_base::opts(); + base.cpu = "x86-64".to_string(); + base.max_atomic_width = Some(64); + base.has_elf_tls = true; + + Ok(Target { + llvm_target: "x86_64-pc-windows-msvc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "windows".to_string(), + target_env: "msvc".to_string(), + target_vendor: "xp".to_string(), + linker_flavor: LinkerFlavor::Msvc, + options: base, + }) +}