0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

自动初始化机制原理详解

玩转单片机 来源:玩转单片机 2023-12-16 09:33 次阅读

自动初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。这篇文章就来探索一下其中的奥秘, 简单理解其原理!

|知识点补充

__attribute__((section(x)))是GNU C的一个特色之一,它可以用于将变量或函数放置在指定的段中。例如,你可以使用__attribute__((section(".my_section")))将变量或函数放置在名为my_section的段中。这对于嵌入式系统编程操作系统内核编程非常有用。

__attribute__((used))是GCC编译器提供的一个特性,用于告诉编译器在目标文件中保留一个静态变量或函数,即使它没有被引用。这样可以避免链接器删除未使用的节,或者确保某些特定的变量或函数被输出。

__attribute__((unused))是GCC编译器提供的一个特性,用于告诉编译器某个变量或函数可能未被使用,从而避免编译器产生未使用变量或函数的警告。在变量或函数前加上__attribute__((unused))即可使用该特性。

__attribute__((aligned(n)))是GCC编译器提供的一个特性,用于设置变量、类型、函数的对齐方式。它的作用是告诉编译器在分配内存空间时,要求以n个字节为边界。

__attribute__((weak))是GCC编译器提供的一个特性,用于声明或定义一个弱符号(weak symbol)。弱符号是指在链接时,如果存在同名的强符号(strong symbol),则会被强符号覆盖。

a67dabf8-9ba6-11ee-8b88-92fbcf53809c.png

| 原理研究

深入研究了一下, 发现这样使用宏真的很奇妙, 这里就简单介绍一下原理:

export.h文件

#ifndef__EXPORT_H
#define__EXPORT_H

#defineEXPORT_USED__attribute__((used))
#defineEXPORT_SECTION(x)__attribute__((section(x)))

typedefint(*export_init_fn_t)(void);

#defineEXPORT_INIT_EXPORT(fn,level)
EXPORT_USEDconstexport_init_fn_t__export_call_##fnEXPORT_SECTION(".export_call."level)=fn

//板级初始化顺序1
#defineEXPORT_BOARD_INIT(fn)EXPORT_INIT_EXPORT(fn,"1")

//设备初始化顺序3
#defineEXPORT_DEVICE_INIT(fn)EXPORT_INIT_EXPORT(fn,"2")

//组件初始化顺序4
#defineEXPORT_COMPONENT_INIT(fn)EXPORT_INIT_EXPORT(fn,"3")

//环境初始化顺序5
#defineEXPORT_ENV_INIT(fn)EXPORT_INIT_EXPORT(fn,"4")

//APP初始化顺序6
#defineEXPORT_APP_INIT(fn)EXPORT_INIT_EXPORT(fn,"5")

voidexport_components_init(void);

#endif

export.c文件

#include"export.h"
#include"stdio.h"

staticinttest_0_start(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_start,"0");

staticinttest_0_0(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_0,"0");

staticinttest_0_1(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_1,"0");

staticinttest_0_end(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_end,"0.end");

staticinttest_1_start(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_start,"1");

staticinttest_1_0(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_0,"1");

staticinttest_1_1(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_1,"1");

staticinttest_1_end(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_end,"1.end");

