1. U-Boot版本

1VERSION = 2021
2PATCHLEVEL = 10
3SUBLEVEL =
4EXTRAVERSION =
5NAME =

2. 涉及的文件

  1. include/_exports.h,辅助文件,在包含_exports.h前,定义不同的EXPORT_FUNC来实现不同的功能,其内容为一系列EXPORT_FUNC修饰的函数。
  2. include/exports.h,函数声明。
  3. examples/standalone/stubs.c,用于建立jumptable,将U-Boot的函数指针存入jumptable中。
  4. common/exports.c,初始化jumptable
  5. examples/standalone/hello_world.c,独立于U-Boot的程序代码,编译目标文件为单独的bin,可以调用U-Boot的函数。

类似的还有kernelinclude/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}