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.
This commit is contained in:
commit
ffafd15280
38 changed files with 219 additions and 225 deletions
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
TargetOptions {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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};
|
||||
|
@ -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)]
|
||||
|
@ -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());
|
||||
}
|
||||
)+
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
|
35
src/librustc_target/spec/msvc_base.rs
Normal file
35
src/librustc_target/spec/msvc_base.rs
Normal file
|
@ -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,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::TargetOptions;
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
TargetOptions {
|
||||
|
|
43
src/librustc_target/spec/tests/tests_impl.rs
Normal file
43
src/librustc_target/spec/tests/tests_impl.rs
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
// build scripts / gcc flags.
|
||||
|
||||
use crate::spec::{PanicStrategy, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
// See rust-lang/rfcs#1645 for a discussion about these defaults
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
|
||||
|
||||
pub fn target() -> TargetResult {
|
||||
let mut base = super::windows_msvc_base::opts();
|
||||
|
@ -10,7 +10,12 @@ 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.
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/OPT:NOLBR".to_string());
|
||||
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
|
||||
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
|
||||
.unwrap()
|
||||
.push(pre_link_args_msvc);
|
||||
|
||||
// FIXME(jordanrh): use PanicStrategy::Unwind when SEH is
|
||||
// implemented for windows/arm in LLVM
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
// This defines a base target-configuration for native UEFI systems. The UEFI specification has
|
||||
// quite detailed sections on the ABI of all the supported target architectures. In almost all
|
||||
// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
|
||||
// documentation.
|
||||
// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
|
||||
// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
|
||||
// by the loader if the pre-chosen memory location is already in use.
|
||||
// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
|
||||
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
|
||||
// code runs in the same environment, no process separation is supported.
|
||||
|
||||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Lld(LldFlavor::Link),
|
||||
vec![
|
||||
// Suppress the verbose logo and authorship debugging output, which would needlessly
|
||||
// clog any log files.
|
||||
"/NOLOGO".to_string(),
|
||||
// UEFI is fully compatible to non-executable data pages. Tell the compiler that
|
||||
// non-code sections can be marked as non-executable, including stack 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(),
|
||||
// There is no runtime for UEFI targets, prevent them from being linked. UEFI targets
|
||||
// must be freestanding.
|
||||
"/nodefaultlib".to_string(),
|
||||
// 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.
|
||||
"/entry:efi_main".to_string(),
|
||||
// COFF images have a "Subsystem" field in their header, which defines what kind of
|
||||
// program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
|
||||
// EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
|
||||
// which is very likely the most common option. Individual projects can override this
|
||||
// with custom linker flags.
|
||||
// The subsystem-type only has minor effects on the application. It defines the memory
|
||||
// regions the application is loaded into (runtime-drivers need to be put into
|
||||
// reserved areas), as well as whether a return from the entry-point is treated as
|
||||
// exit (default for applications).
|
||||
"/subsystem:efi_application".to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
TargetOptions {
|
||||
dynamic_linking: false,
|
||||
executables: true,
|
||||
disable_redzone: true,
|
||||
exe_suffix: ".efi".to_string(),
|
||||
allows_weak_linkage: false,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
stack_probes: true,
|
||||
singlethread: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
|
||||
linker: Some("rust-lld".to_string()),
|
||||
lld_flavor: LldFlavor::Link,
|
||||
pre_link_args,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
58
src/librustc_target/spec/uefi_msvc_base.rs
Normal file
58
src/librustc_target/spec/uefi_msvc_base.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
// This defines a base target-configuration for native UEFI systems. The UEFI specification has
|
||||
// quite detailed sections on the ABI of all the supported target architectures. In almost all
|
||||
// cases it simply follows what Microsoft Windows does. Hence, whenever in doubt, see the MSDN
|
||||
// documentation.
|
||||
// UEFI uses COFF/PE32+ format for binaries. All binaries must be statically linked. No dynamic
|
||||
// linker is supported. As native to COFF, binaries are position-dependent, but will be relocated
|
||||
// by the loader if the pre-chosen memory location is already in use.
|
||||
// UEFI forbids running code on anything but the boot-CPU. No interrupts are allowed other than
|
||||
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
|
||||
// code runs in the same environment, no process separation is supported.
|
||||
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut base = super::msvc_base::opts();
|
||||
|
||||
let pre_link_args_msvc = 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.
|
||||
"/entry:efi_main".to_string(),
|
||||
// COFF images have a "Subsystem" field in their header, which defines what kind of
|
||||
// program it is. UEFI has 3 fields reserved, which are EFI_APPLICATION,
|
||||
// EFI_BOOT_SERVICE_DRIVER, and EFI_RUNTIME_DRIVER. We default to EFI_APPLICATION,
|
||||
// which is very likely the most common option. Individual projects can override this
|
||||
// with custom linker flags.
|
||||
// The subsystem-type only has minor effects on the application. It defines the memory
|
||||
// regions the application is loaded into (runtime-drivers need to be put into
|
||||
// reserved areas), as well as whether a return from the entry-point is treated as
|
||||
// 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
|
||||
.get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
|
||||
.unwrap()
|
||||
.extend(pre_link_args_msvc);
|
||||
|
||||
TargetOptions {
|
||||
disable_redzone: true,
|
||||
exe_suffix: ".efi".to_string(),
|
||||
allows_weak_linkage: false,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
stack_probes: true,
|
||||
singlethread: true,
|
||||
linker: Some("rust-lld".to_string()),
|
||||
// FIXME: This should likely be `true` inherited from `msvc_base`
|
||||
// because UEFI follows Windows ABI and uses PE/COFF.
|
||||
// The `false` is probably causing ABI bugs right now.
|
||||
is_like_windows: false,
|
||||
// FIXME: This should likely be `true` inherited from `msvc_base`
|
||||
// because UEFI follows Windows ABI and uses PE/COFF.
|
||||
// The `false` is probably causing ABI bugs right now.
|
||||
is_like_msvc: false,
|
||||
|
||||
..base
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args_crt = LinkArgs::new();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut pre_link_args = LinkArgs::new();
|
|
@ -1,36 +1,30 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
|
||||
use std::default::Default;
|
||||
use crate::spec::TargetOptions;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let pre_args = vec!["/NOLOGO".to_string(), "/NXCOMPAT".to_string()];
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(LinkerFlavor::Msvc, pre_args.clone());
|
||||
args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_args);
|
||||
let base = super::msvc_base::opts();
|
||||
|
||||
TargetOptions {
|
||||
function_sections: true,
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
dll_prefix: String::new(),
|
||||
dll_suffix: ".dll".to_string(),
|
||||
exe_suffix: ".exe".to_string(),
|
||||
staticlib_prefix: String::new(),
|
||||
staticlib_suffix: ".lib".to_string(),
|
||||
target_family: Some("windows".to_string()),
|
||||
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: args,
|
||||
crt_static_allows_dylibs: true,
|
||||
crt_static_respected: true,
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
requires_uwtable: true,
|
||||
// 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.
|
||||
no_default_libraries: false,
|
||||
|
||||
..Default::default()
|
||||
..base
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
use std::default::Default;
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let base = super::windows_gnu_base::opts();
|
||||
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
let mut pre_link_args = LinkArgs::new();
|
||||
pre_link_args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
|
@ -14,7 +16,10 @@ pub fn opts() -> TargetOptions {
|
|||
],
|
||||
);
|
||||
|
||||
// FIXME: This should be updated for the exception machinery changes from #67502.
|
||||
let mut late_link_args = LinkArgs::new();
|
||||
let late_link_args_dynamic = LinkArgs::new();
|
||||
let late_link_args_static = LinkArgs::new();
|
||||
late_link_args.insert(
|
||||
LinkerFlavor::Gcc,
|
||||
vec![
|
||||
|
@ -33,31 +38,17 @@ pub fn opts() -> TargetOptions {
|
|||
);
|
||||
|
||||
TargetOptions {
|
||||
// FIXME(#13846) this should be enabled for windows
|
||||
function_sections: false,
|
||||
linker: Some("gcc".to_string()),
|
||||
dynamic_linking: true,
|
||||
executables: false,
|
||||
dll_prefix: String::new(),
|
||||
dll_suffix: ".dll".to_string(),
|
||||
exe_suffix: ".exe".to_string(),
|
||||
staticlib_prefix: "lib".to_string(),
|
||||
staticlib_suffix: ".a".to_string(),
|
||||
target_family: Some("windows".to_string()),
|
||||
is_like_windows: true,
|
||||
allows_weak_linkage: false,
|
||||
limit_rdylib_exports: false,
|
||||
pre_link_args,
|
||||
pre_link_objects_exe: vec![
|
||||
"rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs
|
||||
],
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
pre_link_objects_exe: vec!["rsbegin.o".to_string()],
|
||||
// FIXME: Consider adding `-nostdlib` and inheriting from `windows_gnu_base`.
|
||||
pre_link_objects_dll: vec!["rsbegin.o".to_string()],
|
||||
late_link_args,
|
||||
post_link_objects: vec!["rsend.o".to_string()],
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
requires_uwtable: true,
|
||||
limit_rdylib_exports: false,
|
||||
late_link_args_dynamic,
|
||||
late_link_args_static,
|
||||
|
||||
..Default::default()
|
||||
..base
|
||||
}
|
||||
}
|
|
@ -1,37 +1,14 @@
|
|||
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};
|
||||
use std::default::Default;
|
||||
use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions};
|
||||
|
||||
pub fn opts() -> TargetOptions {
|
||||
let mut args = LinkArgs::new();
|
||||
args.insert(
|
||||
LinkerFlavor::Msvc,
|
||||
vec![
|
||||
"/NOLOGO".to_string(),
|
||||
"/NXCOMPAT".to_string(),
|
||||
"/APPCONTAINER".to_string(),
|
||||
"mincore.lib".to_string(),
|
||||
],
|
||||
);
|
||||
let mut opts = super::windows_msvc_base::opts();
|
||||
|
||||
TargetOptions {
|
||||
function_sections: true,
|
||||
dynamic_linking: true,
|
||||
executables: true,
|
||||
dll_prefix: String::new(),
|
||||
dll_suffix: ".dll".to_string(),
|
||||
exe_suffix: ".exe".to_string(),
|
||||
staticlib_prefix: String::new(),
|
||||
staticlib_suffix: ".lib".to_string(),
|
||||
target_family: Some("windows".to_string()),
|
||||
is_like_windows: true,
|
||||
is_like_msvc: true,
|
||||
pre_link_args: args,
|
||||
crt_static_allows_dylibs: true,
|
||||
crt_static_respected: true,
|
||||
abi_return_struct_as_int: true,
|
||||
emit_debug_gdb_scripts: false,
|
||||
requires_uwtable: true,
|
||||
let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "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))
|
||||
.unwrap()
|
||||
.extend(pre_link_args_msvc);
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
opts
|
||||
}
|
||||
|
|
|
@ -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 = "x86-64".to_string();
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
|
||||
base.max_atomic_width = Some(64);
|
||||
|
|
|
@ -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 = "x86-64".to_string();
|
||||
base.max_atomic_width = Some(64);
|
||||
|
||||
|
@ -28,11 +28,6 @@ pub fn target() -> TargetResult {
|
|||
// places no locality-restrictions, so it fits well here.
|
||||
base.code_model = Some("large".to_string());
|
||||
|
||||
// UEFI mirrors the calling-conventions used on windows. In case of x86-64 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;
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "x86_64-unknown-windows".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
|
|
@ -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 = "x86-64".to_string();
|
||||
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
|
||||
base.max_atomic_width = Some(64);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue