自动初始化

简介

mr-auto-init 模块为 mr-library 项目下的可裁剪模块,以C语言编写,可快速移植到各种平台(主要以嵌入式mcu为主)。
mr-auto-init 模块通过隐式调用初始化函数,使代码更简介更模块化。

自动初始化

常规调用初始化函数都是在 main 函数前单独调用,使得程序非常冗长同时高度耦合,导致模块化困难。而自动初始化,因为其为隐式调用,使得程序非常简洁,高度解耦。在各类 RTOS 中自动初始化已经是较为常见的存在。

自动初始化的核心为编译器命令 __attribute__((section(x))) 这条指令会将修饰的函数添加到指定的同一块内存中,由于内存是连续的,让我们以指定的长度移动时便可将函数依次提取出来。

初始化函数类型

首先我们先定义一个初始化函数类型,需要强调的是,一旦确定这个函数类型,后续所有的初始化函数都应是此类型的。因为函数保存在一整块内存中,我们只有确定的函数类型才能正确的取出函数。

typedef int (*init_fn_t)(void);

优先级导出函数

__attribute__((section(x))) 这条指令虽然实现了自动初始化,但是并不能满足我们实际使用中,初始化需要按照优先级调用的需求,因此我们需要完善这个命令。

#define INIT_EXPORT(fn,level) \
    mr_used const init_fn_t _mr_init_##fn mr_section(".mri_fn."level) = fn

例如:

int init(void)
{
	printf("auto-init");
}
INIT_EXPORT(init, "1");

最终经过展开

__attribute__((used))const init_fn_t _mr_init_init __attribute__((section(".mri_fn." "1"))) = init

这个函数就被导出到了".mri_fn.1"这块空间。
当我们再导出一个函数到".mri_fn.2",当自动初始化时将先调用".mri_fn.1"中的函数再调用".mri_fn.2"中的函数。

获取初始化函数起始地址和初始化函数结束地址

static int mri_start(void)
{
  return 0;
}
INIT_EXPORT(mri_start, "0");

static int mri_end(void)
{
  return 0;
}
INIT_EXPORT(mri_end,"6.end");

创建两个函数,当我们取mri_start地址时我们将得到初始化函数起始地址,取mri_end地址时我们将得到初始化函数结束地址。

如何自动初始化

从函数起始地址开始取函数,调用完毕后向后移动,直到到达函数结束地址。

void mr_auto_init(void)
{
  volatile const init_fn_t *fn_ptr;

  /* auto-init-board */
  for (fn_ptr = &_mr_init_mri_start; fn_ptr < &_mr_init_mri_board_end; fn_ptr++)
  {
    (*fn_ptr)();
  }

  /* auto-init-other */
  for (fn_ptr = &_mr_init_mri_board_end; fn_ptr < &_mr_init_mri_end; fn_ptr++)
  {
    (*fn_ptr)();
  }
}

使用示例

/* -------------------- 模拟需要导出的初始化函数 -------------------- */

int board_init(void)
{
  printf("auto-init: board\r\n");
  return 0;
}
INIT_BOARD_EXPORT(board_init);

int device_init(void)
{
  printf("auto-init: device\r\n");
  return 0;
}
INIT_DEVICE_EXPORT(device_init);

int env_init(void)
{
  printf("auto-init: env\r\n");
  return 0;
}
INIT_ENV_EXPORT(env_init);

int app_init(void)
{
  printf("auto-init: app\r\n");
  return 0;
}
INIT_APP_EXPORT(app_init);

/* -------------------- 使用 -------------------- */

int main(void)
{
    /* 初始化 */
    mr_auto_init();
    
    /* 用户代码 */
    ...
}

注意事项

当您使用中出现功能无法实现并且您的编译器为 GCC 时,请您手动在 link.ld / SECTIONS / .text 中添加以下代码。

/* section information for initial. */
. = ALIGN(4);
_mr_init_ = .;
KEEP(*(SORT(.mri_fn*)))
_mr_init__end = .;

剩余底层代码位于开源代码中,请下载开源代码。

开源代码

仓库链接(https://gitee.com/chen-fanyi/mr-library.git)
路径:master/mr-library/ device / mr_auto_init
或者给我发email:macrsh@outlook.com

请仔细阅读README.md !!!!!

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值