Skip to content

Commit 4f9aa69

Browse files
committed
[WIP] Encode more info about order-dependence of linker arguments
1 parent 36b1a92 commit 4f9aa69

File tree

7 files changed

+114
-30
lines changed

7 files changed

+114
-30
lines changed

src/librustc_codegen_ssa/back/link.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1571,9 +1571,19 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
15711571
// OBJECT-FILES-NO, AUDIT-ORDER
15721572
add_rpath_args(cmd, sess, codegen_results, out_filename);
15731573

1574+
// OBJECT-FILES-NO
1575+
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
1576+
cmd.args(&args.unordered_right_overridable);
1577+
}
1578+
15741579
// OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
15751580
add_user_defined_link_args(cmd, sess, codegen_results);
15761581

1582+
// OBJECT-FILES-NO
1583+
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
1584+
cmd.args(&args.unordered_left_overridable);
1585+
}
1586+
15771587
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
15781588
cmd.finalize();
15791589

@@ -1586,6 +1596,11 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
15861596
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
15871597
add_post_link_args(cmd, sess, flavor);
15881598

1599+
// OBJECT-FILES-NO
1600+
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
1601+
cmd.args(&args.unordered_non_overridable);
1602+
}
1603+
15891604
cmd.take_cmd()
15901605
}
15911606

