From 456f65ec8b7ec815cab39929b31f4b6e181651c2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 17 Jun 2022 23:53:00 +0300 Subject: [PATCH] rustc_target: Some more tests and fixes for linker arguments --- compiler/rustc_target/src/lib.rs | 1 + .../src/spec/i686_pc_windows_gnu.rs | 2 +- .../src/spec/i686_uwp_windows_gnu.rs | 2 +- .../rustc_target/src/spec/tests/tests_impl.rs | 97 ++++++++++++++++--- .../src/spec/wasm32_unknown_emscripten.rs | 21 ++-- .../src/spec/wasm32_unknown_unknown.rs | 21 ++-- .../src/spec/wasm64_unknown_unknown.rs | 13 ++- .../rustc_target/src/spec/windows_gnu_base.rs | 14 ++- .../src/spec/windows_uwp_gnu_base.rs | 1 + .../src/spec/x86_64_pc_windows_gnu.rs | 2 +- .../src/spec/x86_64_uwp_windows_gnu.rs | 2 +- 11 files changed, 132 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index a8ddcc9bfac64..59dbea7053447 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -8,6 +8,7 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] #![feature(let_else)] diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs index 75b6d15cdcf88..6318654399c47 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -3,13 +3,13 @@ use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "pentium4".into(); - base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe"]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces base.linker = Some("i686-w64-mingw32-gcc".into()); // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs index 8ee83b19d9c9e..d52810d2fb08b 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -3,12 +3,12 @@ use crate::spec::{FramePointer, LinkerFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "pentium4".into(); - base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe"]); base.max_atomic_width = Some(64); base.frame_pointer = FramePointer::Always; // Required for backtraces // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pe", "--large-address-aware"]); base.add_pre_link_args(LinkerFlavor::Gcc, &["-Wl,--large-address-aware"]); Target { diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 0865ca7ea7df0..c7c5a23190102 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -1,4 +1,5 @@ use super::super::*; +use std::assert_matches::assert_matches; // Test target self-consistency and JSON encoding/decoding roundtrip. pub(super) fn test_target(target: Target) { @@ -14,35 +15,105 @@ impl Target { assert_eq!(self.is_like_wasm, self.arch == "wasm32" || self.arch == "wasm64"); assert!(self.is_like_windows || !self.is_like_msvc); - // Check that LLD with the given flavor is treated identically to the linker it emulates. - // If your target really needs to deviate from the rules below, except it and document the - // reasons. - assert_eq!( - self.linker_flavor == LinkerFlavor::Msvc - || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link), - self.lld_flavor == LldFlavor::Link, - ); - assert_eq!(self.is_like_msvc, self.lld_flavor == LldFlavor::Link); - for args in &[ + // Check that default linker flavor and lld flavor are compatible + // with some other key properties. + assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64)); + assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link)); + assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm)); + assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender)); + assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em)); + assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker)); + assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker)); + + for args in [ &self.pre_link_args, &self.late_link_args, &self.late_link_args_dynamic, &self.late_link_args_static, &self.post_link_args, ] { + for (&flavor, flavor_args) in args { + assert!(!flavor_args.is_empty()); + // Check that flavors mentioned in link args are compatible with the default flavor. + match (self.linker_flavor, self.lld_flavor) { + ( + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc, + LldFlavor::Ld, + ) => { + assert_matches!( + flavor, + LinkerFlavor::Ld | LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::Gcc, LldFlavor::Ld64) => { + assert_matches!(flavor, LinkerFlavor::Gcc) + } + (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => { + assert_matches!( + flavor, + LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link) + ) + } + (LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc, LldFlavor::Wasm) => { + assert_matches!( + flavor, + LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc + ) + } + (LinkerFlavor::L4Bender, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::L4Bender) + } + (LinkerFlavor::Em, LldFlavor::Wasm) => { + assert_matches!(flavor, LinkerFlavor::Em) + } + (LinkerFlavor::BpfLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::BpfLinker) + } + (LinkerFlavor::PtxLinker, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::PtxLinker) + } + flavors => unreachable!("unexpected flavor combination: {:?}", flavors), + } + + // Check that link args for cc and non-cc versions of flavors are consistent. + let check_noncc = |noncc_flavor| { + if let Some(noncc_args) = args.get(&noncc_flavor) { + for arg in flavor_args { + if let Some(suffix) = arg.strip_prefix("-Wl,") { + assert!(noncc_args.iter().any(|a| a == suffix)); + } + } + } + }; + match self.linker_flavor { + LinkerFlavor::Gcc => match self.lld_flavor { + LldFlavor::Ld => { + check_noncc(LinkerFlavor::Ld); + check_noncc(LinkerFlavor::Lld(LldFlavor::Ld)); + } + LldFlavor::Wasm => check_noncc(LinkerFlavor::Lld(LldFlavor::Wasm)), + LldFlavor::Ld64 | LldFlavor::Link => {} + }, + _ => {} + } + } + + // Check that link args for lld and non-lld versions of flavors are consistent. + assert_eq!(args.get(&LinkerFlavor::Ld), args.get(&LinkerFlavor::Lld(LldFlavor::Ld))); assert_eq!( args.get(&LinkerFlavor::Msvc), args.get(&LinkerFlavor::Lld(LldFlavor::Link)), ); - if args.contains_key(&LinkerFlavor::Msvc) { - assert_eq!(self.lld_flavor, LldFlavor::Link); - } } + assert!( (self.pre_link_objects_fallback.is_empty() && self.post_link_objects_fallback.is_empty()) || self.crt_objects_fallback.is_some() ); + + // If your target really needs to deviate from the rules below, + // except it and document the reasons. // Keep the default "unknown" vendor instead. assert_ne!(self.vendor, ""); if !self.can_use_os_unknown() { diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index fbcc2aba5b708..c7e7d22108656 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -1,16 +1,13 @@ use super::{cvs, wasm_base}; -use super::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; pub fn target() -> Target { - let mut options = wasm_base::options(); - - // Rust really needs a way for users to specify exports and imports in - // the source code. --export-dynamic isn't the right tool for this job, - // however it does have the side effect of automatically exporting a lot - // of symbols, which approximates what people want when compiling for - // wasm32-unknown-unknown expect, so use it for now. - options.add_pre_link_args(LinkerFlavor::Gcc, &["--export-dynamic"]); - options.add_post_link_args(LinkerFlavor::Em, &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"]); + // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. + let pre_link_args = LinkArgs::new(); + let post_link_args = TargetOptions::link_args( + LinkerFlavor::Em, + &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], + ); let opts = TargetOptions { os: "emscripten".into(), @@ -19,11 +16,13 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".into(), linker: None, + pre_link_args, + post_link_args, relocation_model: RelocModel::Pic, panic_strategy: PanicStrategy::Unwind, no_default_libraries: false, families: cvs!["unix", "wasm"], - ..options + ..wasm_base::options() }; Target { llvm_target: "wasm32-unknown-emscripten".into(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index d572e6b3be1b8..4e2927dd913c2 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -30,27 +30,30 @@ pub fn target() -> Target { options.default_adjusted_cabi = Some(Abi::Wasm); options.add_pre_link_args( - LinkerFlavor::Gcc, + LinkerFlavor::Lld(LldFlavor::Wasm), &[ - // Make sure clang uses LLD as its linker and is configured appropriately - // otherwise - "--target=wasm32-unknown-unknown", // For now this target just never has an entry symbol no matter the output // type, so unconditionally pass this. - "-Wl,--no-entry", + "--no-entry", // Rust really needs a way for users to specify exports and imports in // the source code. --export-dynamic isn't the right tool for this job, // however it does have the side effect of automatically exporting a lot // of symbols, which approximates what people want when compiling for // wasm32-unknown-unknown expect, so use it for now. + "--export-dynamic", + ], + ); + options.add_pre_link_args( + LinkerFlavor::Gcc, + &[ + // Make sure clang uses LLD as its linker and is configured appropriately + // otherwise + "--target=wasm32-unknown-unknown", + "-Wl,--no-entry", "-Wl,--export-dynamic", ], ); - // Add the flags to wasm-ld's args too. - options - .add_pre_link_args(LinkerFlavor::Lld(LldFlavor::Wasm), &["--no-entry", "--export-dynamic"]); - Target { llvm_target: "wasm32-unknown-unknown".into(), pointer_width: 32, diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs index d5c88f23489fd..5211f7707fbb2 100644 --- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs @@ -15,20 +15,25 @@ pub fn target() -> Target { options.os = "unknown".into(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); + options.add_pre_link_args( + LinkerFlavor::Lld(LldFlavor::Wasm), + &[ + // For now this target just never has an entry symbol no matter the output + // type, so unconditionally pass this. + "--no-entry", + "-mwasm64", + ], + ); options.add_pre_link_args( LinkerFlavor::Gcc, &[ // Make sure clang uses LLD as its linker and is configured appropriately // otherwise "--target=wasm64-unknown-unknown", - // For now this target just never has an entry symbol no matter the output - // type, so unconditionally pass this. "-Wl,--no-entry", ], ); - options.add_pre_link_args(LinkerFlavor::Lld(LldFlavor::Wasm), &["--no-entry", "-mwasm64"]); - // Any engine that implements wasm64 will surely implement the rest of these // features since they were all merged into the official spec by the time // wasm64 was designed. diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 40396e3a1ffd0..a0480f386f74e 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -2,15 +2,23 @@ use crate::spec::crt_objects::{self, CrtObjectsFallback}; use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { - let pre_link_args = TargetOptions::link_args( + let mut pre_link_args = TargetOptions::link_args( + LinkerFlavor::Ld, + &[ + // Enable ASLR + "--dynamicbase", + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "--disable-auto-image-base", + ], + ); + super::add_link_args( + &mut pre_link_args, LinkerFlavor::Gcc, &[ // Tell GCC to avoid linker plugins, because we are not bundling // them with Windows installer, and Rust does its own LTO anyways. "-fno-use-linker-plugin", - // Enable ASLR "-Wl,--dynamicbase", - // ASLR will rebase it anyway so leaving that option enabled only leads to confusion "-Wl,--disable-auto-image-base", ], ); diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index 03f966ffcb2ee..334dec43ef7e0 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -17,6 +17,7 @@ pub fn opts() -> TargetOptions { ]; let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Ld, mingw_libs); super::add_link_args(&mut late_link_args, LinkerFlavor::Gcc, mingw_libs); + // Reset the flags back to empty until the FIXME above is addressed. let late_link_args_dynamic = LinkArgs::new(); let late_link_args_static = LinkArgs::new(); diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index 1d16b6580c88b..59a8cffca480a 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -4,8 +4,8 @@ pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".into(); // Use high-entropy 64 bit address space for ASLR + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); - base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep"]); base.max_atomic_width = Some(64); base.linker = Some("x86_64-w64-mingw32-gcc".into()); diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index c82fbc7592cf7..76d2013cf7fdc 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -4,8 +4,8 @@ pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".into(); // Use high-entropy 64 bit address space for ASLR + base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep", "--high-entropy-va"]); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-Wl,--high-entropy-va"]); - base.add_pre_link_args(LinkerFlavor::Ld, &["-m", "i386pep"]); base.max_atomic_width = Some(64); Target {