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

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

3天内不再提示

关于attribute(section)在GCC和ARMGCC中的使用

jf_L18yujSQ 来源:小飞哥学嵌入式 2023-04-15 17:09 次阅读

简介

__attribute__ 是gcc编译器支持的一个编译特性(arm编译器也支持此特性,比如我们常用的keil就是用的ARMGCC编译器),也就是通过给函数或者变量声明属性值,以便让编译器能够对要编译的程序进行优化处理。

而对于 section 这个关键字,我们可以通过它将指定的变量定义到指定的输入段中。

section 属性指定变量必须放置在特定数据部分中,通常,ARM 编译器将其生成的对象放在 .data 和 .bss 等部分中。但是,您可能需要其他数据部分,或者您可能希望变量出现在特殊部分中,例如,映射到特殊硬件

如果使用 section 属性,则只读变量将放置在 RO 数据部分中,读写变量将放置在 RW 数据部分中,除非您使用 zero_init 属性。在这种情况下,变量放置在 ZI 部分中。

/*inROsection*/
constintdescriptor[3]__attribute__((section("descr")))={1,2,3};
/*inRWsection*/
longlongrw_initialized[10]__attribute__((section("INITIALIZED_RW")))={5};
/*inRWsection*/
longlongrw[10]__attribute__((section("RW")));
/*inZIsection*/
longlongaltstack[10]__attribute__((section("STACK"),zero_init));

用法详解

先来看一段代码(摘自CSDN,如有侵权,联系删除):

#include

#defineSEC__attribute__((__section__("ss"),aligned(sizeof(void*))))

