利用__attribute__((section("name")))构建初始化函数表

Posted aresguangjie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用__attribute__((section("name")))构建初始化函数表相关的知识,希望对你有一定的参考价值。

在嵌入式学习工作中经常初始化一个硬件就写一个初始化函数,基本都要到主函数中调用进行初始化,main函数都要改变。当利用__attribute__((section("name")))这个属性就可以构造一个初始化函数表,这样每次初始化一个硬件啥的就不用到main函数中去调用初始化函数。式在RTT初始化函数和Linux初始化驱动模块也是类似这样做的。

attribute的用法

http://www.keil.com/support/man/docs/armcc/armcc_chr1359124982450.htm

代码

  • 头文件
#ifndef _HARDWARE_INIT_H_
#define _HARDWARE_INIT_H_

#if defined(__CC_ARM) || defined(__CLANG_ARM)   /* ARMCC Complier */
    #define INIT_SECTION(x)      __attribute__((section(x))) 
    #define INIT_USED            __attribute__((used))     
#elif defined(__ICCARM__)                      /* IAR ARMCC Complier */

#elif defined(__GNUC__)                        /* GNUC Complier */

#else
    #error "not support tool chain"
#endif

typedef void (*init_func)(void);

typedef struct{
    init_func _init_func;
}init_func_t;

#define INIT_EXPORT(handler)                                                      INIT_USED init_func_t _init_##handler##_func INIT_SECTION("INIT_LIST") =            //INIT_LIST自定义段名
    {                                                                                 handler,                                                                  }
    
void sys_init(void);

#endif
  • 源文件
    在MDK中使用下面方式获得自定义段的起始和终止地址。
static init_func_t *init_list_begin;
static init_func_t *init_list_end;

void sys_init(void)
{
    init_func_t *index;
#if defined(__CC_ARM) || defined(__CLANG_ARM) 
    extern const int INIT_LIST$$Base;   
    extern const int INIT_LIST$$Limit;
    init_list_begin = (init_func_t *)&INIT_LIST$$Base;   //获得段起始地址
    init_list_end   = (init_func_t *)&INIT_LIST$$Limit;  //获得结束段地址
#elif defined(__ICCARM__)                      /* IAR ARMCC Complier */

#elif defined(__GNUC__)                        /* GNUC Complier */

#endif
    for(index = init_list_begin; index < init_list_end; index++)
    {
        index->_init_func();
    }
}
  • 初始化函数使用INIT_EXPORT修饰
void MY_USART_Init(void)
{
    __MY_USART_Init(115200);
}
INIT_EXPORT(MY_USART_Init);

用INIT_EXPORT修饰过的函数都会定义一个函数指针在自定义的section——INIT_LIST,这个自定义的段由编译器静态分配。

  • 主函数中调用sys_init()
 int main(void)
 {           
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
     
    sys_init(); 

    while(1)
    {
        software_timer_main_loop();
    }
}    

以上是关于利用__attribute__((section("name")))构建初始化函数表的主要内容,如果未能解决你的问题,请参考以下文章

删除使用 __attribute__((section)) 创建的部分

C语言中的__attribute__宏定义之section属性

__attribute__((section(”name“)))的一些理解

gcc - 使用 #pragma 将 __attribute__((section(".dflash_code"))) 应用于整个源文件

__attribute__之section详解 ------ 把函数指定到具体某个section 之 RT-thread 实例详解

mdk keil 指定变量函数存储位置,使用 Scatter-Loading Description File, __attribute__(("section“))