10.5.7. Using GROUP and UNION Statements

Two SECTIONS statements allow you to organize or conserve memory: GROUP and UNION. Grouping sections causes the linker to allocate them contiguously in memory. Unioning sections causes the linker to allocate them to the same run address.

10.5.7.1. Grouping Output Sections Together

The SECTIONS directive’s GROUP option forces several output sections to be allocated contiguously and in the order listed, unless the UNORDERED operator is used. For example, assume that a section named term_rec contains a termination record for a table in the .data section. You can force the linker to allocate .data and term_rec together:

SECTIONS
{
    .text              /* Normal output section             */
    .bss               /* Normal output section             */
    GROUP 0x00001000 : /* Specify a group of sections       */
    {
        .data          /* First section in the group        */
        term_rec       /* Allocated immediately after .data */
    }
}

You can use binding, alignment, or named memory to allocate a GROUP in the same manner as a single output section. In the preceding example, the GROUP is bound to address 0x1000. This means that .data is allocated at 0x1000, and term_rec follows it in memory.

Note

You Cannot Specify Addresses for Sections Within a GROUP

When you use the GROUP option, binding, alignment, or allocation into named memory can be specified for the group only. You cannot use binding, named memory, or alignment for sections within a group.

The MEMORY directive also allows you to use the GROUP keyword to create logical groups of memory ranges for use with Cyclic Redundancy Checks (CRC). See Using the crc_table() Operator in the MEMORY Directive for how to compute CRCs over memory ranges using the GROUP syntax.

10.5.7.2. Overlaying Sections With the UNION Statement

For some applications, you may want to allocate more than one section that occupies the same address during run time. For example, you may have several routines you want in fast external memory at different stages of execution. Or you may want several data objects that are not active at the same time to share a block of memory. The UNION statement within the SECTIONS directive provides a way to allocate several sections at the same run-time address.

In the following example, the .bss sections from file1.c.o and file2.c.o are allocated at the same address in FAST_MEM. In the memory map, the union occupies as much space as its largest component. The components of a union remain independent sections; they are simply allocated together as a unit.

SECTIONS
{
    .text: load = SLOW_MEM
    UNION: run  = FAST_MEM
    {
        .bss:part1: { file1.c.o(.bss) }
        .bss:part2: { file2.c.o(.bss) }
    }
        .bss:part3: run = FAST_MEM { globals.c.o(.bss) }
}

Allocation of a section as part of a union affects only its run address. Under no circumstances can sections be overlaid for loading. If an initialized section is a union member (an initialized section, such as .text, has raw data), its load allocation must be separately specified as shown in the following example. (There is an exception to this rule when combining an initialized section with uninitialized sections; see Using Memory for Multiple Purposes.)

UNION run = FAST_MEM
{
    .text:part1: load = SLOW_MEM, { file1.c.o(.text) }
    .text:part2: load = SLOW_MEM, { file2.c.o(.text) }
}

The following figure shows the memory allocation for the first example above (left) and the second example above (right)

../../../_images/memallocate_tdz075.png

Since the .text sections contain raw data, they cannot load as a union, although they can be run as a union. Therefore, each requires its own load address. If you fail to provide a load allocation for an initialized section within a UNION, the linker issues a warning and allocates load space anywhere it can in configured memory.

Uninitialized sections are not loaded and do not require load addresses.

The UNION statement applies only to allocation of run addresses, so it is meaningless to specify a load address for the union itself. For purposes of allocation, the union is treated as an uninitialized section: any one allocation specified is considered a run address, and if both run and load addresses are specified, the linker issues a warning and ignores the load address.

10.5.7.3. Using Memory for Multiple Purposes

One way to reduce an application’s memory requirement is to use the same range of memory for multiple purposes. You can first use a range of memory for system initialization and startup. Once that phase is complete, the same memory can be repurposed as a collection of uninitialized data variables or a heap. To implement this scheme, use the following variation of the UNION statement to allow one section to be initialized and the remaining sections to be uninitialized.

Generally, an initialized section (one with raw data, such as .text) in a union must have its load allocation specified separately. However, one and only one initialized section in a union can be allocated at the union’s run address. By listing it in the UNION statement with no load allocation at all, it will use the union’s run address as its own load address.

