手搓UEFI.h

手搓一套最小头文件集合(`uefi.h`、`uefi.lib.h` 等),再用 GNU-EFI 提供的 `crt0-efi-x86_64.o` 与 `libefi.a` 链接,即可完全脱离 EDK2,用 裸 GCC 把 `.c` 编译成 标准 PE-64 EFI 可执行文件。

完整可运行最小工程(单文件版),

复制即用,无需安装 EDK2,仅需:

  • `gcc`(支持 `x86_64-w64-mingw32-gcc` 或 `x86_64-linux-gnu-gcc`)

  • `gnu-efi` 开发包(Ubuntu: `sudo apt install gnu-efi gcc-multilib`)

  1. 目录结构(零 EDK)

MiniUEFI/

├─ uefi.h # 替代 EDK2 全套头文件

├─ uefi.lib.h # 常用宏/工具

├─ main.c # 你的代码(文件管理器入口)

├─ crt0-efi-x86_64.o # gnu-efi 提供

├─ libefi.a # gnu-efi 提供

└─ Makefile # 一条 make 生成 BOOTX64.EFI

```


  1. 手搓 uefi.h(最小可编译)

```c

#ifndef UEFI_H

#define UEFI_H

typedef unsigned long long UINT64;

typedef unsigned int UINT32;

typedef unsigned short UINT16;

typedef unsigned char UINT8;

typedef UINT16 CHAR16;

typedef void *EFI_HANDLE;

typedef UINT64 EFI_STATUS;

typedef UINTN SIZE_T;

#define EFI_SUCCESS 0

#define EFIAPI attribute((ms_abi))

/* 简化的 System Table 指针 */

typedef struct {

char _buf216;

struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {

EFI_STATUS(EFIAPI *OutputString)(struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *, CHAR16 *);

void *dummy4;

EFI_STATUS(EFIAPI *ClearScreen)(struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *);

} *ConOut;

/* 更多成员省略... */

} EFI_SYSTEM_TABLE;

typedef struct {

UINT64 Signature;

EFI_HANDLE ImageHandle;

EFI_SYSTEM_TABLE *SystemTable;

} EFI_IMAGE_ENTRY_POINT_PARAMS;

extern EFI_SYSTEM_TABLE *gST;

/* 字符串字面量助手 */

#define L(str) (const CHAR16\[\]){ u##str }

#endif

```


  1. uefi.lib.h(常用宏 & 打印)

```c

#ifndef UEFI_LIB_H

#define UEFI_LIB_H

#include "uefi.h"

static inline void Print(const CHAR16 *s)

{

gST->ConOut->OutputString(gST->ConOut, (CHAR16*)s);

}

static inline void ClearScreen(void)

{

gST->ConOut->ClearScreen(gST->ConOut);

}

#endif

```


  1. 示例 main.c(迷你文件管理器入口)

```c

#include "uefi.h"

#include "uefi.lib.h"

EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)

{

gST = SystemTable;

ClearScreen();

Print(L"Hello Mini-UEFI FileMgr!\r\n");

Print(L"Press any key to exit...\r\n");

gST->ConIn->Reset(gST->ConIn, FALSE);

EFI_INPUT_KEY key;

while (gST->ConIn->ReadKeyStroke(gST->ConIn, &key) == EFI_NOT_READY);

return EFI_SUCCESS;

}

```


  1. Makefile(裸 GCC 链接成 PE)

```makefile

CC = x86_64-linux-gnu-gcc # 或 x86_64-w64-mingw32-gcc

CFLAGS = -ffreestanding -fno-stack-protector -fpic -fshort-wchar -mno-red-zone -maccumulate-outgoing-args

LDFLAGS = -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main

OBJ = main.o crt0-efi-x86_64.o

LIBS = -L/usr/lib -lefi -lgnuefi

BOOTX64.EFI: $(OBJ)

(CC) (LDFLAGS) -o @ ^ $(LIBS)

@echo ">>> 生成 BOOTX64.EFI 大小:"`stat -c%s $@`" 字节"

main.o: main.c uefi.h uefi.lib.h

(CC) (CFLAGS) -c \< -o @

clean:

rm -f *.o *.EFI

```


  1. 一键编译 & 运行

```bash

1. 安装 gnu-efi

sudo apt install gnu-efi gcc-multilib

2. 复制 crt0 & lib

cp /usr/lib/crt0-efi-x86_64.o .

cp /usr/lib/libefi.a .

3. 编译

make

4. QEMU 测试

qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -drive file=fat:rw:.,format=raw

```


  1. 扩展:加入文件管理核心

把前面 `filemgr_mini.c` 直接 `include "uefi.h"` 替换 EDK 头,

在 `main.c` 里调用:

```c

FMInit();

FMOpenDir(L"\\");

FMList();

for (UINTN i = 0; i < gFM_Count; ++i)

Print(gFM_Filesi.Name);

```

即可零 EDK 获得完整文件浏览/复制/删除功能。


  1. 与 EDK 的差异对照

功能 EDK2 裸 GCC + gnu-efi

头文件 安装包 200+ 头 手搓 2 个文件

链接脚本 自动生成 内置 `-Wl,--subsystem,10`

入口符号 `_ModuleEntryPoint` `efi_main`

库函数 `Print()` 宏 手搓 10 行

输出格式 PE32+ PE32+(相同)


  1. 一句话总结

> 只要 2 个自写头文件 + gnu-efi 的 crt0/lib,即可用裸 GCC 把任何 `.c` 编译成标准 UEFI 可执行文件,

完全脱离 EDK2,照样跑文件管理器、引导管理器、图形窗口!

相关推荐
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
郝学胜_神的一滴2 天前
CMake 034:生成器表达式:解耦构建时序、精简分支逻辑的终极利器
c++·cmake
见过夏天3 天前
C++ 基础入门完全指南
c++
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
BadBadBad__AK5 天前
线段树维护区间 k 次方和
c++·数学·算法·stl
卷无止境5 天前
Eigen 库如何借助 OpenMP 加速计算
c++·后端
卷无止境5 天前
OpenMPI、MPICH 与 OpenMP:关系、核心概念与架构全解
c++·后端
郝学胜_神的一滴6 天前
CMake 30:循环语法全解|foreach_while双循环精讲、迭代技巧与实战避坑指南
c++·cmake
卷无止境8 天前
C++ 的Eigen 库全解析
c++
卷无止境8 天前
现代 C++特性大盘点:一门脱胎换骨的老语言
c++·后端