UEFI Application Binaries vs Standard PE Executables
At a foundational level, UEFI application binaries adopt the Microsoft Portable Executable/Common Object File Format (PE/COFF or PE32+) structure, but they serve an entirely different execution environment than standard Windows PE executables. While standard PE files rely on an operating system kernel, dynamic link libraries (DLLs), and user-mode subsystems, UEFI binaries operate directly on bare-metal firmware. This fundamental difference shapes how the PE headers are populated, how memory relocation is handled, and how APIs are linked and invoked.
The Subsystem Field
The most explicit structural difference within the file header is
located in the PE Optional Header's Subsystem field.
Standard Windows executables typically declare:
IMAGE_SUBSYSTEM_WINDOWS_GUI(value2)IMAGE_SUBSYSTEM_WINDOWS_CUI(value3, for command-line programs)
UEFI images target specific pre-boot environments and must declare one of the following subsystem values:
IMAGE_SUBSYSTEM_EFI_APPLICATION(value10): A standalone program that unloads when it exits.IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER(value11): A driver that remains resident until the OS loader callsExitBootServices().IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER(value12): A driver that remains in memory even after the operating system boots.IMAGE_SUBSYSTEM_EFI_ROM(value13): Firmware intended to be executed from a ROM chip.
The UEFI firmware boot manager inspects this field to determine memory allocation rules, execution lifetime, and permission boundaries before running the image.
Import and Export Tables
Standard PE executables rely heavily on the Import Address Table
(IAT) to link against user-space dynamic libraries such as
ntdll.dll or kernel32.dll. The Windows loader
resolves these external symbols dynamically at runtime.
In contrast, UEFI binaries do not use an external dynamic linker or OS-provided DLLs. As a result:
- The Import Table is generally absent, empty, or unpopulated.
- UEFI applications access system APIs through function pointers
provided in the
EFI_SYSTEM_TABLEstructure passed directly to the binary's entry point. - Communication between different UEFI modules occurs via "Protocols" discovered dynamically at runtime through GUID lookups rather than named PE imports.
Relocation Section Requirements
While modern 64-bit Windows PE files can sometimes omit base
relocations if they support fixed base addresses, the relocation section
(.reloc) is strictly mandatory for UEFI binaries.
UEFI firmware initializes memory dynamically at boot. Because memory
layouts vary significantly between hardware platforms and motherboard
designs, the firmware can load a binary at virtually any arbitrary
physical memory address. The UEFI image loader requires base relocation
data to patch absolute addresses in the code during load time; a UEFI
binary missing its .reloc section will fail to execute.
Entry Point Signature and Calling Convention
Standard PE binaries compile to an entry point that expects
conventional C runtime initialization (such as
mainCRTStartup or WinMainCRTStartup), which
sets up thread environments, handles, and command-line arguments.
A UEFI binary requires a standardized entry point adhering to the UEFI specification:
EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable);The binary's headers point to this function, which takes an image handle and a pointer to the system table as parameters. The standard Microsoft x64 calling convention is preserved in 64-bit UEFI binaries, ensuring CPU register consistency during function calls even before an operating system is present.
Execution Environment Constraints
Standard PE executables are mapped into isolated virtual address spaces using paging mechanisms managed by the OS kernel, generally executing in Ring 3 (User Mode).
UEFI application binaries execute in Ring 0 (Privileged Mode) on flat, identity-mapped physical memory. They possess direct access to CPU control registers, I/O ports, and hardware devices, operating without the thread management, security tokens, or memory isolation native to conventional PE execution.