__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详解
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容