Skip to content

Commit ffafd15

Browse files
authored
Rollup merge of #71030 - petrochenkov:linkorder2, r=nagisa
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.
2 parents 629e51b + 8392e47 commit ffafd15

38 files changed

+219
-225
lines changed

src/librustc_codegen_ssa/back/link.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_session::search_paths::PathKind;
1212
/// need out of the shared crate context before we get rid of it.
1313
use rustc_session::{filesearch, Session};
1414
use rustc_span::symbol::Symbol;
15-
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
15+
use rustc_target::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelroLevel};
1616

1717
use super::archive::ArchiveBuilder;
1818
use super::command::Command;
@@ -182,7 +182,9 @@ fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> Command {
182182
// To comply with the Windows App Certification Kit,
183183
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
184184
let t = &sess.target.target;
185-
if flavor == LinkerFlavor::Msvc && t.target_vendor == "uwp" {
185+
if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
186+
&& t.target_vendor == "uwp"
187+
{
186188
if let Some(ref tool) = msvc_tool {
187189
let original_path = tool.path();
188190
if let Some(ref root_lib_path) = original_path.ancestors().nth(4) {
@@ -1530,13 +1532,8 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
15301532
cmd.debuginfo();
15311533

15321534
// OBJECT-FILES-NO, AUDIT-ORDER
1533-
// We want to, by default, prevent the compiler from accidentally leaking in
1534-
// any system libraries, so we may explicitly ask linkers to not link to any
1535-
// libraries by default. Note that this does not happen for windows because
1536-
// windows pulls in some large number of libraries and I couldn't quite
1537-
// figure out which subset we wanted.
1538-
//
1539-
// This is all naturally configurable via the standard methods as well.
1535+
// We want to prevent the compiler from accidentally leaking in any system libraries,
1536+
// so by default we tell linkers not to link to any default libraries.
15401537
if !sess.opts.cg.default_linker_libraries.unwrap_or(false)
15411538
&& sess.target.target.options.no_default_libraries
15421539
{

src/librustc_codegen_ssa/back/linker.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -631,15 +631,7 @@ impl<'a> Linker for MsvcLinker<'a> {
631631
}
632632

633633
fn no_default_libraries(&mut self) {
634-
// Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
635-
// as there's been trouble in the past of linking the C++ standard
636-
// library required by LLVM. This likely needs to happen one day, but
637-
// in general Windows is also a more controlled environment than
638-
// Unix, so it's not necessarily as critical that this be implemented.
639-
//
640-
// Note that there are also some licensing worries about statically
641-
// linking some libraries which require a specific agreement, so it may
642-
// not ever be possible for us to pass this flag.
634+
self.cmd.arg("/NODEFAULTLIB");
643635
}
644636

645637
fn include_path(&mut self, path: &Path) {

src/librustc_target/spec/armebv7r_none_eabi.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
22

33
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
4-
use std::default::Default;
54

65
pub fn target() -> TargetResult {
76
Ok(Target {

src/librustc_target/spec/armebv7r_none_eabihf.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
22

33
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
4-
use std::default::Default;
54

65
pub fn target() -> TargetResult {
76
Ok(Target {

src/librustc_target/spec/armv7r_none_eabi.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
22

33
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
4-
use std::default::Default;
54

65
pub fn target() -> TargetResult {
76
Ok(Target {

src/librustc_target/spec/armv7r_none_eabihf.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
22

33
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
4-
use std::default::Default;
54

65
pub fn target() -> TargetResult {
76
Ok(Target {

src/librustc_target/spec/dragonfly_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/freebsd_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/fuchsia_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut pre_link_args = LinkArgs::new();

src/librustc_target/spec/haiku_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
TargetOptions {

src/librustc_target/spec/hermit_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut pre_link_args = LinkArgs::new();

src/librustc_target/spec/hermit_kernel_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut pre_link_args = LinkArgs::new();

src/librustc_target/spec/i686_pc_windows_gnu.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::spec::{LinkerFlavor, Target, TargetResult};
22

33
pub fn target() -> TargetResult {
4-
let mut base = super::windows_base::opts();
4+
let mut base = super::windows_gnu_base::opts();
55
base.cpu = "pentium4".to_string();
66
base.max_atomic_width = Some(64);
77
base.eliminate_frame_pointer = false; // Required for backtraces

src/librustc_target/spec/i686_pc_windows_msvc.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
use crate::spec::{LinkerFlavor, Target, TargetResult};
1+
use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
22

33
pub fn target() -> TargetResult {
44
let mut base = super::windows_msvc_base::opts();
55
base.cpu = "pentium4".to_string();
66
base.max_atomic_width = Some(64);
77

8-
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
9-
// space available to x86 Windows binaries on x86_64.
10-
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string());
11-
12-
// Ensure the linker will only produce an image if it can also produce a table of
13-
// the image's safe exception handlers.
14-
// https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers
15-
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string());
8+
let pre_link_args_msvc = vec![
9+
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
10+
// space available to x86 Windows binaries on x86_64.
11+
"/LARGEADDRESSAWARE".to_string(),
12+
// Ensure the linker will only produce an image if it can also produce a table of
13+
// the image's safe exception handlers.
14+
// https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers
15+
"/SAFESEH".to_string(),
16+
];
17+
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
18+
base.pre_link_args
19+
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
20+
.unwrap()
21+
.extend(pre_link_args_msvc);
1622

1723
Ok(Target {
1824
llvm_target: "i686-pc-windows-msvc".to_string(),

src/librustc_target/spec/i686_unknown_uefi.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
99

1010
pub fn target() -> TargetResult {
11-
let mut base = super::uefi_base::opts();
11+
let mut base = super::uefi_msvc_base::opts();
1212
base.cpu = "pentium4".to_string();
1313
base.max_atomic_width = Some(64);
1414

@@ -23,11 +23,6 @@ pub fn target() -> TargetResult {
2323
// arguments, thus giving you access to full MMX/SSE acceleration.
2424
base.features = "-mmx,-sse,+soft-float".to_string();
2525

26-
// UEFI mirrors the calling-conventions used on windows. In case of i686 this means small
27-
// structs will be returned as int. This shouldn't matter much, since the restrictions placed
28-
// by the UEFI specifications forbid any ABI to return structures.
29-
base.abi_return_struct_as_int = true;
30-
3126
// Use -GNU here, because of the reason below:
3227
// Background and Problem:
3328
// If we use i686-unknown-windows, the LLVM IA32 MSVC generates compiler intrinsic

src/librustc_target/spec/i686_uwp_windows_gnu.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::spec::{LinkerFlavor, Target, TargetResult};
22

33
pub fn target() -> TargetResult {
4-
let mut base = super::windows_uwp_base::opts();
4+
let mut base = super::windows_uwp_gnu_base::opts();
55
base.cpu = "pentium4".to_string();
66
base.max_atomic_width = Some(64);
77
base.eliminate_frame_pointer = false; // Required for backtraces

src/librustc_target/spec/l4re_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
2-
use std::default::Default;
32
//use std::process::Command;
43

54
// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note

src/librustc_target/spec/linux_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/linux_kernel_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut pre_link_args = LinkArgs::new();

src/librustc_target/spec/mod.rs

+13-20
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
use crate::spec::abi::{lookup as lookup_abi, Abi};
3838
use rustc_serialize::json::{Json, ToJson};
3939
use std::collections::BTreeMap;
40-
use std::default::Default;
4140
use std::path::{Path, PathBuf};
4241
use std::str::FromStr;
4342
use std::{fmt, io};
@@ -60,18 +59,19 @@ mod l4re_base;
6059
mod linux_base;
6160
mod linux_kernel_base;
6261
mod linux_musl_base;
62+
mod msvc_base;
6363
mod netbsd_base;
6464
mod openbsd_base;
6565
mod redox_base;
6666
mod riscv_base;
6767
mod solaris_base;
6868
mod thumb_base;
69-
mod uefi_base;
69+
mod uefi_msvc_base;
7070
mod vxworks_base;
7171
mod wasm32_base;
72-
mod windows_base;
72+
mod windows_gnu_base;
7373
mod windows_msvc_base;
74-
mod windows_uwp_base;
74+
mod windows_uwp_gnu_base;
7575
mod windows_uwp_msvc_base;
7676

7777
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
@@ -309,23 +309,14 @@ macro_rules! supported_targets {
309309
}
310310

311311
#[cfg(test)]
312-
mod test_json_encode_decode {
313-
use rustc_serialize::json::ToJson;
314-
use super::Target;
315-
$(use super::$module;)+
312+
mod tests {
313+
mod tests_impl;
316314

315+
// Cannot put this into a separate file without duplication, make an exception.
317316
$(
318-
#[test] // `#[test]` - this is hard to put into a separate file, make an exception
317+
#[test] // `#[test]`
319318
fn $module() {
320-
// Grab the TargetResult struct. If we successfully retrieved
321-
// a Target, then the test JSON encoding/decoding can run for this
322-
// Target on this testing platform (i.e., checking the iOS targets
323-
// only on a Mac test platform).
324-
let _ = $module::target().map(|original| {
325-
let as_json = original.to_json();
326-
let parsed = Target::from_json(as_json).unwrap();
327-
assert_eq!(original, parsed);
328-
});
319+
tests_impl::test_target(super::$module::target());
329320
}
330321
)+
331322
}
@@ -538,7 +529,8 @@ pub struct Target {
538529
pub arch: String,
539530
/// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
540531
pub data_layout: String,
541-
/// Linker flavor
532+
/// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
533+
/// on the command line.
542534
pub linker_flavor: LinkerFlavor,
543535
/// Optional settings with defaults.
544536
pub options: TargetOptions,
@@ -566,7 +558,8 @@ pub struct TargetOptions {
566558
/// Linker to invoke
567559
pub linker: Option<String>,
568560

569-
/// LLD flavor
561+
/// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
562+
/// without clarifying its flavor in any way.
570563
pub lld_flavor: LldFlavor,
571564

572565
/// Linker arguments that are passed *before* any user-defined libraries.

src/librustc_target/spec/msvc_base.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
2+
3+
pub fn opts() -> TargetOptions {
4+
let pre_link_args_msvc = vec![
5+
// Suppress the verbose logo and authorship debugging output, which would needlessly
6+
// clog any log files.
7+
"/NOLOGO".to_string(),
8+
// Tell the compiler that non-code sections can be marked as non-executable,
9+
// including stack pages.
10+
// UEFI is fully compatible to non-executable data pages.
11+
// In fact, firmware might enforce this, so we better let the linker know about this,
12+
// so it will fail if the compiler ever tries placing code on the stack
13+
// (e.g., trampoline constructs and alike).
14+
"/NXCOMPAT".to_string(),
15+
];
16+
let mut pre_link_args = LinkArgs::new();
17+
pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
18+
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
19+
20+
TargetOptions {
21+
executables: true,
22+
is_like_windows: true,
23+
is_like_msvc: true,
24+
// set VSLANG to 1033 can prevent link.exe from using
25+
// language packs, and avoid generating Non-UTF-8 error
26+
// messages if a link error occurred.
27+
link_env: vec![("VSLANG".to_string(), "1033".to_string())],
28+
lld_flavor: LldFlavor::Link,
29+
pre_link_args,
30+
abi_return_struct_as_int: true,
31+
emit_debug_gdb_scripts: false,
32+
33+
..Default::default()
34+
}
35+
}

src/librustc_target/spec/netbsd_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/openbsd_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/redox_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
let mut args = LinkArgs::new();

src/librustc_target/spec/solaris_base.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::spec::TargetOptions;
2-
use std::default::Default;
32

43
pub fn opts() -> TargetOptions {
54
TargetOptions {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use super::super::*;
2+
3+
pub(super) fn test_target(target: TargetResult) {
4+
// Grab the TargetResult struct. If we successfully retrieved
5+
// a Target, then the test JSON encoding/decoding can run for this
6+
// Target on this testing platform (i.e., checking the iOS targets
7+
// only on a Mac test platform).
8+
if let Ok(original) = target {
9+
original.check_consistency();
10+
let as_json = original.to_json();
11+
let parsed = Target::from_json(as_json).unwrap();
12+
assert_eq!(original, parsed);
13+
}
14+
}
15+
16+
impl Target {
17+
fn check_consistency(&self) {
18+
// Check that LLD with the given flavor is treated identically to the linker it emulates.
19+
// If you target really needs to deviate from the rules below, whitelist it
20+
// and document the reasons.
21+
assert_eq!(
22+
self.linker_flavor == LinkerFlavor::Msvc
23+
|| self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link),
24+
self.options.lld_flavor == LldFlavor::Link,
25+
);
26+
for args in &[
27+
&self.options.pre_link_args,
28+
&self.options.pre_link_args_crt,
29+
&self.options.late_link_args,
30+
&self.options.late_link_args_dynamic,
31+
&self.options.late_link_args_static,
32+
&self.options.post_link_args,
33+
] {
34+
assert_eq!(
35+
args.get(&LinkerFlavor::Msvc),
36+
args.get(&LinkerFlavor::Lld(LldFlavor::Link)),
37+
);
38+
if args.contains_key(&LinkerFlavor::Msvc) {
39+
assert_eq!(self.options.lld_flavor, LldFlavor::Link);
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)