手搓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 _buf[216];

struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {

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

void *dummy[4];

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_Files[i].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,照样跑文件管理器、引导管理器、图形窗口!

相关推荐
杜子不疼.2 分钟前
【C++ AI 大模型接入 SDK】 - DeepSeek 模型接入(上)
开发语言·c++·chatgpt
石山代码1 小时前
C++ 内存分区 堆区
java·开发语言·c++
张小姐的猫3 小时前
【Linux】多线程 —— 线程互斥
linux·运维·服务器·c++
做人求其滴6 小时前
面试经典 150 题 380 274
c++·算法·面试·职场和发展·力扣
见叶之秋6 小时前
C++基础入门指南
开发语言·c++
计算机安禾6 小时前
【c++面向对象编程】第42篇:模板特化与偏特化:为特定类型定制实现
开发语言·c++·算法
玖釉-6 小时前
C++ 中的循环语句详解:while、do...while、for、嵌套循环与循环控制
开发语言·c++·算法
欧米欧7 小时前
C++进阶数据结构之搜索二叉树
开发语言·数据结构·c++
青小莫7 小时前
C++之vector讲解
c++·stl
计算机安禾8 小时前
【c++面向对象编程】第41篇:函数模板与类模板:泛型编程的基石
开发语言·c++·算法