voidfunc_1(inta,intb)
{
printf("%s%d%d
",__func__,__LINE__,a+b);
}
voidfunc_2(inta,intb)
{
printf("%s%d%d
",__func__,__LINE__,a*b);
}

//编译器会自动提供__start_ss,__stop_ss标志段ss的起止地址
externsize_t__start_ss;
externsize_t__stop_ss;

typedefstruct
{
void(*p)(int,int);
}node_t;

//结构体变量a位于自定义段ss
SECnode_ta={
.p=func_1,
};
SECnode_tb={
.p=func_2,
};
intmain(intargc,char**argv)
{
inta=3,b=4;
node_t*p;
//遍历段ss,执行node_t结构中的p指向的函数
for(p=(node_t*)&__start_ss;p< (node_t *)&__stop_ss; p++)
    {
        p->p(a,b);
a+=1;
b+=2;
}
}

来看一下运行的结果:

poYBAGQ6aiyAGKAiAACaDdW4qbM210.jpg

1、section关键字可以将变量定义到指定的输入段中,

#defineSECTION(level)__attribute__((used,__section__(".fn_cmd."level)))
#defineCMD_START_EXPORT(func,func_s)conststructCMD_LISTcmd_fn_##funcSECTION("0.end")={func,func_s}
CMD_START_EXPORT(start_fun,"start_fun");

conststructCMD_LISTcmd_fn_##funcSECTION("0.end")={func,func_s}

conststructCMD_LISTcmd_fn_funcSECTION("0.end")={start_fun,start_fun}

conststructCMD_LISTcmd_fn_func__attribute__((used,__section__(".fn_cmd.""0.end")))={start_fun,start_fun}

这个时候再来看会发现其实就是定义了一个struct CMD_LIST 类型的变量,变量的名字是cmd_fn_start_fun,并且这个变量被放到了我们所希望的一个输入段.fn_cmd.0.end中了

typedefvoid(*fun)();
structCMD_LIST
{
funfuns;
constINT8*cmd;
};

2、使用section将变量放到我们自定义的输入段中有什么意义呢?

#defineSECTION(level)__attribute__((used,__section__(".fn_cmd."level)))
#defineCMD_START_EXPORT(func,func_s)conststructCMD_LISTcmd_fn_##funcSECTION("0.end")={func,func_s}
#defineCMD_EXPORT(func,func_s)conststructCMD_LISTcmd_fn_##funcSECTION("1")={func,func_s}
#defineCMD_END_EXPORT(func,func_s)conststructCMD_LISTcmd_fn_##funcSECTION("1.end")={func,func_s}

当这几个宏被调用时将会产生名为cmd_fn_xx的变量,并且这个变量根据被调用的宏来把这个变量放到相应的输入段。例如CMD_START_EXPORT这个宏,这个宏其实上面已经讲过了,调用这个宏的时候会产生一个名为cmd_fn_xx的变量,并且把这个变量放到了我们自定义的输入段.fn_cmd.0.end中了。

其他两个宏的其实也是差不多的,不同之处就是输入段有些区别。言归正传,现在继续来讲如何使用section将不同的函数放到我们想要的输入段中,并且获得他们的起始地址和结束地址。

我们可以在每个XXX_Init函数后面都调用宏CMD_EXPORT,在调用这个宏时编译器会将XXX_init这个函数加入到输入段中,由于变量在输入段中的地址是连续的,并且顺序先按 section 名 01234排一遍,section 内再按函数名称排。

所以可以按照输入段中顺序来逐个调用这些初始化函数来完成系统的初始化。具体实现我会根据我的一个自定义命令行的应用来进行部分的说明。

/*命令函数段起始位置*/
intcmd_start(void)
{
return0;
}
CMD_START_EXPORT(cmd_start,"intcmd_start(void)");

/*命令函数段结束位置*/
intcmd_end(void)
{
return0;
}
CMD_END_EXPORT(cmd_end,"intcmd_end(void)");

voidtest(void)
{
printf("helloworld
");
}
CMD_EXPORT(test,"voidtest(void)");

voiddemo(void)
{
printf("helloworld
");
}
CMD_EXPORT(demo,"voiddemo(void)");

先定义start和end函数并且分别使用CMD_START_EXPORT和CMD_END_EXPORT来将其放到输入段.fn_cmd.0.end和.fn_cmd.1.end中,按照上面的说明输入段.fn_cmd.0.end是排在输入段.fn_cmd.1.end前面的,而使用的CMD_EXPORT这个宏对应的输入段.fn_cmd.1是排在.fn_cmd.0.end和.fn_cmd.1.end之间的,这里可以看一下编译产生的.map会更加的形象一些。具体在MAP文件的位置如下所示

cmd_fn_cmd_start0x080042f0Data8serialcmd.o(.fn_cmd.0.end)
cmd_fn_test0x080042f8Data8application.o(.fn_cmd.1)
cmd_fn_demo0x08004300Data8application.o(.fn_cmd.1)
cmd_fn_cmd_end0x08004308Data8serialcmd.o(.fn_cmd.1.end)

typedefvoid(*fun)();
structCMD_LIST
{
funfuns;
constINT8*cmd;
};

conststaticstructCMD_LIST*CmdList;
staticUINT8CmdSize=0;

/*命令函数初始化*/
voidSerialCmdInit(void)
{
conststructCMD_LIST*cmd_ptr;
CmdList=&cmd_fn_cmd_start;
CmdList++;
for(cmd_ptr=CmdList;cmd_ptr< &cmd_fn_cmd_end;cmd_ptr++)
 {
        /*这里如果用于初始化的话可以使用下面这种方式来执行初始化函数,因为我的应用并不是用于初始            
         化,所以就没有进行函数调用。
         (*cmd_ptr->fun)();
*/
CmdSize++;
}
}

其中cmd_fn_cmd_start是在.fn_cmd.0.end这个输入段中的,而各个要执行的函数是在.fn_cmd.1这个输入段中的,cmd_fn_cmd_end作为结束的标志在.fn_cmd.1.end输入段中。

其余的就不做过多讲解了,从上面的.map文件中的地址很容易就可以看出在得到了起始地址和结束地址之后怎样一个个遍历这些函数。

然而上述功能只能对 GCC 平台有效, 如果是 ARMCC 或是其他平台, 因为编译器不同, 方法可能不一样, 为了跨平台, 就不得不添加平台检测的宏, 比如将下面的代码替换获取 myfun_section 所在的内存区间部分即可支持 ARMCC 平台。

#ifdef__ARMCC_VERSION/*ARMCCompiler*/
externtest_command_tmyfun_section$$Base;
externtest_command_tmyfun_section$$Limit;
test_command_t*myfun_section_begin=&(myfun_section$$Base);
test_command_t*myfun_section_end=&(myfun_section$$Limit);
#elifdefined(__GNUC__)
externtest_command_t__start_myfun_section;
externtest_command_t__stop_myfun_section;
test_command_t*myfun_section_begin=&__start_myfun_section;
test_command_t*myfun_section_end=&__stop_myfun_section;
#else
#error"Theplatformisnotsupported"
#endif

结语

以上就是关于attribute(section)在GCC和ARMGCC中的使用。






审核编辑:刘清

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

    关注

    134

    文章

    9087

    浏览量

    367404
  • GNU
    GNU
    +关注

    关注

    0

    文章

    143

    浏览量

    17492
  • CMD命令
    +关注

    关注

    0

    文章

    28

    浏览量

    8306
  • gcc编译器
    +关注

    关注

    0

    文章

    78

    浏览量

    3381

原文标题:鲜为人知的__attribute__((__section__(section_name))),你知道怎么用吗?

文章出处:【微信号:小飞哥玩嵌入式,微信公众号:小飞哥玩嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    pads提示警告:Section *DEL_ATTRIBUTE*

    第一次从pads logic向pads layout中导入原理图的时候没有提示警告,但是我第一次的基础上再重复一次的时候就会提示很多的警告类似于:Line 6 , Section
    发表于 08-27 13:53

    __ATTRIBUTE__ 你知多少?

    , transparent_union, unused, deprecated 和 may_alias 。使用__attribute__ 参数时,你也可以参数的前后都加上“__” (两个下划线),例如
    发表于 09-05 11:12

    section的使用方法

    无论是GNU还是ARM的编译器,都支持__attribute__所指定的编译属性,这里着重讲解一下KEIL环境下__attribute__se
    发表于 11-25 08:10

    attribute用法section部分的资料大合集

    转载:http://blog.sina.com.cn/s/blog_5e11a56a0100c8h5.html###1. gcc的__attribute__编译属性要了解Linux Kernel代码
    发表于 11-25 08:25

    来了解一下GNU C __attribute__机制

    不存在普通符号,则使用弱符号。更多的__attribute__属性可以参考GCC手册,我们需要使用到编译器一些高级特性的时候,可以在手册查找。
    发表于 03-03 15:49

    怎么理解RTT#define UNUSED __attribute__((unused))这个语句呢

    ){UNUSED rt_uint32_t iir;而UNUSED的定义,rtdef.h:#ifdef __CC_ARM /* ARM Compiler */#include#define SECTION
    发表于 03-29 09:27

    MounRiver keil的定位语句无法使用是为什么?

    由于从F转到V,keil变为MounRiver,用gcc编译器。原先keil的定位语句无法使用了。1、keil地址0x08005400位置定位一个变量用于存放程序版本号:#define
    发表于 06-15 07:47

    请问GCC支持attribute at属性吗?

    MAP您好,GCC目前不支持attribute at属性,需要通过section属性和LD来实现类似功能,编译显示RAM也超出了,您使用的是哪款芯片,以及具体的用法及程序可以到邮箱:yangy@wch.cn 。详细沟通下。你好,
    发表于 07-18 08:59

    关于链接脚本(ld)的使用中段(section)被优化的问题求解

    USER_SECTION_NAME__attribute__((section("user_section_name_tab")))#define USER_SECTION__attribu
    发表于 03-08 07:56

    GCCSTUDIO的使用方法(WINAVR及AVR_STUDIO)

    GCCSTUDIO的使用方法(WINAVR及AVR_STUDIO),感兴趣的可以看看。
    发表于 07-25 18:26 38次下载

    关于GCC的分析,想进一步了解GCC的朋友可以看看

    关于GCC的分析,想进一步了解GCC的朋友可以看看
    发表于 10-25 08:40 5次下载
    <b class='flag-5'>关于</b><b class='flag-5'>GCC</b>的分析,想进一步了解<b class='flag-5'>GCC</b>的朋友可以看看

    __attribute__((section(x))) 使用详解

    无论是GNU还是ARM的编译器,都支持__attribute__所指定的编译属性,这里着重讲解一下KEIL环境下__attribute__se
    发表于 11-16 18:06 8次下载
    __<b class='flag-5'>attribute</b>__((<b class='flag-5'>section</b>(x))) 使用详解

    attribute 用法 section 部分

    attribute 用法 section 部分
    发表于 11-16 18:21 87次下载
    <b class='flag-5'>attribute</b> 用法 <b class='flag-5'>section</b> 部分

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

    __attribute__所指定的编译属性,这里着重讲解一下KEIL 环境下__attribute__section的使用方法。一、
    发表于 11-16 18:21 47次下载
    C语言中的__<b class='flag-5'>attribute</b>__宏定义之<b class='flag-5'>section</b>属性

    __attribute__((section(“section_name“)))使用方法

    __attribute__((section("section_name")))使用方法内容待补充!!!!
    发表于 11-16 19:06 12次下载
    __<b class='flag-5'>attribute</b>__((<b class='flag-5'>section</b>(“<b class='flag-5'>section</b>_name“)))使用方法