Take you through scatter loading (with code)

(Simply put) The purpose of scatter-loading is to let the MCU core know where the code is stored and where the data is stored, which specific address to find the function that needs to be run next, and tell the compiler to put each compiled function , The specific physical address where the data is placed.

(Technically speaking) A scatter file is a text file that describes the information that a linker needs to generate an image file. By writing a scatter-loading file to specify how the ARM connector allocates the storage addresses of Code, RO-Data, RW-Data, ZI-Data and other data when generating the image file. If no scatter-loading file is specified, the ARM linker will generate the image file in the default way of the default project configuration. Normally we don't need to use scatter-loading files. However, for some special cases, such as when different program codes need to be stored in different address areas, it is necessary to modify the scatter-loading file.

Table of contents

basic concept

Overview of scatter-loading description file syntax

Load time domain description

Description of the runtime domain

Enter a section description

Simple scatter-loading memory map example

Complex scatter-loading memory map example


basic concept

Code: Indicates the program code part;

RO-Data: Indicates all constants and const data defined by the program;

RW-Data: Indicates all static variables that have been initialized, and the variables have initial values;

ZI-Data: Indicates all uninitialized static variables, and the variables have no initial value.

Examples of various types of data declarations are as follows:

#define      	DATA     	(0x10000000)     /* RO-Data*/
char const   	GcChar = 5;                  /* RO-Data*/
char        	GcStr[] = "string.";         /* RW-Data*/
char        	GcZero;                      /* ZI-Data*/

The initialization of variables is done in the __main() function. __main() is automatically created and generated by the compiler. It can automatically complete all variable initializations, and can also automatically generate copy codes, etc. After executing __main(), you can see that there are two large functions: __scatterload() and __rt_entry().

__main(): Complete the copy of code and data, and clear the ZI data area. Code copy can copy the code to another mapping space and execute it, such as copying the code to RAM for execution; data copying completes the RW segment data assignment; data area clearing completes the ZI segment data assignment. The code above is closely related to scatter-loading files.

__scatterload(): Responsible for copying the RW/RO output section from the loading domain address to the running domain address, and completing the initialization of the ZI running domain.

_rt_entry(): Initialize STACK and HEAP. Finally, _rt_entry jumps into the main() function entry. When the main() function is executed, _rt_entry returns control to the debugger.

ZI-Data variable initialization method: put all the variables without initial value together consecutively, and initialize them to zero. It has a name called zero-segment variable, and the term (namely the name in the scatter-loading file) is ZI.

The way to complete the initialization of RW-Data: RW-Data occupies both Flash and RAM, and occupies the same size. The initialization method is briefly described as follows: First, the compiler plans all the variables with initial values ​​together, which is RW Segment variables, the term is RW; secondly, the compiler stores their initial values ​​in Flash in order; finally, when initializing, you only need to copy the initial value corresponding to RW in Flash to the corresponding RAM.

Overview of scatter-loading description file syntax

A scatter-loading file mainly consists of a load-time field and a runtime field. in:

Loading time domain, as the name implies, is used to load and store data, including Code, RO-Data and RW-Data;

The runtime domain is used to allocate variables and code mapping space for runtime, including Code, ZI-Data, and RW-Data.

Typical organization of a scatter-loading description file:

3fd9b6d163fc45fbac5533ea814ea2a8.png

Load time domain description

Load Time Domain In the BNF syntax format, the load time domain is generally used to specify an area to store read-only data.

load_region_description ::=

load_region_name(base_address|("+"offset))[attribute_list][max_size]

{
    execution_region_description+
}

The meaning of each of them is explained below.

load_region_name: the name of the loading time domain, the name can be defined according to the user's wishes, and only the first 31 characters in the name are meaningful;

base_designator: It is used to indicate the starting address of the loading time domain, which can have one of the following two formats: base_address: indicates the starting address of the object in the loading time domain when connecting, and the address must be word-aligned; +offset: Indicates that the start address of the object in this loading time domain at the time of connection is the offset byte after the end address of the previous loading time domain. This loading time domain is the first loading time domain, its starting address is offset, and the value of offset must be divisible by 4.

attribute_list: Specify the attributes of the loading time domain content, including the following types, the default loading time domain attribute is ABSOLUTE. ABSOLUTE: absolute address; PI: position-independent; RELOC: relocatable; OVERLAY: overlay; NOCOMPRESS: no compression.

max_size: Specifies the maximum size of the loading time domain. If the actual size of the loaded time domain exceeds this value, the linker will report an error, and the default value is 0xFFFFFFFF;

execution_region_description: Indicates the runtime domain, followed by a + sign, indicating that it can have one or more runtime domains.

Load the components in the time domain description:

4552a28b06d44f86bb76bb689187f10e.png

Description of the runtime domain

The runtime domain syntax format is as follows, which is generally used to allocate variables and code mapping space for runtime.

execution_region_description ::=

exec_region_name(base_address|"+"offset)[attribute_list][max_size|" "length]

{
    input_section_description*
}

The meaning of each is explained below:

exec_region_name: The name of the loading time domain. The name can be defined according to the user's wishes. Only the first 31 characters in the name are meaningful;

base_address: It is used to indicate the starting address of the loading time domain, which can have one of the following two formats: base_address: indicates the starting address of the object in the loading time domain when connecting, and the address must be word-aligned; +offset: Indicates that the start address of the object in this loading time domain when connecting is at the offset byte after the end address of the previous loading time domain, and the value of offset must be divisible by 4.