//自动初始化(在main函数调用)
voidexport_components_init(void)
{
printf("pfn1:%p
",&__export_call_test_0_start);
printf("pfn2:%p
",&__export_call_test_0_0);
printf("pfn3:%p
",&__export_call_test_0_1);
printf("pfn4:%p
",&__export_call_test_0_end);

printf("pfn5:%p
",&__export_call_test_1_start);
printf("pfn6:%p
",&__export_call_test_1_0);
printf("pfn7:%p
",&__export_call_test_1_1);
printf("pfn8:%p
",&__export_call_test_1_end);

volatileconstexport_init_fn_t*pfn;
for(pfn=&__export_call_test_0_start;pfn< &__export_call_test_1_end; pfn++)
    {
        printf("%p
", pfn);
        // (*pfn)();
    }
}

结果输出:

pfn1:08000c50
pfn2:08000c54
pfn3:08000c58
pfn4:08000c5c
pfn5:08000c60
pfn6:08000c64
pfn7:08000c68
pfn8:08000c6c
08000c50
08000c54
08000c58
08000c5c
08000c60
08000c64
08000c68

过程分析:

这个测试代码片段主要定义和使用了两个段,每个段定义了开始和结束,并且在开始和结束间插入了若干个函数,通过观察地址的变化会发现, 它们是按规律递增的,就可以使用遍历来调用指针指向的函数, 从而实现自动初始化外设的目的.

细节分析:

//定义一个函数指针
typedefint(*export_init_fn_t)(void);

//宏定义
#defineEXPORT_INIT_EXPORT(fn,level)
EXPORT_USEDconstexport_init_fn_t__export_call_##fnEXPORT_SECTION(".export_call."level)=fn

//假设调用
EXPORT_INIT_EXPORT(test_1_0,"1");

//一顿操作后,内存就存在了一个export_init_fn_t__export_call_test_1_0存放在".export_call."的输入段中,并指定其属于第一级初始化段
//就可以通过指针调用指针指向的函数来调用指定的函数,实现自动化初始化

|EventOS的EXPORT

这个先待定, 后续有时间再移植,export需要参考elab,涉及到assertcommonexportlog,感兴趣的读者可以参考:

a68b86ec-9ba6-11ee-8b88-92fbcf53809c.png

链接//gitee.com/event-os/eventos/tree/dev_df/examples/stm32g070

使用了export机制可以让代码变得更加简洁,感兴趣的读者可以在理解原理后进行完善和优化.

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • GCC
    GCC
    +关注

    关注

    0

    文章

    104

    浏览量

    24716
  • 开源
    +关注

    关注

    3

    文章

    2985

    浏览量

    41718
  • 函数
    +关注

    关注

    3

    文章

    3868

    浏览量

    61309
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48614
  • 宏定义
    +关注

    关注

    0

    文章

    48

    浏览量

    8927

原文标题:开源探索|EventOS之自动初始化

文章出处:【微信号:玩转单片机,微信公众号:玩转单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    RT-Thread自动初始化详解

    我们知道,在写裸机程序时,当我们完成硬件初始化后,就需要在主函数中进行调用。当我们使用RT-Thread后,完全不需要这样做了,我们可以将硬件等自动初始化。 RT-Thread 自动
    的头像 发表于 06-25 21:38 9561次阅读
    RT-Thread<b class='flag-5'>自动</b><b class='flag-5'>初始化</b><b class='flag-5'>详解</b>

    求蓝牙协议栈初始化和调度机制资料?

    青云NRF51822/NRF52832蓝牙4.x详解第二讲:蓝牙协议栈初始化和调度机制对应蓝牙协议栈的初始化一直是大家关注的问题,Nordic的协议栈如何运行,如何处理成为关键。本文并
    发表于 06-19 09:00

    蓝牙广播初始化详解

    第一讲 讲述了蓝牙样例的建立,第二讲 描述了协议栈初始化,本讲讲探讨下广播初始化问题:具体教程如下,兼容52系列:宝贝链接点击具体教程如下,兼容52系列:宝贝链接点击青风手把手教你学蓝牙34:蓝牙
    发表于 07-20 04:26

    STM32串口初始化与使用详解

    STM32串口初始化与使用详解串口简介串口初始化具体步骤串口收发理论代码执行串口简介USART(Universal Synchronous/Asynchronous Receiver
    发表于 08-19 06:06

    STM32CubeMX双缓冲机制初始化怎么实现?

    STM32CubeMX双缓冲机制初始化怎么实现?
    发表于 12-08 06:30

    USART初始化结构体详解

    USART 初始化结构体详解标准库函数对每个外设都建立了一个初始化结构体,比如USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如USART
    发表于 02-22 06:08

    RT-Thread自动初始化机制简介

    RT-Thread 的时钟管理以时钟节拍为基础,时钟节拍是 RT-Thread 操作系统中最小的RT-Thread 自动初始化机制时钟单位。RT-Thread 的定时器提供两类定时器机制
    发表于 04-06 18:08

    RT-Thread系统自动初始化机制简介

    RT-Thread 自动初始化机制1、自动初始化机制简介在系统启动流程图中,有两个函数:rt_c
    发表于 04-12 17:43

    EasyFlash+ulog自动初始化的问题与解决办法介绍

    INIT_APP_EXPORT这个自动初始化机制,会发现有两个相关的函数会自动初始化,请看下图ulog_ef_backend_init函数会
    发表于 05-31 15:23

    关于EasyFlash+ulog初始化的问题及其解决办法

    了软件包ulog_easyflash以后,查找INIT_APP_EXPORT这个自动初始化机制,会发现有两个相关的函数会自动初始化,请看下图
    发表于 07-06 09:37

    RT-Thread自动初始化原理分析

    ;}这里我们直接就可以使用 printf 进行打印,而没有进行一些其它的初始化,参考这个思路引出了 RT-Thread 的自动初始化机制。RT-Thread
    发表于 12-05 14:17

    在MAX-IDE中自动初始化数据段

    在MAX-IDE中自动初始化数据段 摘要:该应用笔记讨论了MAX-IDE提供的程序和数据段的灵活工具,用于MAXQ®微控制器的应用编程。程序和数据段机制
    发表于 09-18 09:01 523次阅读

    一文详解RT-Thread自动初始化

    在学RT-Thread时,经常能听到这个词:自动初始化。用起来也非常容易,一个宏就解决了,但是原理是什么呢?
    的头像 发表于 07-21 10:17 7109次阅读
    一文<b class='flag-5'>详解</b>RT-Thread<b class='flag-5'>自动</b><b class='flag-5'>初始化</b>

    RT-Thread自动初始化机制

      在分析之前首先查阅 RT-Thread 的官方文档 [RT-Thread 自动初始化机制](https://www.rt-thread.org/document/site
    的头像 发表于 06-17 08:52 1901次阅读
    RT-Thread<b class='flag-5'>自动</b><b class='flag-5'>初始化</b><b class='flag-5'>机制</b>

    初始化的if和switch语句详解

    在上面的代码中,初始化语句是int s = check()。s的生命周期是整个if语句,这里也包含else语句。
    的头像 发表于 10-14 10:50 1012次阅读