IAR Embedded Workbench中的初始化策略

Technical Note

Architectures:

All

Component:

linker

Updated:

2023/8/10 6:27

之前的文章“IAR Embedded Workbench中的MCU启动过程”介绍了IAR Embedded Workbench中的MCU启动过程:其中非常重要的一步是存储在RAM中的全局和静态变量的初始化。

本文主要介绍IAR Embedded Workbench中的初始化策略。

存储在RAM中的全局和静态变量的初始化

初始化初始值为0的存储在RAM中的全局和静态变量(比如 int i = 0;):

初始化初始值为非0的存储在RAM中的全局和静态变量(比如 int i = 1;),对应的初始值(Initialize variables)从相应的ROM拷贝到对应的RAM:

IAR Embedded Workbench中的初始化策略

initialize by copy

在ICF文件添加initialize by copy { readwrite };命令之后,Linker会自动添加对应的initializers,并在启动代码里面自动完成对应的初始化操作:

initialize by copy { readwrite };

MAP文件中的INIT TABLE会列出对应的初始化信息:其中初始值为0的全局和静态变量会通过__iar_zero_init3函数进行初始化:初始化的时候__iar_zero_init3函数会对相关RAM区域进行写0操作,完成对初始值为0的全局和静态变量的初始化;初始值为非0的全局和静态变量会通过__iar_copy_init3函数进行初始化:对应的Initializer bytes放到ROM,初始化的时候__iar_copy_init3函数会把ROM中的Initializer bytes拷贝到RAM中,完成对初始值为非0的全局和静态变量的初始化:

注意:initialize by copy命令需要启动代码里面调用__iar_program_start进行初始化。

在ICF文件添加initialize by copy { readwrite };命令之后,Linker会自动添加对应的initializers,并在启动代码里面自动完成对应的初始化操作,对应的__iar_zero_init3函数和__iar_copy_init3函数都是通过__iar_program_start调用,所以需要使用__iar_program_start进行初始化:

        THUMB
        PUBWEAK Reset_Handler
        SECTION .text:CODE:REORDER:NOROOT(2)
Reset_Handler

        LDR     R0, =SystemInit
        BLX     R0
        LDR     R0, =__iar_program_start
        BX      R0

如果没有调用__iar_program_start进行初始化,link的时候会提示类似下面的错误(__iar_data_init3函数会先后调用__iar_zero_init3函数和__iar_copy_init3函数):

initialize manually

如果代码里面没有使用__iar_program_start进行初始化,就不能使用initialize by copy初始化策略对初始值为非0的全局和静态变量进行自动初始化。可以使用initialize manually初始化策略对初始值为非0的全局和静态变量进行手动初始化(当然,代码里面使用了__iar_program_start进行初始化,也是可以使用initialize manually初始化策略对初始值为非0的全局和静态变量进行手动初始化的)。

如下所示:ICF文件中使用initialize manually对.data section进行手动初始化:.data section包含的是初始值为非0的全局和静态变量,放到MY_DATA block中,并把对应的MY_DATA block放到RAM;.data_init section包含的是初始值为非0的全局和静态变量的Initializer bytes,放到MY_DATA_INIT block中, 并把对应的MY_DATA_INIT block放到ROM:

define block MY_DATA { section .data };

define block MY_DATA_INIT { section .data_init };

initialize manually { section .data };

place in IRAM_region  { block MY_DATA };

place in IROM_region  { block MY_DATA_INIT };

然后需要在代码里面添加对应的手动初始化.data section的代码:其中#pragma section命令用于定义对应的section名字,然后对应的section操作符__section_begin, __section_end和section_size就可以分别获取对应section的开始地址,结束地址和大小。

#pragma section = "MY_DATA"
#pragma section = "MY_DATA_INIT"

static void MyDataSectionInit(void)
{
  char * from = __section_begin("MY_DATA_INIT");
  char * to = __section_begin("MY_DATA");
  memcpy(to, from, __section_size("MY_DATA"));
}



int main(void)
{
  MyDataSectionInit();

  …
 }

MAP文件中.data section放到MY_DATA block中,放置到RAM,对应的.data_init section(Initializer bytes)放到MY_DATA_INIT block中,放置到ROM:

do not initialize

如果代码里面没有使用__iar_program_start进行初始化,就不能使用initialize by copy初始化策略对初始值为0的全局和静态变量进行自动初始化。可以使用do not initialize初始化策略对初始值为0的全局和静态变量进行手动初始化(当然,代码里面使用了__iar_program_start进行初始化,也是可以使用do not initialize初始化策略对初始值为0的全局和静态变量进行手动初始化的)。

如下所示,ICF文件中使用do not initialize对.bss section进行手动初始化:.bss section包含的是初始值为0的全局和静态变量,放到MY_BSS block中,并把对应的MY_BSS block放到RAM:

