UEFI应用必须使用efi_main作为入口函数而非main,签名固定为EFI_STATUS efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE),需extern "C"声明、返回EFI_状态码,并依赖Uefi.h及EDK II构建系统。

UEFI应用必须用 efi_main 入口,不是 main
UEFI环境不认标准C++的 main 函数,链接时会报 undefined reference to 'main' 或直接启动失败。所有UEFI应用的真正入口是 efi_main,签名固定为:EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)。
- 必须在源文件中显式定义这个函数,且不能加
static或inline - 编译器不会自动识别它——它不是约定俗成的,而是UEFI PE/COFF加载器硬编码查找的符号名
- 如果用了C++,需用
extern "C"包裹声明,否则C++ name mangling会导致找不到入口:extern "C" EFI_STATUS efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE*);
- 返回值必须是
EFI_SUCCESS或其他EFI_*状态码,返回任意整数(如0)可能被UEFI解释为错误并终止执行
头文件和链接依赖不能靠标准libc,得用 Uefi.h + MdePkg
你写的代码里出现 #include 或 #include 就已经走错路了。UEFI没有POSIX环境,也没有STL运行时支持,所有API都来自EDK II提供的固件抽象层。
- 必须包含
#include,它定义了EFI_STATUS、EFI_HANDLE等核心类型 - 常用服务如打印、内存分配,要额外包含
#include和#include - 编译时不能链接
-lc或-lstdc++;EDK II构建系统(build命令)会自动链接MdePkg提供的精简CRT实现,比如UefiApplicationEntryPoint - 若手动用clang/g++交叉编译,必须指定
--target=x86_64-unknown-elf并链接EDK II提供的UefiApplicationEntryPoint.lib,否则即使函数名对了也进不了efi_main
字符串、内存、调试输出全得用UEFI原生方式
习惯用 std::string 或 printf 的人,在UEFI里第一分钟就会卡住:没有堆管理器自动初始化,没有格式化IO,连字符串都是 CHAR16*(UTF-16)。
- 打印用
Print(L"Hello World\n"),注意是大写L"",不是" ";传char*会乱码或崩溃 - 申请内存必须调
gBS->AllocatePool(),不能用new或malloc;UEFI不提供全局堆,new默认调用的分配器未初始化 -
std::vector、std::map等模板无法使用——它们依赖异常、RTTI和动态内存,而UEFI默认关闭这些特性(NO_EFI_RUNTIME、DISABLE_NEW_DELETE_OPERATORS) - 调试建议用
DEBUG((DEBUG_INFO, "Value: %x\n", Value)),但需确保DSC文件中启用了DEBUG_PRINT_ENABLED = TRUE,否则这行什么也不输出
构建必须走EDK II工具链,别试图用CMake直接生成PE32+
UEFI应用不是普通可执行文件,它必须是PE32+格式、带特定section(如 .reloc)、入口地址对齐到4KB,并嵌入UEFI所需的子系统标识(SUBSYSTEM:EFI_APPLICATION)。手工配置链接脚本极易出错。
- 必须用EDK II的
build工具,基于.inf描述文件驱动构建流程;.inf中要明确写BASE_NAME = HelloWorldApp和MODULE_TYPE = UEFI_APPLICATION - 不要在CMakeLists.txt里写
add_executable(...)然后指望它能启动——即使生成了 .efi 文件,也可能因重定位信息缺失、导入表为空或入口偏移错位被UEFI固件拒绝加载 - 常见错误现象:
LoadImage() failed: Unsupported,大概率是PE头校验失败或架构不匹配(比如用x86_64工具链编译却放到AArch64平台运行) - 调试构建问题最有效的办法是:用
GenFw工具检查生成的 .efi 文件:GenFw -d HelloWorldApp.efi,确认Machine字段和Entry Point是否符合目标平台要求
UEFI开发里最容易被忽略的,是“每个平台的 gBS 地址在每次启动时都不一样”,所以任何把 Boot Services 表地址硬编码、保存到非易失存储、或者跨启动周期复用的行为,都会在真实机器上静默失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











