Skip to content

Commit 3ad8c88

Browse files
committed
rustc_target: Make sure lld-link is treated as link.exe by default
The differences if they are discovered will need to be explicitly documented
1 parent d28a464 commit 3ad8c88

File tree

7 files changed

+106
-64
lines changed

7 files changed

+106
-64
lines changed

src/librustc_codegen_ssa/back/link.rs

Lines changed: 4 additions & 2 deletions
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) {

src/librustc_target/spec/i686_pc_windows_msvc.rs

Lines changed: 15 additions & 9 deletions
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/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ macro_rules! supported_targets {
322322
// Target on this testing platform (i.e., checking the iOS targets
323323
// only on a Mac test platform).
324324
let _ = $module::target().map(|original| {
325+
original.check_consistency();
325326
let as_json = original.to_json();
326327
let parsed = Target::from_json(as_json).unwrap();
327328
assert_eq!(original, parsed);
@@ -538,7 +539,8 @@ pub struct Target {
538539
pub arch: String,
539540
/// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
540541
pub data_layout: String,
541-
/// Linker flavor
542+
/// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
543+
/// on the command line.
542544
pub linker_flavor: LinkerFlavor,
543545
/// Optional settings with defaults.
544546
pub options: TargetOptions,
@@ -566,7 +568,8 @@ pub struct TargetOptions {
566568
/// Linker to invoke
567569
pub linker: Option<String>,
568570

569-
/// LLD flavor
571+
/// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker
572+
/// without clarifying its flavor in any way.
570573
pub lld_flavor: LldFlavor,
571574

572575
/// Linker arguments that are passed *before* any user-defined libraries.
@@ -1286,6 +1289,34 @@ impl Target {
12861289
}
12871290
}
12881291
}
1292+
1293+
#[cfg(test)]
1294+
fn check_consistency(&self) {
1295+
// Check that LLD with the given flavor is treated identically to the linker it emulates.
1296+
// If you target really needs to deviate from the rules below, whitelist it
1297+
// and document the reasons.
1298+
assert_eq!(
1299+
self.linker_flavor == LinkerFlavor::Msvc
1300+
|| self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link),
1301+
self.options.lld_flavor == LldFlavor::Link,
1302+
);
1303+
for args in &[
1304+
&self.options.pre_link_args,
1305+
&self.options.pre_link_args_crt,
1306+
&self.options.late_link_args,
1307+
&self.options.late_link_args_dynamic,
1308+
&self.options.late_link_args_static,
1309+
&self.options.post_link_args,
1310+
] {
1311+
assert_eq!(
1312+
args.get(&LinkerFlavor::Msvc),
1313+
args.get(&LinkerFlavor::Lld(LldFlavor::Link)),
1314+
);
1315+
if args.contains_key(&LinkerFlavor::Msvc) {
1316+
assert_eq!(self.options.lld_flavor, LldFlavor::Link);
1317+
}
1318+
}
1319+
}
12891320
}
12901321

12911322
impl ToJson for Target {

src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
1+
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
22

33
pub fn target() -> TargetResult {
44
let mut base = super::windows_msvc_base::opts();
@@ -10,7 +10,12 @@ pub fn target() -> TargetResult {
1010
// should be smart enough to insert branch islands only
1111
// where necessary, but this is not the observed behavior.
1212
// Disabling the LBR optimization works around the issue.
13-
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/OPT:NOLBR".to_string());
13+
let pre_link_args_msvc = "/OPT:NOLBR".to_string();
14+
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(pre_link_args_msvc.clone());
15+
base.pre_link_args
16+
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
17+
.unwrap()
18+
.push(pre_link_args_msvc);
1419

1520
// FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
1621
// implemented for windows/arm in LLVM

src/librustc_target/spec/uefi_base.rs

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,37 @@ use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOption
1313
use std::default::Default;
1414

1515
pub fn opts() -> TargetOptions {
16+
let pre_link_args_msvc = vec![
17+
// Suppress the verbose logo and authorship debugging output, which would needlessly
18+
// clog any log files.
19+
"/NOLOGO".to_string(),
20+
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
21+
// non-code sections can be marked as non-executable, including stack pages. In fact,
22+
// firmware might enforce this, so we better let the linker know about this, so it
23+
// will fail if the compiler ever tries placing code on the stack (e.g., trampoline
24+
// constructs and alike).
25+
"/NXCOMPAT".to_string(),
26+
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
27+
// must be freestanding.
28+
"/nodefaultlib".to_string(),
29+
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
30+
// one. "efi_main" seems to be a common choice amongst other implementations and the
31+
// spec.
32+
"/entry:efi_main".to_string(),
33+
// COFF images have a "Subsystem" field in their header, which defines what kind of
34+
// program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
35+
// EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
36+
// which is very likely the most common option. Individual projects can override this
37+
// with custom linker flags.
38+
// The subsystem-type only has minor effects on the application. It defines the memory
39+
// regions the application is loaded into (runtime-drivers need to be put into
40+
// reserved areas), as well as whether a return from the entry-point is treated as
41+
// exit (default for applications).
42+
"/subsystem:efi_application".to_string(),
43+
];
1644
let mut pre_link_args = LinkArgs::new();
17-
18-
pre_link_args.insert(
19-
LinkerFlavor::Lld(LldFlavor::Link),
20-
vec![
21-
// Suppress the verbose logo and authorship debugging output, which would needlessly
22-
// clog any log files.
23-
"/NOLOGO".to_string(),
24-
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
25-
// non-code sections can be marked as non-executable, including stack pages. In fact,
26-
// firmware might enforce this, so we better let the linker know about this, so it
27-
// will fail if the compiler ever tries placing code on the stack (e.g., trampoline
28-
// constructs and alike).
29-
"/NXCOMPAT".to_string(),
30-
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
31-
// must be freestanding.
32-
"/nodefaultlib".to_string(),
33-
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
34-
// one. "efi_main" seems to be a common choice amongst other implementations and the
35-
// spec.
36-
"/entry:efi_main".to_string(),
37-
// COFF images have a "Subsystem" field in their header, which defines what kind of
38-
// program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
39-
// EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
40-
// which is very likely the most common option. Individual projects can override this
41-
// with custom linker flags.
42-
// The subsystem-type only has minor effects on the application. It defines the memory
43-
// regions the application is loaded into (runtime-drivers need to be put into
44-
// reserved areas), as well as whether a return from the entry-point is treated as
45-
// exit (default for applications).
46-
"/subsystem:efi_application".to_string(),
47-
],
48-
);
45+
pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
46+
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
4947

5048
TargetOptions {
5149
dynamic_linking: false,

src/librustc_target/spec/windows_msvc_base.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
22
use std::default::Default;
33

44
pub fn opts() -> TargetOptions {
5-
let pre_args = vec!["/NOLOGO".to_string(), "/NXCOMPAT".to_string()];
6-
let mut args = LinkArgs::new();
7-
args.insert(LinkerFlavor::Msvc, pre_args.clone());
8-
args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_args);
5+
let pre_link_args_msvc = vec!["/NOLOGO".to_string(), "/NXCOMPAT".to_string()];
6+
let mut pre_link_args = LinkArgs::new();
7+
pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
8+
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
99

1010
TargetOptions {
1111
function_sections: true,
@@ -24,7 +24,7 @@ pub fn opts() -> TargetOptions {
2424
// messages if a link error occurred.
2525
link_env: vec![("VSLANG".to_string(), "1033".to_string())],
2626
lld_flavor: LldFlavor::Link,
27-
pre_link_args: args,
27+
pre_link_args,
2828
crt_static_allows_dylibs: true,
2929
crt_static_respected: true,
3030
abi_return_struct_as_int: true,

src/librustc_target/spec/windows_uwp_msvc_base.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
1-
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
1+
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
22
use std::default::Default;
33

44
pub fn opts() -> TargetOptions {
5-
let mut args = LinkArgs::new();
6-
args.insert(
7-
LinkerFlavor::Msvc,
8-
vec![
9-
"/NOLOGO".to_string(),
10-
"/NXCOMPAT".to_string(),
11-
"/APPCONTAINER".to_string(),
12-
"mincore.lib".to_string(),
13-
],
14-
);
5+
let pre_link_args_msvc = vec![
6+
"/NOLOGO".to_string(),
7+
"/NXCOMPAT".to_string(),
8+
"/APPCONTAINER".to_string(),
9+
"mincore.lib".to_string(),
10+
];
11+
let mut pre_link_args = LinkArgs::new();
12+
pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone());
13+
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
1514

1615
TargetOptions {
1716
function_sections: true,
@@ -25,12 +24,13 @@ pub fn opts() -> TargetOptions {
2524
target_family: Some("windows".to_string()),
2625
is_like_windows: true,
2726
is_like_msvc: true,
28-
pre_link_args: args,
27+
pre_link_args,
2928
crt_static_allows_dylibs: true,
3029
crt_static_respected: true,
3130
abi_return_struct_as_int: true,
3231
emit_debug_gdb_scripts: false,
3332
requires_uwtable: true,
33+
lld_flavor: LldFlavor::Link,
3434

3535
..Default::default()
3636
}

0 commit comments

Comments
 (0)