先放一段实际项目用到的程序。

#include <stdio.h>#define SEC __attribute__((__section__("ss"), aligned(sizeof(void*))))void func_1 (int a, int b)
{printf("%s %d %d\n", __func__, __LINE__, a+b);
}
void func_2 (int a, int b)
{printf("%s %d %d\n", __func__, __LINE__, a*b);
}// 编译器会自动提供__start_ss,__stop_ss标志段ss的起止地址
extern size_t __start_ss;
extern size_t __stop_ss;typedef struct {void (*p)(int, int);
} node_t;// 结构体变量a位于自定义段ss
SEC node_t a = { .p = func_1,
};
SEC node_t b = { .p = func_2,
};
int main(int argc, char **argv)
{int a = 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;}
}

看不懂没关系,以下内容是我的理解和参考其他人的(来源自CSDN一位大佬,如有侵权,联系删除)

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

#define      SECTION(level)                  __attribute__((used,__section__(".fn_cmd."level)))
#define     CMD_START_EXPORT(func,func_s)   const struct CMD_LIST cmd_fn_##func SECTION("0.end") = {func,func_s}
CMD_START_EXPORT(start_fun,"start_fun");const struct CMD_LIST cmd_fn_##func SECTION("0.end") = {func,func_s}const struct CMD_LIST cmd_fn_func SECTION("0.end") = {start_fun,start_fun}const struct CMD_LIST cmd_fn_func  __attribute__((used,__section__(".fn_cmd.""0.end"))) = {start_fun,start_fun}

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

typedef void (*fun)();
struct CMD_LIST
{fun funs;const INT8 *cmd;
};

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

#define SECTION(level)  __attribute__((used,__section__(".fn_cmd."level)))
#define CMD_START_EXPORT(func,func_s) const struct CMD_LIST cmd_fn_##func SECTION("0.end") = {func,func_s}
#define CMD_EXPORT(func,func_s) const struct CMD_LIST cmd_fn_##func SECTION("1") = {func,func_s}
#define CMD_END_EXPORT(func,func_s) const struct CMD_LIST cmd_fn_##func SECTION("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 内再按函数名称排。所以可以按照输入段中顺序来逐个调用这些初始化函数来完成系统的初始化。
具体实现我会根据我的一个自定义命令行的应用来进行部分的说明。

