__attribute__使用

__attribute__是GNU对标准C的扩展,可以用来设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。

__attribute__书写特征为:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的参数。

__attribute__语法格式为:__attribute__ ((attribute-list))。

其位置约束为:放于声明的尾部";"之前。

used

标记为__attribute__((used))的函数被标记在目标文件中,以避免链接器删除未使用的节。

weak

__attribute__((weak)) int main(int argc, char **argv)
{
    return tbox::main::Main(argc, argv);
}

如上所示,main函数被定义为弱符号。

如果用户没有定义main函数,则会使用默认的main函数。

如果用户定义了自己的main函数,则会使用用户自定义的main函数。

packed

使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐。

struct student
{
    char name[7];
    uint32_t id;
    char subject[5];
} __attribute__ ((packed));

section

section关键字可以将变量或者函数定义到可执行文件特定段中:

int test __attribute__((section("show"))) = 0;

static elab_export_poll_data_t poll_shell_poll_data = { .timeout_ms = 0, }; 

__attribute__((used)) const elab_export_t poll_shell_poll __attribute__((section("expoll"))) = 
{ 
    .name = "poll", 
    .func = &shell_poll, 
    .data = (void *)&poll_shell_poll_data,
    .level = EXPORT_POLL, 
    .period_ms = (uint32_t)((10)), 
    .magic_head = (0xbeefbeef), 
    .magic_tail = (0xbeefbeef), 
};

使用section可以使我们如在初始化函数时,不用在主函数中去添加一个新的初始化程序,只需要在自己的函数模块内注册就好了。

或者在实现某些命令时,添加或删除该命令的支持,会方便很多。

cpost为例,在使用section进行属性设置后,用户自定义的函数、const修饰的变量会被放到Flash指定的section内,以下定义了一个名为cEvent的section。

