- IAR Embedded Workbench for RISC-V 3.40
- IAR C/C++ Development
- Linking your application
- Linking considerations
- Changing the default initialization
Changing the default initialization
By default, memory initialization is performed during application startup. ILINK sets up the initialization process and chooses a suitable packing method. If the default initialization process does not suit your application and you want more precise control over the initialization process, these alternatives are available:
Suppressing initialization
Choosing the packing algorithm
Manual initialization
Initializing code—copying ROM to RAM.
For information about the performed initializations, inspect the log file (the command line option ‑‑log initialization).
Suppressing initialization
If you do not want the linker to arrange for initialization by copying, for some or all sections, make sure that those sections do not match a pattern in an initialize by copy directive—or use an except clause to exclude them from matching. If you do not want any initialization by copying at all, you can omit the initialize by copy directive entirely.
This can be useful if your application, or just your variables, are loaded into RAM by some other mechanism before application startup.
Choosing a packing algorithm
To override the default packing algorithm, write for example:
initialize by copy with packing = lz77 { readwrite };For more information about the available packing algorithms, see initialize directive.
Manual initialization
In the usual case, the initialize by copy directive is used for making the linker arrange for initialization by copying—with or without packing—of sections with content at application startup. The linker achieves this by logically creating an initialization section for each such section, holding the content of the section, and turning the original section into a section without content. The name of this initialization section is the name of the original section with the added suffix _init. For example, the initialization section for the .data section is called .data_init. Then, the linker adds table elements to the initialization table so that the initialization will be performed at application startup.
You can use initialize manually to suppress the creation of table elements to take control over when and how the elements are copied. This is useful for overlays, but also in other circumstances.
For sections without content (zero-initialized sections), the situation is reversed. The linker arranges for zero initialization of all such sections at application startup, except for those that are mentioned in a do not initialize directive.
Simple copying example with an automatic block
Assume that you have some initialized variables in MYSECTION. If you add this directive to your linker configuration file:
initialize manually { section MYSECTION };you can use this source code example to initialize the section:
#pragma section = "MYSECTION"
#pragma section = "MYSECTION_init"
void DoInit()
{
char * from = __section_begin("MYSECTION_init");
char * to = __section_begin("MYSECTION");
memcpy(to, from, __section_size("MYSECTION"));
}This piece of source code takes advantage of the fact that if you use __section_begin (and related operators) with a section name, an automatic block is created by the linker for those sections.
Note
Automatic blocks override the normal section selection process and forces everything that matches the section name to form one block.
Example with explicit blocks
Assume that you instead of needing manual initialization for variables in a specific section, you need it for all initialized variables from a particular library. In that case, you must create explicit blocks for both the variables and the content. Like this:
initialize manually { section .data object mylib.a };
define block MYBLOCK { section .data object mylib.a };
define block MYBLOCK_init { section .data_init object mylib.a };You must also place the two new blocks using one of the section placement directives, the block MYBLOCK in RAM and the block MYBLOCK_init in ROM.
Then you can initialize the sections using the same source code as in the previous example, only with MYBLOCK instead of MYSECTION.
Note
When using manual initialization, you must handle each copy init batch explicitly. The linker will create a separate batch for each combination of source block or placement directive and destination block or placement directive. To see which batches are created, use initialization logging (‑‑log initialization).
In some cases, blocks are created automatically by the linker, which can affect the number of batches. This can happen when using a block with fixed order and when using the first, last, or midway modifiers in extended section selectors.
Overlay example
This is a simple overlay example that takes advantage of automatic block creation:
initialize manually { section MYOVERLAY* };
define overlay MYOVERLAY { section MYOVERLAY1 };
define overlay MYOVERLAY { section MYOVERLAY2 };You must also place overlay MYOVERLAY somewhere in RAM. The copying could look like this:
#pragma section = "MYOVERLAY"
#pragma section = "MYOVERLAY1_init"
#pragma section = "MYOVERLAY2_init"
void SwitchToOverlay1()
{
char * from = __section_begin("MYOVERLAY1_init");
char * to = __section_begin("MYOVERLAY");
memcpy(to, from, __section_size("MYOVERLAY1_init"));
}
void SwitchToOverlay2()
{
char * from = __section_begin("MYOVERLAY2_init");
char * to = __section_begin("MYOVERLAY");
memcpy(to, from, __section_size("MYOVERLAY2_init"));
}Initializing code—copying ROM to RAM
Sometimes, an application copies pieces of code from flash/ROM to RAM. You can direct the linker to arrange for this to be done automatically at application startup, or do it yourself at some later time using the techniques described in Manual initialization.
You need to list the code sections that should be copied in an initialize by copy directive. The easiest way is usually to place the relevant functions in a particular section—for example, RAMCODE— and add section RAMCODE to your initialize by copy directive. For example:
initialize by copy { rw, section RAMCODE };If you need to place the RAMCODE functions in some particular location, you must mention them in a placement directive, otherwise they will be placed together with other read/write sections.
If you need to control the manner and/or time of copying, you must use an initialize manually directive instead. See Manual initialization.
Running all code from RAM
If you want to copy the entire application from ROM to RAM at program startup, use the initialize by copy directive, for example:
initialize by copy { readonly, readwrite };The readwrite pattern will match all statically initialized variables and arrange for them to be initialized at startup. The readonly pattern will do the same for all read-only code and data, except for code and data needed for the initialization.
Because the function __low_level_init, if present, is called before initialization, it and anything it needs, will not be copied from ROM to RAM either. In some circumstances—for example, if the ROM contents are no longer available to the program after startup—you might need to avoid using the same functions during startup and in the rest of the code.
If anything else should not be copied, include it in an except clause. This can apply to, for example, the interrupt vector table.
It is also recommended to exclude the C++ dynamic initialization table from being copied to RAM, as it is typically only read once and then never referenced again. For example, like this:
initialize by copy { readonly, readwrite }
except { section .intvec, /* Don’t copy interrupt table */
section .init_array }; /* Don’t copy C++ init table */