2. 编写HelloWorld UEFI应用

任务目标

编写一个最小的UEFI应用程序,在UEFI Shell中运行时输出字符串 Hello, UEFI!,并编译生成可加载的 .efi 可执行文件。

环境与依赖

  • 操作系统:Linux(本文以Ubuntu为例)或Windows(需安装MSYS2)
  • 编译器:x86_64-w64-mingw32-gcc(MinGW-w64交叉编译器),用于生成PE32+格式的EFI可执行文件
  • UEFI头文件:gnu-efi 开发包(提供基本类型定义与协议接口声明)

Ubuntu安装命令:

sudo apt install gcc-mingw-w64-x86-64 gnu-efi

核心代码

以下代码使用GNU-EFI的封装方式,通过 efi_main 作为入口点,调用 Print 服务输出字符串,然后返回 EFI_SUCCESS 退出应用。

#include <efi.h>
#include <efilib.h>

EFI_STATUS
efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
    // 初始化GNU-EFI运行时库,使Print等辅助函数可用
    InitializeLib(ImageHandle, SystemTable);

    // 输出字符串到UEFI控制台
    Print(L"Hello, UEFI!\r\n");

    // 返回成功状态,应用正常退出
    return EFI_SUCCESS;
}

编译与运行

将上述代码保存为 hello.c,在同一目录下执行以下命令编译:

x86_64-w64-mingw32-gcc -c -I/usr/include/efi -I/usr/include/efi/x86_64 \
    -fno-stack-protector -fpic -fshort-wchar -mno-red-zone -Wall hello.c
x86_64-w64-mingw32-ld -shared -Bsymbolic -L/usr/lib -T/usr/lib/elf_x86_64_efi.lds \
    -o hello.efi hello.o -lefi -lgcc

生成 hello.efi 后,将其复制到UEFI启动盘(FAT32格式)的 EFI/BOOT 目录下,或直接在UEFI Shell中通过文件系统访问该文件。

运行方式:

  • 在UEFI Shell中切换到文件所在分区(如 fs0:),执行 hello.efi;
  • 或将 hello.efi 作为启动项加载(需在固件设置中配置)。

验证方法

应用执行后,屏幕应显示一行文本 Hello, UEFI!,随后自动返回Shell提示符。若在OVMF(开源UEFI固件)虚拟机中测试,可直接在QEMU窗口中观察输出。

通过条件:控制台出现且仅出现一次 Hello, UEFI!,无错误码或崩溃信息。

常见问题

  • 编译报错找不到头文件:确认 -I 参数路径与gnu-efi安装位置一致,不同发行版路径可能为 /usr/include/efi 或 /usr/local/include/efi。
  • 链接失败:检查 -T 指定的链接脚本路径是否正确,该脚本由gnu-efi提供,用于生成PE32+格式。
  • 运行时无输出:确认 hello.efi 确实在UEFI环境(而非传统BIOS模式)下执行,且文件系统可被固件识别。