src/librustc_target/spec/i686_pc_windows_msvc.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub fn target() -> TargetResult {
55
base.cpu = "pentium4".to_string();
66
base.max_atomic_width = Some(64);
77

8-
let pre_link_args_msvc = vec![
8+
let new_link_args = vec![
99
// Mark all dynamic libraries and executables as compatible with the larger 4GiB address
1010
// space available to x86 Windows binaries on x86_64.
1111
"/LARGEADDRESSAWARE".to_string(),
@@ -14,11 +14,16 @@ pub fn target() -> TargetResult {
1414
// https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers
1515
"/SAFESEH".to_string(),
1616
];
17-
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
18-
base.pre_link_args
17+
base.link_args
18+
.get_mut(&LinkerFlavor::Msvc)
19+
.unwrap()
20+
.unordered_right_overridable
21+
.extend(new_link_args.clone());
22+
base.link_args
1923
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
2024
.unwrap()
21-
.extend(pre_link_args_msvc);
25+
.unordered_right_overridable
26+
.extend(new_link_args);
2227

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

src/librustc_target/spec/mod.rs

+24
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,26 @@ impl HasTargetSpec for Target {
549549
}
550550
}
551551

552+
/// "Unordered" options are options applied to the whole linking process rather than to individual
553+
/// input object files or libraries. So it doesn't matter whether they are passed before or after
554+
/// input files.
555+
#[derive(Default, PartialEq, Clone, Debug)]
556+
pub struct NewLinkArgs {
557+
/// These options cannot be overridden once specified.
558+
/// So they can be passed anywhere on the command line.
559+
pub unordered_non_overridable: Vec<String>,
560+
/// These option can be overridden by options placed to the left from them on the command line.
561+
/// So they need to be placed after customization points like `-C link-args`.
562+
/// (Library search directories traversed from left to right is a typical example.)
563+
pub unordered_left_overridable: Vec<String>,
564+
/// These option can be overridden by options placed to the right from them on the command line.
565+
/// So they need to be placed before customization points like `-C link-args`.
566+
/// (Options like `-foo=yes` overridden by `-foo=no` is a typical example.)
567+
pub unordered_right_overridable: Vec<String>,
568+
}
569+
570+
type LinkArgsMap = BTreeMap<LinkerFlavor, NewLinkArgs>;
571+
552572
/// Optional aspects of a target specification.
553573
///
554574
/// This has an implementation of `Default`, see each field for what the default is. In general,
@@ -565,6 +585,9 @@ pub struct TargetOptions {
565585
/// without clarifying its flavor in any way.
566586
pub lld_flavor: LldFlavor,
567587

588+
/// New style default linker arguments.
589+
/// Other link arg fields are supposed to be migrated to them eventually.
590+
pub link_args: LinkArgsMap,
568591
/// Linker arguments that are passed *before* any user-defined libraries.
569592
pub pre_link_args: LinkArgs, // ... unconditionally
570593
pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
@@ -812,6 +835,7 @@ impl Default for TargetOptions {
812835
is_builtin: false,
813836
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
814837
lld_flavor: LldFlavor::Ld,
838+
link_args: Default::default(),
815839
pre_link_args: LinkArgs::new(),
816840
pre_link_args_crt: LinkArgs::new(),
817841
post_link_args: LinkArgs::new(),

src/librustc_target/spec/msvc_base.rs

+35-17
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,39 @@
1-
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
1+
// https://docs.microsoft.com/en-us/cpp/build/reference/linking
2+
// https://docs.microsoft.com/en-us/cpp/build/reference/libpath-additional-libpath
3+
// > LINK first processes options specified in the LINK environment variable, followed by options
4+
// > in the order they are specified on the command line and in command files.
5+
// > If an option is repeated with different arguments, the last one processed takes precedence.
6+
// > Options apply to the entire build; no options can be applied to specific input files.
7+
// > If you want to specify more than one directory, you must specify multiple /LIBPATH options.
8+
// > The linker will then search the specified directories in order.
9+
//
10+
// Therefore all options that are not input files are order-independent and either non-overridable
11+
// or right-overridable. Library search directories are left-overridable.
12+
13+
use crate::spec::{LinkArgsMap, LinkerFlavor, LldFlavor, NewLinkArgs, TargetOptions};
214

315
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);
16+
let new_link_args = NewLinkArgs {
17+
unordered_non_overridable: vec![
18+
// Suppress the verbose logo and authorship debugging output, which would needlessly
19+
// clog any log files.
20+
"/NOLOGO".to_string(),
21+
],
22+
unordered_right_overridable: vec![
23+
// Tell the compiler that non-code sections can be marked as non-executable,
24+
// including stack pages.
25+
// UEFI is fully compatible to non-executable data pages.
26+
// In fact, firmware might enforce this, so we better let the linker know about this,
27+
// so it will fail if the compiler ever tries placing code on the stack
28+
// (e.g., trampoline constructs and alike).
29+
"/NXCOMPAT".to_string(),
30+
],
31+
..Default::default()
32+
};
33+
34+
let mut link_args = LinkArgsMap::new();
35+
link_args.insert(LinkerFlavor::Msvc, new_link_args.clone());
36+
link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), new_link_args);
1937

2038
TargetOptions {
2139
executables: true,
@@ -26,7 +44,7 @@ pub fn opts() -> TargetOptions {
2644
// messages if a link error occurred.
2745
link_env: vec![("VSLANG".to_string(), "1033".to_string())],
2846
lld_flavor: LldFlavor::Link,
29-
pre_link_args,
47+
link_args,
3048
abi_return_struct_as_int: true,
3149
emit_debug_gdb_scripts: false,
3250

src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@ 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-
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
13+
let new_link_args = "/OPT:NOLBR".to_string();
14+
base.link_args
15+
.get_mut(&LinkerFlavor::Msvc)
16+
.unwrap()
17+
.unordered_right_overridable
18+
.push(new_link_args.clone());
19+
base.link_args
1620
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
1721
.unwrap()
18-
.push(pre_link_args_msvc);
22+
.unordered_right_overridable
23+
.push(new_link_args);
1924

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

src/librustc_target/spec/uefi_msvc_base.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
1414
pub fn opts() -> TargetOptions {
1515
let mut base = super::msvc_base::opts();
1616

17-
let pre_link_args_msvc = vec![
17+
let new_link_args = vec![
1818
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
1919
// one. "efi_main" seems to be a common choice amongst other implementations and the
2020
// spec.
@@ -30,11 +30,16 @@ pub fn opts() -> TargetOptions {
3030
// exit (default for applications).
3131
"/subsystem:efi_application".to_string(),
3232
];
33-
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
34-
base.pre_link_args
33+
base.link_args
34+
.get_mut(&LinkerFlavor::Msvc)
35+
.unwrap()
36+
.unordered_right_overridable
37+
.extend(new_link_args.clone());
38+
base.link_args
3539
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
3640
.unwrap()
37-
.extend(pre_link_args_msvc);
41+
.unordered_right_overridable
42+
.extend(new_link_args);
3843

3944
TargetOptions {
4045
disable_redzone: true,

src/librustc_target/spec/windows_uwp_msvc_base.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,19 @@ use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions};
33
pub fn opts() -> TargetOptions {
44
let mut opts = super::windows_msvc_base::opts();
55

6-
let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()];
6+
let new_link_args = vec!["/APPCONTAINER".to_string()];
7+
opts.link_args
8+
.get_mut(&LinkerFlavor::Msvc)
9+
.unwrap()
10+
.unordered_right_overridable
11+
.extend(new_link_args.clone());
12+
opts.link_args
13+
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
14+
.unwrap()
15+
.unordered_right_overridable
16+
.extend(new_link_args);
17+
18+
let pre_link_args_msvc = vec!["mincore.lib".to_string()];
719
opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
820
opts.pre_link_args
921
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))

0 commit comments

Comments
 (0)