arm64平台,2022uboot
编译:
在 menu "General setup"下勾选选config EXAMPLES: bool "Compile API examples"。编译完成后会在examples/standalone目录下生成hello_world.bin。将这个bin放在可执行地址,使用go命令跳转过去执行。当无.bss段时,这个bin可以在任意地址执行。
=> go 80000000
## Starting application at 0x80000000 ...
Example expects ABI version 9
Actual U-Boot ABI version 9
Hello World
argc = 1
argv[0] = "80000000"
argv[1] = "<NULL>"
Hit any key to exit ...
代码原理:
hello_world.c中
int hello_world(int argc, char *const argv[])
{
int i;
/* Print the ABI version */
app_startup(argv);
printf ("Example expects ABI version %d\n", XF_VERSION);
printf ("Actual U-Boot ABI version %d\n", (int)get_version());
printf ("Hello World\n");
printf ("argc = %d\n", argc);
for (i=0; i<=argc; ++i) {
printf ("argv[%d] = \"%s\"\n",
i,
argv[i] ? argv[i] : "<NULL>");
}
printf ("Hit any key to exit ... ");
while (!tstc())
;
/* consume input */
(void) getc();
printf ("\n\n");
return (0);
}
其中 app_startup(argv)功能为清零BSS段。
通过反汇编可以知道,其他printf,tstc,getc等函数并不是真正在helloworld.bin中实现了;都是一层封装函数,先获取gd中的固定偏移地址,再从此偏移地址的某个偏移获取对应函数的地址,并跳转。对照代码可以看到使用的是gd里保存的jt结构体。
struct jt_funcs *jt; 初始化在common\exports.c中:
#define EXPORT_FUNC(f, a, x, ...) gd->jt->x = f;
void jumptable_init(void)
{
gd->jt = malloc(sizeof(struct jt_funcs));
#include <_exports.h>
}
结构体定义在include\exports.h中:
struct jt_funcs {
#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__);
#include <_exports.h>
#undef EXPORT_FUNC
};
可以看到,正在这两个文件中,EXPORT_FUNC宏定义不同,因此<_exports.h>头文件展开之后的作用也不同;在include\exports.h中是完成jt_funcs结构体,将一系列函数指针加入到为该结构体成员中。在common\exports.c则是对结构体成员进行赋值。
在examples\stanalone\stubs.c中,EXPORT_FUNC宏定义不同又有不同。展开之后就是从gd->jt中获取函数地址并跳转的流程。在这个文件中的作用是将需要用的函数制作出同名的封装函数。
/*
* x18 holds the pointer to the global_data, x9 is a call-clobbered
* register
*/
#define EXPORT_FUNC(f, a, x, ...) \
asm volatile ( \
" .globl " #x "\n" \
#x ":\n" \
" ldr x9, [x18, %0]\n" \
" ldr x9, [x9, %1]\n" \
" br x9\n" \
: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x9");
void __attribute__((unused)) dummy(void)
{
#include <_exports.h>
}
通过以上代码的分析可以得出,想在hello_world.c中调用其他函数,只需要在include\_exports.h中添加对应函数的EXPORT_FUNC宏声明,再在include\exports.h中添加函数声明。