--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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. Not 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 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.
+ "/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,
+ singlethread: true,
+ emit_debug_gdb_scripts: false,
+
+ linker: Some("lld-link".to_string()),
+ lld_flavor: LldFlavor::Link,
+ pre_link_args,
+
+ .. Default::default()
+ }
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This defines the amd64 target for UEFI systems as described in the UEFI specification. See the
+// uefi-base module for generic UEFI options. On x86_64 systems (mostly called "x64" in the spec)
+// UEFI systems always run in long-mode, have the interrupt-controller pre-configured and force a
+// single-CPU execution.
+// The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
+// LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
+
+use spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::uefi_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.max_atomic_width = Some(64);
+
+ // We disable MMX and SSE for now. UEFI does not prevent these from being used, but there have
+ // been reports to GRUB that some firmware does not initialize the FP exception handlers
+ // properly. Therefore, using FP coprocessors will end you up at random memory locations when
+ // you throw FP exceptions.
+ // To be safe, we disable them for now and force soft-float. This can be revisited when we
+ // have more test coverage. Disabling FP served GRUB well so far, so it should be good for us
+ // as well.
+ base.features = "-mmx,-sse,+soft-float".to_string();
+
+ // UEFI systems run without a host OS, hence we cannot assume any code locality. We must tell
+ // LLVM to expect code to reference any address in the address-space. The "large" code-model
+ // places no locality-restrictions, so it fits well here.
+ base.code_model = Some("large".to_string());
+
+ // UEFI mostly 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(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:w-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+ target_os: "uefi".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ arch: "x86_64".to_string(),
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+
+ options: base,
+ })
+}