1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
// 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::{base, LinkerFlavor, Lld, PanicStrategy, StackProbeType, TargetOptions};
pub fn opts() -> TargetOptions {
let mut base = base::msvc::opts();
base.add_pre_link_args(
LinkerFlavor::Msvc(Lld::No),
&[
// 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",
// 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",
],
);
TargetOptions {
os: "uefi".into(),
linker_flavor: LinkerFlavor::Msvc(Lld::Yes),
disable_redzone: true,
exe_suffix: ".efi".into(),
allows_weak_linkage: false,
panic_strategy: PanicStrategy::Abort,
// LLVM does not emit inline assembly because the LLVM target does not get considered as…
// "Windows".
stack_probes: StackProbeType::Call,
singlethread: true,
linker: Some("rust-lld".into()),
entry_name: "efi_main".into(),
..base
}
}