diff --git a/src/librustc_target/spec/uefi_base.rs b/src/librustc_target/spec/uefi_base.rs index 5078d500679d1..631966c09a498 100644 --- a/src/librustc_target/spec/uefi_base.rs +++ b/src/librustc_target/spec/uefi_base.rs @@ -5,7 +5,7 @@ // 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 +// 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. @@ -21,7 +21,10 @@ pub fn opts() -> TargetOptions { "/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. + // 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 diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/src/librustc_target/spec/x86_64_unknown_uefi.rs index 9ac17a1693fb5..443479f55f04a 100644 --- a/src/librustc_target/spec/x86_64_unknown_uefi.rs +++ b/src/librustc_target/spec/x86_64_unknown_uefi.rs @@ -12,13 +12,15 @@ pub fn target() -> TargetResult { 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. + // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to + // enable these CPU features explicitly before their first use, otherwise their instructions + // will trigger an exception. Rust does not inject any code that enables AVX/MMX/SSE + // instruction sets, so this must be done by the firmware. However, existing firmware is known + // to leave these uninitialized, thus triggering exceptions if we make use of them. Which is + // why we avoid them and instead use soft-floats. This is also what GRUB and friends did so + // far. + // If you initialize FP units yourself, you can override these flags with custom linker + // arguments, thus giving you access to full MMX/SSE acceleration. 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 @@ -26,9 +28,9 @@ pub fn target() -> TargetResult { // 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. + // 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 {