手搓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,照样跑文件管理器、引导管理器、图形窗口!

相关推荐
LIZhang20162 小时前
基于ffmpeg8.0录制mp4文件
开发语言·c++
_OP_CHEN2 小时前
C++进阶:(九)深度剖析unordered_map 与 unordered_set容器
开发语言·c++·stl容器·哈希表·哈希桶·unordered_map·unordered_set
freedom_1024_3 小时前
LRU缓存淘汰算法详解与C++实现
c++·算法·缓存
无敌最俊朗@3 小时前
C++-Qt-音视频-基础问题01
开发语言·c++
折戟不必沉沙3 小时前
C++四种类型转换cast,其在参数传递时的作用
c++
kyle~3 小时前
C++---万能指针 void* (不绑定具体数据类型,能指向任意类型的内存地址)
开发语言·c++
誰能久伴不乏3 小时前
Linux 进程通信与同步机制:共享内存、内存映射、文件锁与信号量的深度解析
linux·服务器·c++
_F_y4 小时前
C++异常
c++
小龙报4 小时前
《算法通关指南:算法基础篇 --- 一维前缀和 — 1. 【模板】一维前缀和,2.最大子段和》
c语言·数据结构·c++·算法·职场和发展·创业创新·visual studio