For example:

UNION run = FAST_MEM { .cinit .bss }

In this example, the .cinit section is an initialized section. It will be loaded into FAST_MEM at the run address of the union. In contrast, .bss is an uninitialized section. Its run address will also be that of the union.

10.5.7.4. Nesting UNIONs and GROUPs

The linker allows arbitrary nesting of GROUP and UNION statements with the SECTIONS directive. By nesting GROUP and UNION statements, you can express hierarchical overlays and groupings of sections. The following example shows how two overlays can be grouped together.

SECTIONS
{
    GROUP 0x1000 : run = FAST_MEM
    {
        UNION:
        {
            mysect1: load = SLOW_MEM
            mysect2: load = SLOW_MEM
        }
        UNION:
        {
            mysect3: load = SLOW_MEM
            mysect4: load = SLOW_MEM
        }
    }
}

For this example, the linker performs the following allocations:

  • The four sections (mysect1, mysect2, mysect3, mysect4) are assigned unique, non-overlapping load addresses. The name you defined with the .label directive is used in the SLOW_MEM memory region.This assignment is determined by the particular load allocations given for each section.

  • Sections mysect1 and mysect2 are assigned the same run address in FAST_MEM.

  • Sections mysect3 and mysect4 are assigned the same run address in FAST_MEM.

  • The run addresses of mysect1/mysect2 and mysect3/mysect4 are allocated contiguously, as directed by the GROUP statement (subject to alignment and blocking restrictions).

To refer to groups and unions, linker diagnostic messages use the notation:

GROUP_n UNION_n

where n is a sequential number (beginning at 1) that represents the lexical ordering of the group or union in the linker control file without regard to nesting. Groups and unions each have their own counter.

10.5.7.5. Checking the Consistency of Allocators

The linker checks the consistency of load and run allocations specified for unions, groups, and sections. The following rules are used:

  • Run allocations are only allowed for top-level sections, groups, or unions (sections, groups, or unions that are not nested under any other groups or unions). The linker uses the run address of the top-level structure to compute the run addresses of the components within groups and unions.

  • The linker does not accept a load allocation for UNIONs.

  • The linker does not accept a load allocation for uninitialized sections.

  • In most cases, you must provide a load allocation for an initialized section. However, the linker does not accept a load allocation for an initialized section that is located within a group that already defines a load allocator.

  • As a shortcut, you can specify a load allocation for an entire group, to determine the load allocations for every initialized section or subgroup nested within the group. However, a load allocation is accepted for an entire group only if all of the following conditions are true:

    • The group is initialized (that is, it has at least one initialized member).

    • The group is not nested inside another group that has a load allocator.

    • The group does not contain a union containing initialized sections.

  • If the group contains a union with initialized sections, it is necessary to specify the load allocation for each initialized section nested within the group. Consider the following example:

SECTIONS
{
    GROUP: load = SLOW_MEM, run = SLOW_MEM
    {
        .text1:
        UNION:
        {
            .text2:
            .text3:
        }
    }
}

The load allocator given for the group does not uniquely specify the load allocation for the elements within the union: .text2 and .text3. In this case, the linker issues a diagnostic message to request that these load allocations be specified explicitly.

10.5.7.6. Naming UNIONs and GROUPs

You can give a name to a UNION or GROUP by entering the name in parentheses after the declaration. For example:

GROUP(BSS_SYSMEM_STACK_GROUP)
{
    .bss    :{}
    .sysmem :{}
    .stack  :{}
} load=D_MEM,  run=D_MEM

The name you defined is used in diagnostics for easy identification of the problem LCF area. For example:

warning: LOAD placement  ignored for "BSS_SYSMEM_STACK_GROUP": object is uninitialized

UNION(TEXT_CINIT_UNION)
{
    .const  :{}load=D_MEM, table(table1)
    .rodata :{}load=D_MEM, table(table1)
    .pinit  :{}load=D_MEM, table(table1)
}run=P_MEM

warning:table(table1) operator ignored: table(table1) has already been applied to a section
in the "UNION(TEXT_CINIT_UNION)" in which ".pinit" is a descendant