本帖最后由 我喜欢打游戏 于 2022-5-3 11:35 编辑
2、 自动初始化基于前面section的作用,可以将同类函数指针全部使用同一个段名修饰,然后开机后系统自动检索段内函数指针,逐个执行,对上层应用就是无需主动调用,系统自动初始化。 考虑到硬件初始化与应用功能初始化的先后顺序,可以对段名进行分配,map文件按段名排序。自动初始化主体是OS_INIT_EXPORT宏。 范例代码出自中国移动的oneos开源版本,使用gcc,方案和国产RT-Thread类似。 typedef os_err_t (*os_init_fn_t)(void);
#define OS_INIT_EXPORT(fn, level) \
const os_init_fn_t __os_call_##fn OS_SECTION(".init_call."level) = fn
#define OS_BOARD_INIT(fn) OS_INIT_EXPORT(fn, "1")
#define OS_PREV_INIT(fn) OS_INIT_EXPORT(fn, "2")
#define OS_DEVICE_INIT(fn) OS_INIT_EXPORT(fn, "3")
#define OS_CMPOENT_INIT(fn) OS_INIT_EXPORT(fn, "4")
#define OS_ENV_INIT(fn) OS_INIT_EXPORT(fn, "5")
#define OS_APP_INIT(fn) OS_INIT_EXPORT(fn, "6")
例如shell初始化函数,定义如下: OS_APP_INIT(sh_system_init);
将宏定义展开
/* 含义是函数指针 __os_call_sh_system_init
* 其指向sh_system_init函数,且该指针编译后放在".init_call.6"段
*/
const os_init_fn_t __os_call_sh_system_init
__attribute__((section((".init_call.6")))) = sh_system_init
系统自身也有自定义函数,用来标记起止点函数 OS_INIT_EXPORT(os_init_start, "0");//段起点__start
OS_INIT_EXPORT(os_board_init_start, "0.end");
OS_INIT_EXPORT(os_board_init_end, "1.end");
OS_INIT_EXPORT(os_init_end, "6.end");//段终点__stop
最终生成的map文件如下图:
//系统底层在合适的时机调用如下两函数,将指定段区间内的所有函数自动执行
void os_board_auto_init(void)
{
const os_init_fn_t *fn_ptr_board_init_start;
const os_init_fn_t *fn_ptr_board_init_end;
const os_init_fn_t *fn_ptr;
fn_ptr_board_init_start = &__os_call_os_board_init_start + 1;
fn_ptr_board_init_end = &__os_call_os_board_init_end - 1;
//将段首尾区间内的函数全部遍历执行
for (fn_ptr = fn_ptr_board_init_start; fn_ptr <= fn_ptr_board_init_end; fn_ptr++)
{
(void)(*fn_ptr)();
}
return;
}
static void os_other_auto_init(void)
{
const os_init_fn_t *fn_ptr_other_init_start;
const os_init_fn_t *fn_ptr_other_init_end;
const os_init_fn_t *fn_ptr;
fn_ptr_other_init_start = &__os_call_os_board_init_end + 1;
fn_ptr_other_init_end = &__os_call_os_init_end - 1;
for (fn_ptr = fn_ptr_other_init_start; fn_ptr <= fn_ptr_other_init_end; fn_ptr++)
{
(void)(*fn_ptr)();
}
return;
}
系统执行os_other_auto_init时实现了sh_system_init的自动执行,即使应用层没有显示的去调用它。使用符号段的方式实现初始化函数自动执行,应用层修改软件,增加功能启动或者裁剪,对底层代码无需任何改动。更多信息请关注微信公众号【嵌入式系统】。 注意:段中函数类型都是一样的,范例是同一类函数指针,也可以是结构体,需要确保每个成员占用空间大小相同,这样才能逐个遍历。
|