C关键字section的作⽤<;摘要> section关键字的效果,以及在SDK实现开机⾃启动的应⽤
1、section的效果
section主要作⽤是将函数或者变量放在指定段中,可在指定的地⽅取函数执⾏。
//section demo with gcc
#include"stdio.h"
int__attribute__((section("my_fun")))test1(int a,int b)
{
return(a+b);
}
int test(int b)
{
return2*b;
}
int__attribute__((section("my_fun")))test0(int a,int b)
{
return(a*b);
}
int__attribute__((section("my_val"))) chengi;
int__attribute__((section("my_val"))) chengj;
int main(void)
{
int sum,c,j;
chengi=1,chengj=2;
sum=test1(chengi,chengj);
c=test(100);
j=test0(chengi,chengj);
printf("sum=%d,c=%d,j=%d\r\n",sum,c,j);
return0;
}
编译⽣成map⽂件:
gcc - main.c -Wl,-Map,my_test.map
my_test.map ⽂件⽚段如下:
.text 0x004014600xa0 C:\\Users\\think\\ccmGLaeH.o
0x00401460 test
0x0040146a main
.text 0x004015000x0 c:/mingw/bin/../libmingw32.a(CRTglob.o)
......
my_fun 0x004040000x200
[!provide]PROVIDE(___start_my_fun,.)
my_fun 0x004040000x1c C:\\Users\\think\\ccmGLaeH.o
0x00404000 test1
0x0040400d test0
[!provide]PROVIDE(___stop_my_fun,.)
.data 0x004050000x200
0x00405000 \__data_start_\_ =.
......
\*(.data_cygwin_nocopy)
my_val 0x004060000x200
[!provide]PROVIDE(___start_my_val,.)
my_val 0x004060000x8 C:\\Users\\think\\ccdMcTrl.o
0x00406000 chengi
0x00406004 chengj
[!provide]PROVIDE(___stop_my_val,.)
.rdata 0x004070000x400
分析可见,使⽤section修饰的函数和变量在⾃定义的⽚段,⽽且是连续存放在___start_xx到___stop_
xx之间,这样可根据变量的地址得出与其同段变量的地址,为后续⾃动初始化等功能提供了基础。
2、⾃动初始化
基于前⾯section的作⽤,可以将同类函数指针全部使⽤同⼀个段名修饰,然后开机后系统⾃动检索段内函数指针,逐个执⾏,对上层应⽤就是⽆需主动调⽤,系统⾃动初始化。
考虑到硬件初始化与应⽤功能初始化的先后顺序,可以对段名进⾏分配,map⽂件按段名排序。⾃动初始化主体是OS_INIT_EXPORT宏。范例代码出⾃中国移动的oneos开源版本,使⽤gcc,⽅案和国产RT-Thread类似。
const的作用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的⾃动执⾏,即使应⽤层没有显⽰的去调⽤它。使⽤符号段的⽅式实现初始化函数⾃动执⾏,应⽤层修改软件,增加功能启动或者裁剪,对底层代码⽆需任何改动。更多信息请关注【嵌⼊式系统】。
注意,段中函数类型都是⼀样的,范例是同⼀类函数指针,也可以是结构体,需要确保每个成员占⽤的⼤⼩相同,这样才能逐个遍历。3、总结
不同编译器对section属性的定义略有差异,但效果相同。
/* Compiler Related Definitions */
#if defined(__CC_ARM)||defined(__CLANG_ARM)/* ARM Compiler */
#define SECTION(x)__attribute__((section(x)))
#elif defined(__IAR_SYSTEMS_ICC__)/* for IAR Compiler */
#define SECTION(x) @ x
#elif defined(__GNUC__)/* GNU GCC Compiler */
#define SECTION(x)__attribute__((section(x)))
#elif defined(__ADSPBLACKFIN__)/* for VisualDSP++ Compiler */
#define SECTION(x)__attribute__((section(x)))
#elif defined(_MSC_VER)
#define SECTION(x)
#elif defined(__TI_COMPILER_VERSION__)
/*
* The way that TI compiler set section is different from other(at least
* GCC and MDK) compilers. See ARM Optimizing C/C++ Compiler 5.9.3 for more
* details.
*/
#define SECTION(x)
#else
#error not supported tool chain
#endif
配合C关键字,对代码的安全校验、扩展移植都会有很好的效果,可参考前⽂ 。也许⼩型项⽬、独⽴开发看不出效果,但对复杂的多⼈合作的项⽬,合适的关键字对代码的稳定性和架构是锦上添花。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论