UEFI 随笔 010 — EDK2 的 NULL Lib 聚合模式

声明:个人笔记,概不负责

无责声明:里面许多概念,零帧起步。个人博客,随口而谈,不是教程,概不负责。

一、一般性问题

通常组织一组 可扩展的 代码,需要回答 两个问题,
(1)如何标定个体?通常用一个 int 型常量(或 GUID,或 string,或没有标识)
(2)如何聚合?(数据结构?聚合方式、时机?使用方式?)

个体标识 由于其常量特性,通常可以安全的到处复制,从而达到共享、交换目的。
常量复制 是一切架构的基点——是的,无论多么花里胡哨的系统,这就是软件系统的『炁体源流』
聚合的方式、时机,五花八门。至少有两种:① 在代码构建时,静态聚合;② 在运行时,动态聚合。

《一人之下》——“术之尽头,炁体源流”

二、此情此景(NULL Lib 聚合模式)

EDK2 有一种,利用 LibraryClass 把代码聚合在一起的方法。(这是 EDK2 独有的,与 UEFI spec 无关)
这是一种(本质上的)动态聚合 的手法。我称为 NULL Lib 聚合模式

已知:
(1)铁定事实,所谓 EDK2 的 LibraryClass 就是(被 EDK2 精心打扮的)平凡的 C Library 而已。
(2)简化认知,所谓 EDK2 的各种 Module 就是(被 EDK2 精心打扮的)平凡的 PE 可执行文件而已。

形式上 动态聚合
(1)每一个 LibraryClass 都可以有个(被 EDK2 精心打扮的) Constructor 函数,
(2)这个 Constructor 会(被 EDK2 精心打扮地)在 Module 加载时 调用。【奇点 1】
(3)所以,可以在 Constructor 这里,执行 动态聚合 代码,把个体 注入 到 聚合数据结构。(本质上的,动态聚合)
(4)提醒:其实 LibraryClass 早已在 Module 链接时,融入到 Module 里了。

形式上 静态聚合
(1)EDK2 会在 DSC 文件中,确定 编译时、链接时 的所有参数。
(2)通常 Module 会使用 具名 LibraryClass 来指明依赖。
(3)而 可扩展的代码结构,会使用无名的 NULL 来,开放式注入 任意数量的 LibraryClass
(4)链接时,只有这些(用户选择的)NULL LibraryClass ,才会被 融入到 最终的 Module 中。

推论:
所以 NULL Lib 聚合模式,必然有以下特征
(1)在 LibraryClass 实现的 INF 文件中, 必然有 CONSTRUCTOR 定义【奇点 2】
(2)在 DSC 中,聚合点 Module 那里,必然有(大量的) NULL LibraryClass 无名绑定

《让子弹飞》——“此情此景,恰如彼时彼刻”(原片没有,经典的错误记忆)

三、奇点 连接

现在问题是,在【奇点 1】的地方,Module 怎么知道调用哪些 LibraryClass 的 Constructor 函数?
也就是讲,在【奇点 2】的地方,LibraryClass 怎么把自己定义的 Constructor 函数送到【奇点 1】处?(即 聚合)

EDK2 对【奇点 2】的答案,暴力而又简单——使用 Python 脚本直接生成一个 C 函数,这个 C 代码里 没有任何数据结构。
因为,但凡是通过 EDK2 的 INF 文件构建的 LibraryClasse 或 Module ,都会被 暴力注入一对 AutoGen.h 与 AutoGen.c 文件。
所以,EDK2 可以 从从容容地 动任何手脚,这也算比较朴素的 产生式编程吧。
那个所谓的“NULL Lib 聚合模式”, 自然而然地 溶解在“EDK2 精心打扮的 LibraryClass 机制中”

EDK2 对【奇点 1】的答案,则非常的手工——依赖码农的双手(如果将来 AI 没有灭掉码农的话)
每个 Module 都必须要有个(符合 PE 机制的?DXE 约定的?) 入口函数。
我们在 INF 中指定的 入口函数,其实不是真的入口,EDK2 会统一提供个 Wrapper 函数,作为真的入口函数。
在这个 Wrapper 函数里,EDK2 可以注入任何代码,我们自己提供的(自以为的)入口函数,其实只是 Wrapper 中的一行调用而已。
每个 Module 都必须在 INF 中 选择自己的 Wrapper 函数,就是(码农徒手指定的)各种花式的 EntryPoint
// TODO, 最好弄个 call stack 出来

image

image

四、经典案例

参考代码布局: https://github.com/microsoft/mu_tiano_platforms

image

image

image

五、动态聚合

image

image

image

六、结语

上面的案例中,引用了很多 DSC 文件,那只是为讲解方便, 而引用的人畜无害的 公开代码。
在 EDK2 构建中,构建一个 Platform 只能有一个 DSC 文件,这个 DSC 文件是 编译时、链接时 的唯一公知。
真正落地到自己项目,要看实际 Platform 用的 DSC 文件定义。

在这个 DSC 文件中,在聚合点 Moudle 上,运用 NULL Lib 聚合模式,可以自由组装所需 个体。
标准的 Shell 就是一个典型范例。

比如说:Platforms/QemuSbsaPkg/QemuSbsaPkg.dsc
参考代码布局: https://github.com/microsoft/mu_tiano_platforms

==== 好像也没什么说的,结束线

posted @ 2026-01-07 01:41  悠洋洋  阅读(21)  评论(0)    收藏  举报