Skip to content

Commit

Permalink
Rollup merge of rust-lang#71030 - petrochenkov:linkorder2, r=nagisa
Browse files Browse the repository at this point in the history
rustc_target: Refactor target specifications related to Windows and UEFI

- LLD support is improved.
- Code is cleaned up.
- Target specs are organized in a more hierarchical way.
- Possible issues in UWP and UEFI platforms are identified (see FIXMEs).

The code is better read per-commit.
  • Loading branch information
Centril authored Apr 15, 2020
2 parents 4f84ad2 + 8392e47 commit 7276fd0
Show file tree
Hide file tree
Showing 38 changed files with 219 additions and 225 deletions.
15 changes: 6 additions & 9 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
{
Expand Down
10 changes: 1 addition & 9 deletions src/librustc_codegen_ssa/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/armebv7r_none_eabi.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/armebv7r_none_eabihf.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/armv7r_none_eabi.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/armv7r_none_eabihf.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/dragonfly_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/freebsd_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/fuchsia_base.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/haiku_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
TargetOptions {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/hermit_base.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/hermit_kernel_base.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_target/spec/i686_pc_windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
24 changes: 15 additions & 9 deletions src/librustc_target/spec/i686_pc_windows_msvc.rs
Original file line number Diff line number Diff line change
@@ -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(),
Expand Down
7 changes: 1 addition & 6 deletions src/librustc_target/spec/i686_unknown_uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_target/spec/i686_uwp_windows_gnu.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/l4re_base.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/linux_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/linux_kernel_base.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
33 changes: 13 additions & 20 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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)]
Expand Down Expand Up @@ -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());
}
)+
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -566,7 +558,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.
Expand Down
35 changes: 35 additions & 0 deletions src/librustc_target/spec/msvc_base.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}
1 change: 0 additions & 1 deletion src/librustc_target/spec/netbsd_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/openbsd_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/redox_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
use std::default::Default;

pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
Expand Down
1 change: 0 additions & 1 deletion src/librustc_target/spec/solaris_base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::spec::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
TargetOptions {
Expand Down
43 changes: 43 additions & 0 deletions src/librustc_target/spec/tests/tests_impl.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}
Loading

0 comments on commit 7276fd0

Please sign in to comment.