* Since the code model only applies to the code and not the data and the code model
only applies to functions you call through using `call`, `jmp` and data with `lea`, etc…
If you are calling functions using the function pointers from the UEFI structures the code
model does not apply in that case. It’s just related to the address space size of your own binary.
Since UEFI (uefi is all relocatable) uses relocatable PEs (relocatable code does not care about the
code model) so, we use the small code model here.
* Since applications don't usually take gigabytes of memory, setting the
target to use the small code model should result in better codegen (comparable
with majority of other targets).
Large code models are also known for generating horrible code, for
example 16 bytes of code to load a single 8-byte value.
* Use the LLVM default code model for the architecture for the
x86_64-unknown-uefi targets. For reference small is the default
code model on x86 in LLVM: <7de2173c2a/llvm/lib/Target/X86/X86TargetMachine.cpp (L204)
>
* Remove the comments too as they are not UEFI-specific and applies
to pretty much any target. I added them before as I was explicitily
setting the code model to small.
Signed-off-by: Andy-Python-Programmer <andypythonappdeveloper@gmail.com>
37 lines
1.8 KiB
Rust
37 lines
1.8 KiB
Rust
// 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 crate::spec::Target;
|
|
|
|
pub fn target() -> Target {
|
|
let mut base = super::uefi_msvc_base::opts();
|
|
base.cpu = "x86-64".to_string();
|
|
base.max_atomic_width = Some(64);
|
|
|
|
// 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();
|
|
|
|
Target {
|
|
llvm_target: "x86_64-unknown-windows".to_string(),
|
|
pointer_width: 64,
|
|
data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
|
.to_string(),
|
|
arch: "x86_64".to_string(),
|
|
|
|
options: base,
|
|
}
|
|
}
|