]> git.lizzy.rs Git - rust.git/commitdiff
rustc_target: Make sure lld-link is treated as link.exe by default
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 10 Apr 2020 23:52:34 +0000 (02:52 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Mon, 13 Apr 2020 15:37:51 +0000 (18:37 +0300)
The differences if they are discovered will need to be explicitly documented

src/librustc_codegen_ssa/back/link.rs
src/librustc_target/spec/i686_pc_windows_msvc.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs
src/librustc_target/spec/uefi_base.rs
src/librustc_target/spec/windows_msvc_base.rs
src/librustc_target/spec/windows_uwp_msvc_base.rs

index 20e64f0c488515c5baec199c38afd8d0e0117a84..5f7a1938a33042ff85b88cdcedb78b43b2e9946b 100644 (file)
@@ -12,7 +12,7 @@
 /// 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) {
index ffb66afc7618270dc74a36a8b15ba499ec7c5adf..9d0922b8ce5a957014bbc3fd02fd666c10a177ff 100644 (file)
@@ -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(),
index 1bc2bf12fad9e39b796186bf2b2568ecc7dd2ce1..a1b997482608525f2cbd1281c57dcd198585dcdb 100644 (file)
@@ -322,6 +322,7 @@ fn $module() {
                     // Target on this testing platform (i.e., checking the iOS targets
                     // only on a Mac test platform).
                     let _ = $module::target().map(|original| {
+                        original.check_consistency();
                         let as_json = original.to_json();
                         let parsed = Target::from_json(as_json).unwrap();
                         assert_eq!(original, parsed);
@@ -538,7 +539,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 +568,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.
@@ -1286,6 +1289,34 @@ fn load_file(path: &Path) -> Result<Target, String> {
             }
         }
     }
+
+    #[cfg(test)]
+    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);
+            }
+        }
+    }
 }
 
 impl ToJson for Target {
index ab0f7791e2cda5c2cd4078351fb52ee6c1a7ab10..21d62d252e09ad2d059d2757bfd30ed45acbdd9f 100644 (file)
@@ -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
index d09da9478fb2b356a834639416ea7a307559df96..030eb12eb0ec533daa1e8af2b3d8b046132cce13 100644 (file)
 use std::default::Default;
 
 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(),
+        // 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(),
+    ];
     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(),
-        ],
-    );
+    pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
+    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
 
     TargetOptions {
         dynamic_linking: false,
index 52b166df93996c55d470ccc24a4b554be4f96266..78567a4382bed5dc4d0705f2d0a695b96f8919db 100644 (file)
@@ -2,10 +2,10 @@
 use std::default::Default;
 
 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 pre_link_args_msvc = vec!["/NOLOGO".to_string(), "/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 {
         function_sections: true,
@@ -24,7 +24,7 @@ pub fn opts() -> TargetOptions {
         // messages if a link error occurred.
         link_env: vec![("VSLANG".to_string(), "1033".to_string())],
         lld_flavor: LldFlavor::Link,
-        pre_link_args: args,
+        pre_link_args,
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
         abi_return_struct_as_int: true,
index 3d639b6b628b3c208745b639426eac2898e4be66..9497e525dd97c64a526ae2a0b62ae36ebc19fbda 100644 (file)
@@ -1,17 +1,16 @@
-use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
 use std::default::Default;
 
 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 pre_link_args_msvc = vec![
+        "/NOLOGO".to_string(),
+        "/NXCOMPAT".to_string(),
+        "/APPCONTAINER".to_string(),
+        "mincore.lib".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 {
         function_sections: true,
@@ -25,12 +24,13 @@ pub fn opts() -> TargetOptions {
         target_family: Some("windows".to_string()),
         is_like_windows: true,
         is_like_msvc: true,
-        pre_link_args: args,
+        pre_link_args,
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
         requires_uwtable: true,
+        lld_flavor: LldFlavor::Link,
 
         ..Default::default()
     }