Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Encode more info about order-dependence of linker arguments #71081

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1571,9 +1571,19 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
// OBJECT-FILES-NO, AUDIT-ORDER
add_rpath_args(cmd, sess, codegen_results, out_filename);

// OBJECT-FILES-NO
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
cmd.args(&args.unordered_right_overridable);
}

// OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
add_user_defined_link_args(cmd, sess, codegen_results);

// OBJECT-FILES-NO
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
cmd.args(&args.unordered_left_overridable);
}

// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
cmd.finalize();

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

// OBJECT-FILES-NO
if let Some(args) = sess.target.target.options.link_args.get(&flavor) {
cmd.args(&args.unordered_non_overridable);
}

cmd.take_cmd()
}

Expand Down
13 changes: 9 additions & 4 deletions src/librustc_target/spec/i686_pc_windows_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub fn target() -> TargetResult {
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);

let pre_link_args_msvc = vec![
let new_link_args = 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(),
Expand All @@ -14,11 +14,16 @@ pub fn target() -> TargetResult {
// 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
base.link_args
.get_mut(&LinkerFlavor::Msvc)
.unwrap()
.unordered_right_overridable
.extend(new_link_args.clone());
base.link_args
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
.unwrap()
.extend(pre_link_args_msvc);
.unordered_right_overridable
.extend(new_link_args);

Ok(Target {
llvm_target: "i686-pc-windows-msvc".to_string(),
Expand Down
24 changes: 24 additions & 0 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,26 @@ impl HasTargetSpec for Target {
}
}

/// "Unordered" options are options applied to the whole linking process rather than to individual
/// input object files or libraries. So it doesn't matter whether they are passed before or after
/// input files.
#[derive(Default, PartialEq, Clone, Debug)]
pub struct NewLinkArgs {
/// These options cannot be overridden once specified.
/// So they can be passed anywhere on the command line.
pub unordered_non_overridable: Vec<String>,
/// These option can be overridden by options placed to the left from them on the command line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// These option can be overridden by options placed to the left from them on the command line.
/// These options can be overridden by options placed to the left from them on the command line.

/// So they need to be placed after customization points like `-C link-args`.
/// (Library search directories traversed from left to right is a typical example.)
pub unordered_left_overridable: Vec<String>,
/// These option can be overridden by options placed to the right from them on the command line.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// These option can be overridden by options placed to the right from them on the command line.
/// These options can be overridden by options placed to the right from them on the command line.

/// So they need to be placed before customization points like `-C link-args`.
/// (Options like `-foo=yes` overridden by `-foo=no` is a typical example.)
pub unordered_right_overridable: Vec<String>,
}

type LinkArgsMap = BTreeMap<LinkerFlavor, NewLinkArgs>;

/// Optional aspects of a target specification.
///
/// This has an implementation of `Default`, see each field for what the default is. In general,
Expand All @@ -565,6 +585,9 @@ pub struct TargetOptions {
/// without clarifying its flavor in any way.
pub lld_flavor: LldFlavor,

/// New style default linker arguments.
/// Other link arg fields are supposed to be migrated to them eventually.
pub link_args: LinkArgsMap,
/// Linker arguments that are passed *before* any user-defined libraries.
pub pre_link_args: LinkArgs, // ... unconditionally
pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
Expand Down Expand Up @@ -812,6 +835,7 @@ impl Default for TargetOptions {
is_builtin: false,
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
lld_flavor: LldFlavor::Ld,
link_args: Default::default(),
pre_link_args: LinkArgs::new(),
pre_link_args_crt: LinkArgs::new(),
post_link_args: LinkArgs::new(),
Expand Down
52 changes: 35 additions & 17 deletions src/librustc_target/spec/msvc_base.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
// https://docs.microsoft.com/en-us/cpp/build/reference/linking
// https://docs.microsoft.com/en-us/cpp/build/reference/libpath-additional-libpath
// > LINK first processes options specified in the LINK environment variable, followed by options
// > in the order they are specified on the command line and in command files.
// > If an option is repeated with different arguments, the last one processed takes precedence.
// > Options apply to the entire build; no options can be applied to specific input files.
// > If you want to specify more than one directory, you must specify multiple /LIBPATH options.
// > The linker will then search the specified directories in order.
//
// Therefore all options that are not input files are order-independent and either non-overridable
// or right-overridable. Library search directories are left-overridable.

use crate::spec::{LinkArgsMap, LinkerFlavor, LldFlavor, NewLinkArgs, 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);
let new_link_args = NewLinkArgs {
unordered_non_overridable: vec![
// Suppress the verbose logo and authorship debugging output, which would needlessly
// clog any log files.
"/NOLOGO".to_string(),
],
unordered_right_overridable: vec![
// 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(),
],
..Default::default()
};

let mut link_args = LinkArgsMap::new();
link_args.insert(LinkerFlavor::Msvc, new_link_args.clone());
link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), new_link_args);

TargetOptions {
executables: true,
Expand All @@ -26,7 +44,7 @@ pub fn opts() -> TargetOptions {
// messages if a link error occurred.
link_env: vec![("VSLANG".to_string(), "1033".to_string())],
lld_flavor: LldFlavor::Link,
pre_link_args,
link_args,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,

Expand Down
13 changes: 9 additions & 4 deletions src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ pub fn target() -> TargetResult {
// should be smart enough to insert branch islands only
// where necessary, but this is not the observed behavior.
// Disabling the LBR optimization works around the issue.
let pre_link_args_msvc = "/OPT:NOLBR".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(pre_link_args_msvc.clone());
base.pre_link_args
let new_link_args = "/OPT:NOLBR".to_string();
base.link_args
.get_mut(&LinkerFlavor::Msvc)
.unwrap()
.unordered_right_overridable
.push(new_link_args.clone());
base.link_args
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
.unwrap()
.push(pre_link_args_msvc);
.unordered_right_overridable
.push(new_link_args);

// FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
// implemented for windows/arm in LLVM
Expand Down
13 changes: 9 additions & 4 deletions src/librustc_target/spec/uefi_msvc_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
pub fn opts() -> TargetOptions {
let mut base = super::msvc_base::opts();

let pre_link_args_msvc = vec![
let new_link_args = vec![
// Non-standard subsystems have no default entry-point in PE+ files. We have to define
// one. "efi_main" seems to be a common choice amongst other implementations and the
// spec.
Expand All @@ -30,11 +30,16 @@ pub fn opts() -> TargetOptions {
// exit (default for applications).
"/subsystem:efi_application".to_string(),
];
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
base.pre_link_args
base.link_args
.get_mut(&LinkerFlavor::Msvc)
.unwrap()
.unordered_right_overridable
.extend(new_link_args.clone());
base.link_args
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
.unwrap()
.extend(pre_link_args_msvc);
.unordered_right_overridable
.extend(new_link_args);

TargetOptions {
disable_redzone: true,
Expand Down
14 changes: 13 additions & 1 deletion src/librustc_target/spec/windows_uwp_msvc_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions};
pub fn opts() -> TargetOptions {
let mut opts = super::windows_msvc_base::opts();

let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()];
let new_link_args = vec!["/APPCONTAINER".to_string()];
opts.link_args
.get_mut(&LinkerFlavor::Msvc)
.unwrap()
.unordered_right_overridable
.extend(new_link_args.clone());
opts.link_args
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
.unwrap()
.unordered_right_overridable
.extend(new_link_args);

let pre_link_args_msvc = vec!["mincore.lib".to_string()];
opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
opts.pre_link_args
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
Expand Down