define block MY_BSS { section .bss };

do not initialize { section .bss };

place in IRAM_region  { block MY_BSS };

然后需要在代码里面添加对应的手动初始化.bss section的代码:其中#pragma section命令用于定义对应的section名字,然后对应的section操作符__section_begin, __section_end和section_size就可以分别获得对应section的开始地址,结束地址和大小。

#pragma section = "MY_BSS"

static void MyBssSectionInit(void)
{
  char * to = __section_begin("MY_BSS");
  memset(to, 0, __section_size("MY_BSS"));
}



int main(void)
{
  MyBssSectionInit();

  …
 }

MAP文件中.bss section放到MY_BSS block中,放置到RAM:

另外对于使用了__no_init的静态和全局变量,linker默认会放置到.noinit section,可以在ICF文件使用do not initialize命令,对应代码中不能对.noinit section进行初始化,这样.noinit section的内容在启动过程中不会有任何初始化操作。

do not initialize  { section .noinit };

注意事项

注意:如果静态和全局变量放到了用户定义的section,并且手动明确地赋初始值0(比如 int i = 0;),默认需要对这类变量进行copy初始化,而不是zero初始化。

如下所示,静态变量TaskLedRedCounter放到了用户定义的MY_SECTION section里面,并且手动明确地赋初始值0:

#pragma location = "MY_SECTION"
static uint32_t TaskLedRedCounter = 0;

MAP文件中静态变量TaskLedRedCounter的Kind是inited,而不是uninit;并且INIT TABLE里面生成了对应的Initializer bytes:

这个跟通常的初始值为0的静态和全局变量的处理有点不一样,由于对应变量的Kind是inited,所以需要使用initialize manually初始化策略(跟初始值为非0的全局和静态变量进行手动初始化一样):

如下所示:ICF文件中使用initialize manually对MY_SECTION section进行手动初始化:

define block MY_DATA { section .data, section MY_SECTION };

define block MY_DATA_INIT { section .data_init, section MY_SECTION_init };

initialize manually { section .data, section MY_SECTION };

place in IRAM_region  { block MY_DATA };

place in IROM_region  { block MY_DATA_INIT };

MAP文件中MY_SECTION section放到MY_DATA block中,放置到RAM,对应的Initializer bytes放到MY_DATA_INIT block中,放置到ROM:

如果想对上面的变量使用do not initialize初始化策略(跟初始值为0的全局和静态变量进行手动初始化一样),需要使用编译器选项--do_explicit_zero_opt_in_named_sections:

MAP文件中静态变量TaskLedRedCounter的Kind是zero,并且INIT TABLE只有__iar_zero_init3函数:

在ICF文件中像处理正常的.bss section一样:把MY_SECTION section放到MY_BSS section,同时使用do not initialize命令:

define block MY_BSS { section .bss, section MY_SECTION };

do not initialize { section .bss, section MY_SECTION };

place in IRAM_region  { block MY_BSS };

MAP文件中静态变量TaskLedRedCounter的Kind是期望的uninit:

更多关于Initialization decisions的信息,可以通过使能Linker > List > Generate log file > Initialization decisions选项来查看对应log文件中的信息:

总结 

本文主要介绍了IAR Embedded Workbench中的初始化策略:initialize by copy, initialize manually和do not initialize,用户可以根据对应的需求来灵活合理地选择初始化策略:

  • 如果对应变量在启动过程中不能被初始化,需要使用do not initialize初始化策略,并且代码里面不能对相关变量进行任何初始化;

  • 如果启动代码使用了__iar_program_start:

    • 如果没有特别的初始化需求,使用initialize by copy初始化策略

    • 如果有特别的初始化需求,参考下面启动代码没有使用__iar_program_start的情况

  • 如果启动代码没有使用__iar_program_start:

    • 对应变量的初始值非0,使用initialize manually,并且需要添加对应的代码把ROM中的Initializer bytes拷贝到对应的RAM区域

    • 通常情况下,对应变量的初始值为0,使用do not initialize,并且需要添加对应的代码对相关RAM区域进行写0操作

    • 如果变量放到了用户定义的section,并且手动明确地赋初始值0默认需要对这类变量进行copy初始化(使用initialize by copy初始化策略);需要使用编译器选项--do_explicit_zero_opt_in_named_sections实现zero初始化(使用do not initialize初始化策略)

参考文献:

  1. IAR Embedded Workbench中的MCU启动过程

  2. IAR C/C++ Development Guide (initialize directive, Manual initialization)

  3. 如何在IAR Embedded Workbench中把变量和函数放到指定的section

 

We do no longer support Internet Explorer. To get the best experience of iar.com, we recommend upgrading to a modern browser such as Chrome or Edge.