attribute_list: Specify the attributes of the loading time domain content: ABSOLUTE: absolute address; PI: independent of position; RELOC: relocatable; OVERLAY: overlay; FIXED: fixed address. Both the load address and the execution address of the region are specified by the base address indicator, which must be an absolute base address, or an offset of 0. ALIGNalignment: Increase the alignment constraint of the execution region from 4 to alignment. alignment must be a positive power of 2. If the execution region has a base_address, it must be aligned. If the execution area has an offset, the linker aligns the calculated area base address with the alignment boundary; EMPTY: Reserve a blank memory block of a given length in the execution area, usually for heap or stack use. ZEROPAD: Zero-initialized segments are written to the ELF file as zero-filled blocks, so no padding with zeros is required at runtime; PADVALUE: Defines the value for any padding. If PADVALUE is specified, it must be assigned a value; NOCOMPRESS: no compression; UNINIT: uninitialized data.

max_size: Specifies the maximum size of the loading time domain. If the actual size of the loaded time domain exceeds this value, the linker will report an error, and the default value is 0xFFFFFFFF;

length: If the specified length is negative, base_address will be used as the end address of the zone. It is often used with EMPTY to indicate a stack that becomes smaller in memory.

input_section_description: Specifies the content of the input section.

Components in the runtime domain description:

c2b3e0d578854adb972262daf146afab.png

Enter a section description

The input section is in the above-mentioned runtime domain, the detailed format is not given, and its syntax is described as follows.

input_section_description ::=

module_select_pattern[ "(" input_section_selector ( "," input_section_selector )* ")" ]

input_section_selector ::=

("+" input_section_attr | input_section_pattern | input_symbol_pattern)

module_select_pattern: object file filter, supports the use of wildcards "*" and "?". Where the symbol "*" represents zero or more characters, and the symbol "?" represents a single character. All characters are case-insensitive when matching. The input section will be matched against the module selector pattern when module_select_pattern matches one of the following: names of containing sections and object files; library member names (without leading pathnames); full names of libraries (including pathnames) , you can use wildcards to simplify your search if the name contains spaces, for example, *libname.lib matches C:\lib dir\libname.lib.

nput_section_attr: Attribute selector to match input section attributes. Each input_section_attr is preceded by a "+" sign. If a pattern is specified to match input section names, the name must be preceded by a "+" sign. Any comma immediately preceding the "+" sign can be omitted. Selectors are not case sensitive. The following selectors are recognized: RO-CODE;RO-DATA;RO, select both RO-CODE and RO-DATA; RW-DATA;RW-CODE;RW, select both RW-CODE and RW-DATA;ZI;ENTRY: That is, the segment containing the ENTRY point. The following synonyms are recognized: CODE for RO-CODE; CONST for RO-DATA; TEXT for RO; DATA for RW; BSS for ZI. The following pseudo-attributes are recognized: FIRST;LAST. An input section can be assigned to an execution region regardless of its parent module by using the special module selector pattern .ANY. Runtime fields can be filled in arbitrary distributions using one or more .ANY patterns. In most cases, using a single .ANY is equivalent to using the *module selector.

Component diagram for input segment description:

bf4deebeeb1c4a75966553659f835a23.png

Simple scatter-loading memory map example

LOAD_ROM 0x0000 0x8000                              ; Name of load region (LOAD_ROM),
                                                    ; Start address for load region (0x0000),
                                                    ; Maximum size of load region (0x8000)
{
  EXEC_ROM 0x0000 0x8000                            ; Name of first exec region (EXEC_ROM),
                                                    ; Start address for exec region (0x0000),
                                                    ; Maximum size of first exec region (0x8000)
    {
     * (+RO)                                        ; Place all code and RO data into
                                                    ; this exec region
    }
  
  SRAM 0x10000 0x6000                               ; Name of second exec region (SRAM),
                                                    ; Start address of second exec region (0x10000),
                                                    ; Maximum size of second exec region (0x6000)
    {
     * (+RW, +ZI)                                   ; Place all RW and ZI data into
                                                    ; this exec region
    }
}

The memory map of the above file:

dc3f74c20d8e401fb3b3d2d199b1848f.jpeg

Complex scatter-loading memory map example

LOAD_ROM_1 0x0000                            ; Start address for first load region (0x0000)
{
  EXEC_ROM_1 0x0000                          ; Start address for first exec region (0x0000)
  {
    program1.o (+RO)                         ; Place all code and RO data from
                                             ; program1.o into this exec region
  }
  DRAM 0x18000 0x8000                        ; Start address for this exec region (0x18000),
                                             ; Maximum size of this exec region (0x8000)
  {
    program1.o (+RW, +ZI)                    ; Place all RW and ZI data from
                                             ; program1.o into this exec region
  }
}

LOAD_ROM_2 0x4000                            ; Start address for second load region (0x4000)
{
  EXEC_ROM_2 0x4000
  {
    program2.o (+RO)                         ; Place all code and RO data from
                                             ; program2.o into this exec region
  }
  SRAM 0x8000 0x8000
  {
    program2.o (+RW, +ZI)                    ; Place all RW and ZI data from
                                             ; program2.o into this exec region
  }
}

The memory map of the above file:

4d0ca54b42d548958aa304a8c19cf47e.jpeg

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_30095921/article/details/128905054