#define CEVENT_EXPORT(_event, _func, ...) \
        const void *cEventParam##_event##_func[] = {(void *)_func, ##__VA_ARGS__}; \
        const CEvent SECTION("cEvent") cEvent##_event##_func = \
        { \
            .param = cEventParam##_event##_func, \
            .paramNum = sizeof(cEventParam##_event##_func) / sizeof(void *), \
            .event = _event, \
        }

查看MDK生成的map文件,可以看到该section在flash中的位置:

Memory Map of the image

Image Entry point : 0x08000131

Load Region LR_IROM1 (Base: 0x08000000, Size: 0x000042ac, Max: 0x00080000, ABSOLUTE)

Execution Region ER_IROM1 (Exec base: 0x08000000, Load base: 0x08000000, Size: 0x0000422c, Max: 0x00080000, ABSOLUTE)

Exec Addr    Load Addr    Size         Type   Attr  Idx    E Section Name        Object

0x08000000   0x08000000   0x00000130   Data   RO        3    RESET               startup_stm32f10x_hd.o
0x08000130   0x08000130   0x00000000   Code   RO      351  * .ARM.Collect$$$$00000000  mc_w.l(entry.o)
0x08000130   0x08000130   0x00000004   Code   RO      631    .ARM.Collect$$$$00000001  mc_w.l(entry2.o)
0x08000134   0x08000134   0x00000004   Code   RO      634    .ARM.Collect$$$$00000004  mc_w.l(entry5.o)
0x08000138   0x08000138   0x00000000   Code   RO      636    .ARM.Collect$$$$00000008  mc_w.l(entry7b.o)
0x08000138   0x08000138   0x00000000   Code   RO      638    .ARM.Collect$$$$0000000A  mc_w.l(entry8b.o)
0x08000138   0x08000138   0x00000008   Code   RO      639    .ARM.Collect$$$$0000000B  mc_w.l(entry9a.o)
0x08000140   0x08000140   0x00000000   Code   RO      641    .ARM.Collect$$$$0000000D  mc_w.l(entry10a.o)
0x08000140   0x08000140   0x00000000   Code   RO      643    .ARM.Collect$$$$0000000F  mc_w.l(entry11a.o)
0x08000140   0x08000140   0x00000004   Code   RO      632    .ARM.Collect$$$$00002712  mc_w.l(entry2.o)
0x08000144   0x08000144   0x00000030   Code   RO        4    .text               startup_stm32f10x_hd.o
0x08000174   0x08000174   0x00000174   Code   RO       10    .text               main.o
0x080002e8   0x080002e8   0x00000030   Code   RO       83    .text               stm32f10x_it.o
0x08000318   0x08000318   0x0000011c   Code   RO      104    .text               usart1.o
0x08000434   0x08000434   0x000000bc   Code   RO      123    .text               exti_pa0.o
0x080004f0   0x080004f0   0x00000330   Code   RO      142    .text               stm32f10x_gpio.o
0x08000820   0x08000820   0x000003a0   Code   RO      154    .text               stm32f10x_rcc.o
0x08000bc0   0x08000bc0   0x00000370   Code   RO      168    .text               stm32f10x_usart.o
0x08000f30   0x08000f30   0x000000dc   Code   RO      180    .text               misc.o
0x0800100c   0x0800100c   0x00000140   Code   RO      192    .text               stm32f10x_exti.o
0x0800114c   0x0800114c   0x00000138   Code   RO      214    .text               system_stm32f10x.o
0x08001284   0x08001284   0x00000138   Code   RO      232    .text               cevent.o
0x080013bc   0x080013bc   0x000001b8   Code   RO      252    .text               cpost.o
0x08001574   0x08001574   0x0000130c   Code   RO      270    .text               shell.o
0x08002880   0x08002880   0x000003b2   Code   RO      321    .text               shell_ext.o
0x08002c32   0x08002c32   0x00000002   PAD
0x08002c34   0x08002c34   0x00000074   Code   RO      333    .text               shell_port.o
0x08002ca8   0x08002ca8   0x00000024   Code   RO      354    .text               mc_w.l(memseta.o)
0x08002ccc   0x08002ccc   0x0000000e   Code   RO      356    .text               mc_w.l(strlen.o)
0x08002cda   0x08002cda   0x0000001c   Code   RO      358    .text               mc_w.l(strcmp.o)
0x08002cf6   0x08002cf6   0x0000001e   Code   RO      360    .text               mc_w.l(strncmp.o)
0x08002d14   0x08002d14   0x00000064   Code   RO      623    .text               mf_w.l(fmul.o)
0x08002d78   0x08002d78   0x0000007c   Code   RO      625    .text               mf_w.l(fdiv.o)
0x08002df4   0x08002df4   0x00000012   Code   RO      627    .text               mf_w.l(fflti.o)
0x08002e06   0x08002e06   0x0000000a   Code   RO      629    .text               mf_w.l(ffltui.o)
0x08002e10   0x08002e10   0x0000002c   Code   RO      646    .text               mc_w.l(uidiv.o)
0x08002e3c   0x08002e3c   0x00000062   Code   RO      648    .text               mc_w.l(uldiv.o)
0x08002e9e   0x08002e9e   0x00000000   Code   RO      650    .text               mc_w.l(iusefp.o)
0x08002e9e   0x08002e9e   0x0000006e   Code   RO      651    .text               mf_w.l(fepilogue.o)
0x08002f0c   0x08002f0c   0x0000014e   Code   RO      653    .text               mf_w.l(dadd.o)
0x0800305a   0x0800305a   0x000000e4   Code   RO      655    .text               mf_w.l(dmul.o)
0x0800313e   0x0800313e   0x000000de   Code   RO      657    .text               mf_w.l(ddiv.o)
0x0800321c   0x0800321c   0x00000030   Code   RO      659    .text               mf_w.l(dfixul.o)
0x0800324c   0x0800324c   0x00000030   Code   RO      661    .text               mf_w.l(cdrcmple.o)
0x0800327c   0x0800327c   0x00000024   Code   RO      663    .text               mc_w.l(init.o)
0x080032a0   0x080032a0   0x0000001e   Code   RO      665    .text               mc_w.l(llshl.o)
0x080032be   0x080032be   0x00000020   Code   RO      667    .text               mc_w.l(llushr.o)
0x080032de   0x080032de   0x00000024   Code   RO      669    .text               mc_w.l(llsshr.o)
0x08003302   0x08003302   0x000000ba   Code   RO      671    .text               mf_w.l(depilogue.o)
0x080033bc   0x080033bc   0x00000020   Code   RO      595    i.__0printf         mc_w.l(printfa.o)
0x080033dc   0x080033dc   0x0000002c   Code   RO      600    i.__0vsnprintf      mc_w.l(printfa.o)
0x08003408   0x08003408   0x0000000e   Code   RO      675    i.__scatterload_copy  mc_w.l(handlers.o)
0x08003416   0x08003416   0x00000002   Code   RO      676    i.__scatterload_null  mc_w.l(handlers.o)
0x08003418   0x08003418   0x0000000e   Code   RO      677    i.__scatterload_zeroinit  mc_w.l(handlers.o)
0x08003426   0x08003426   0x00000002   PAD
0x08003428   0x08003428   0x00000184   Code   RO      602    i._fp_digits        mc_w.l(printfa.o)
0x080035ac   0x080035ac   0x000006dc   Code   RO      603    i._printf_core      mc_w.l(printfa.o)
0x08003c88   0x08003c88   0x00000024   Code   RO      604    i._printf_post_padding  mc_w.l(printfa.o)
0x08003cac   0x08003cac   0x0000002e   Code   RO      605    i._printf_pre_padding  mc_w.l(printfa.o)
0x08003cda   0x08003cda   0x00000016   Code   RO      606    i._snputc           mc_w.l(printfa.o)
0x08003cf0   0x08003cf0   0x00000030   Data   RO       11    .constdata          main.o
0x08003d20   0x08003d20   0x00000010   Data   RO      124    .constdata          exti_pa0.o
0x08003d30   0x08003d30   0x000000e8   Data   RO      272    .constdata          shell.o
0x08003e18   0x08003e18   0x000002a1   Data   RO      273    .conststring        shell.o
0x080040b9   0x080040b9   0x00000003   PAD
0x080040bc   0x080040bc   0x00000020   Data   RO      673    Region$$Table       anon$$obj.o
0x080040dc   0x080040dc   0x00000010   Data   RO       13    cEvent              main.o
0x080040ec   0x080040ec   0x00000020   Data   RO       14    shellCommand        main.o
0x0800410c   0x0800410c   0x00000120   Data   RO      275    shellCommand        shell.o

每个section在可执行文件中都会有对应的起始、结束地址,不同编译器对此表示不一样:

#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
    extern const size_t cEvent$$Base;   // MDK
    extern const size_t cEvent$$Limit;
#elif defined(__ICCARM__) || defined(__ICCRX__)
    #pragma section="cEvent"            // IAR
#elif defined(__GNUC__)               
    extern const size_t _cevent_start;  // gcc
    extern const size_t _cevent_end;
#endif

#if CEVENT_SPEED_OPTIMIZE == 1 && CEVENT_BUFFER_SIZE > 0
static size_t ceventBuffer[CEVENT_BUFFER_SIZE] = {0};
#endif

我们可以通过起始、结束地址,对定义的变量进行访问:

    CEvent *base;
    size_t count;
#if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
    base = (CEvent *)(&cEvent$$Base);
    count = ((size_t)(&cEvent$$Limit) - (size_t)(&cEvent$$Base)) / sizeof(CEvent);
#elif defined(__ICCARM__) || defined(__ICCRX__)
    base = (CEvent *)(__section_begin("cEvent"));
    count = ((size_t)(__section_end("cEvent")) - (size_t)(__section_begin("cEvent")))
            / sizeof(CEvent);
#elif defined(__GNUC__)
    base = (CEvent *)(&_cevent_start);
    count = ((size_t)(&_cevent_end) - (size_t)(&_cevent_start)) / sizeof(CEvent);
#else
    #error not supported compiler, please use command table mode
#endif

letter shell在注册命令时也使用了这种技巧,感兴趣可以看看对应的代码。

refrence

  1. attribute之section详解
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容