1. U-Boot版本
1VERSION = 2021
2PATCHLEVEL = 10
3SUBLEVEL =
4EXTRAVERSION =
5NAME =
2. 涉及的文件
include/_exports.h
,辅助文件,在包含_exports.h
前,定义不同的EXPORT_FUNC
来实现不同的功能,其内容为一系列EXPORT_FUNC
修饰的函数。include/exports.h
,函数声明。examples/standalone/stubs.c
,用于建立jumptable
,将U-Boot的函数指针存入jumptable
中。common/exports.c
,初始化jumptable
。examples/standalone/hello_world.c
,独立于U-Boot的程序代码,编译目标文件为单独的bin,可以调用U-Boot的函数。
类似的还有kernel
的include/uapi/asm-generic/unistd.h
文件(以v5.15为例)。
3. 原理
EXPORT_FUNC
巧妙的借助了C语言中的宏来实现,通过对同一个宏进行不同的定义,使得编译器在预处理阶段产生不同的代码,使用尽量少的代码来实现不同的功能。
在包含_exports.h
前,定义不同的EXPORT_FUNC
。
3.1. include/exports.h
1struct jt_funcs {
2#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__);
3#include <_exports.h>
4#undef EXPORT_FUNC
5};
3.2. common/exports.c
1#define EXPORT_FUNC(f, a, x, ...) gd->jt->x = f;
2
3int jumptable_init(void)
4{
5 gd->jt = malloc(sizeof(struct jt_funcs));
6#include <_exports.h>
7
8 return 0;
9}
3.3. examples/standalone/stubs.c
1#ifdef CONFIG_ARM64
2/*
3 * x18 holds the pointer to the global_data, x9 is a call-clobbered
4 * register
5 */
6#define EXPORT_FUNC(f, a, x, ...) \
7 asm volatile ( \
8" .globl " #x "\n" \
9#x ":\n" \
10" ldr x9, [x18, %0]\n" \
11" ldr x9, [x9, %1]\n" \
12" br x9\n" \
13 : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x9");
14#else
15/*
16 * r9 holds the pointer to the global_data, ip is a call-clobbered
17 * register
18 */
19#define EXPORT_FUNC(f, a, x, ...) \
20 asm volatile ( \
21" .globl " #x "\n" \
22#x ":\n" \
23" ldr ip, [r9, %0]\n" \
24" ldr pc, [ip, %1]\n" \
25 : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip");
26#endif
27
28void __attribute__((unused)) dummy(void)
29{
30#include <_exports.h>
31}