/*命令函数段起始位置*/
int cmd_start(void)
{return 0;
}
CMD_START_EXPORT(cmd_start,"int cmd_start(void)");/*命令函数段结束位置*/
int cmd_end(void)
{return 0;
}
CMD_END_EXPORT(cmd_end,"int cmd_end(void)");void test(void)
{printf("hello world\r\n");
}
CMD_EXPORT(test,"void test(void)");void demo(void)
{printf("hello world\r\n");
}
CMD_EXPORT(demo,"void demo(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_start                         0x080042f0   Data           8  serialcmd.o(.fn_cmd.0.end)cmd_fn_test                              0x080042f8   Data           8  application.o(.fn_cmd.1)cmd_fn_demo                              0x08004300   Data           8  application.o(.fn_cmd.1)cmd_fn_cmd_end                           0x08004308   Data           8  serialcmd.o(.fn_cmd.1.end)
typedef void (*fun)();
struct CMD_LIST
{fun funs;const INT8 *cmd;
};const static struct CMD_LIST *CmdList;
static UINT8 CmdSize = 0;/*命令函数初始化*/
void SerialCmdInit(void)
{const struct CMD_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文件中的地址很容易就可以看出在得到了起始地址和结束地址之后怎样一个个遍历这些函数。

最后再说一下之前__attribute__((used,section(".fn_cmd."level)))中used的意思。
unused:表示该函数或变量可能不使用,这个属性可以避免编译器产生警告信息。
used: 向编译器说明这段代码有用,即使在没有用到的情况下编译器也不会警告。
这里很有必要提一下,我在使用KEIL进行编译的时候由于没有加used导致变量被编译器给优化掉了,所以在有些时候这个关键字还是有必要添加的。

看到这里再看开始那段代码是不恍然大悟呢?

__attribute__中的section的理解相关推荐

  1. html5中还有div吗,关于html5中的section标签与div标签的区别(内有实例)

    摘要 腾兴网为您分享:关于html5中的section标签与div标签的区别(内有实例),周公解梦,智学网,学习计时,完美root等软件知识,以及网上预约医院软件,字体预览软件,铁血联盟卷土重来,海量 ...

  2. 【HTML】section标签理解

    1.HTML标准中对section的解释 The section element represents a generic section of a document or application. ...

  3. html5 section与div,关于html5中的section标签与div标签的区别(内有实例)

    本篇文章主要的想大家介绍了关于HTML5 section标签和div标签的区别,section和div的用法看似相近,实则差的也不是太多,有些地方可以相互转换都行,但有些地方只能用section或者只 ...

  4. html中section与div,如何在html中的section标签内包含div标签

    我正在制作一个完整版块的页面网站,如this.每个页面都有自己的标签.目前我的网页有4个部分(呈现不同的背景颜色).如何在html中的section标签内包含div标签 我的第一部分有一个容器div, ...

  5. 对网络中安全审计产品的理解

    对网络中安全审计产品的理解<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" ...

  6. ArcEngine中IFeatureClass.Search(filter, Recycling)方法中Recycling参数的理解

    转自 ArcEngine中IFeatureClass.Search(filter, Recycling)方法中Recycling参数的理解 ArcGIS Engine中总调用IFeatureClass ...

  7. KMP中next数组的理解

    next数组是KMP的核心,但对于next数组我们总是有时候感觉明白了,但有时候又感觉没明白,现在我就说下我自己对KMP中next数组的理解,首先next[i]上的数字的意义,next[i]表示的是当 ...

  8. 串行和并行的区别_入门参考:从Go中的协程理解串行和并行

    本文转自公众号语言随笔,欢迎关注 入门参考:从Go中的协程理解串行和并行​mp.weixin.qq.com Go语言的设计亮点之一就是原生实现了协程,并优化了协程的使用方式.使得用Go来处理高并发问题 ...

  9. 高性能计算中并行的概念理解

    高性能计算中并行的概念理解 分类: 并行计算高性能计算HPC - General2011-11-09 22:54 932人阅读 评论(0) 收藏 举报 编译器编程parallel优化formsvect ...

最新文章

  1. Makefile的补充学习
  2. hdu4975 行列和构造矩阵(dp判断唯一性)
  3. 【数据挖掘笔记八】分类:基本概念
  4. [转]脏读,不可重复读,幻读的理解
  5. 由几个月前写的(验证码利用ashx一般处理程序来做),修改为不用以一般处理程序...
  6. svn钩子自动化同步代码提交任务
  7. 最新版计算机应用基础,计算机应用基础课件(最新版)
  8. VMware——VMware Tools的介绍及安装方法
  9. 软件项目经理应具备的素质和条件_IT项目经理必须具备的能力
  10. php在线解密,zend在线解密
  11. 嗅探工具 --- wireshark、tcpdump、dsniff、ettercap、bettercap、netsniff-ng
  12. 密码学工具箱ToolsFx发布日志
  13. 云计算系列知识点——网络(公网、私网、VPN等)基础知识与计费模式
  14. 国内知名插画培训机构有哪些
  15. 蛋白质结构预测方案总结
  16. 农业遥感技术科研成果汇总
  17. php视频画面区域裁剪,怎么裁剪视频画面
  18. 向日葵远程桌面连接教程(Windows与Linux互连)
  19. 我的世界网易版java材质包下载_我的世界网易版服务器怎么加材质包
  20. OCC实战1:搭建QT+OCC+VS环境

热门文章

  1. Maven的生命周期与插件
  2. linux限制普通用户命令,sudo 限制普通用户权限(示例代码)
  3. Integer自动装箱拆箱注意点
  4. wps怎么添加书签页面
  5. 华为荣耀20和x10比较_荣耀20pro与荣耀x10哪个好-荣耀20pro与荣耀x10对比测评
  6. 计算机系军训横幅,军训横幅标语
  7. php网页打印框架,简单打印【Release】 - HisiPHP基于ThinkPHP和Layui开发的通用后台管理框架...
  8. 如何选择适合自己的内存条
  9. python读取文本文件时报错‘utf-8‘ codec can‘t decode byte 0xb4 in position 100:
  10. 设置 QLabel 上面的 text 行间距