Skip to content

Commit

Permalink
rustc_target: Some more tests and fixes for linker arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Jun 25, 2022
1 parent 46aba88 commit 456f65e
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 44 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
97 changes: 84 additions & 13 deletions compiler/rustc_target/src/spec/tests/tests_impl.rs
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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() {
Expand Down
21 changes: 10 additions & 11 deletions compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
Original file line number Diff line number Diff line change
@@ -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(),
Expand All @@ -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(),
Expand Down
21 changes: 12 additions & 9 deletions compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 11 additions & 3 deletions compiler/rustc_target/src/spec/windows_gnu_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
],
);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 456f65e

Please sign in to comment.