7.2.8 Automatic placement of __at sections

The linker automatically places __at sections, but you can override this.

The automatic placement of __at sections is enabled by default. This feature is controlled by the linker command-line option, --autoat.


You cannot use __at section placement with position independent execution regions.

When linking with the --autoat option, the __at sections are not placed by the scatter-loading selectors. Instead, the linker places the __at section in a compatible region. If no compatible region is found, the linker creates a load and execution region for the __at section.

All linker --autoat created execution regions have the UNINIT scatter-loading attribute. If you require a ZI __at section to be zero-initialized then it must be placed within a compatible region. A linker --autoat created execution region must have a base address that is at least 4 byte-aligned. The linker produces an error message if any region is incorrectly aligned.

A compatible region is one where:

  • The __at address lies within the execution region base and limit, where limit is the base address + maximum size of execution region. If no maximum size is set, the linker sets the limit for placing __at sections as the current size of the execution region without __at sections plus a constant. The default value of this constant is 10240 bytes, but you can change the value using the --max_er_extension command-line option.

  • The execution region meets at least one of the following conditions:

    • It has a selector that matches the __at section by the standard scatter-loading rules.

    • It has at least one section of the same type (RO, RW or ZI) as the __at section.

    • It does not have the EMPTY attribute.


      The linker considers an __at section with type RW compatible with RO.


The following example shows the manual placement of variables is achieved in C or C++ code, with the sections .ARM.__at_0x0000 type RO, .ARM.__at_0x2000 type RW, .ARM.__at_0x4000 type ZI, and .ARM.__at_0x8000 type ZI:

// place the RO variable in a section called .ARM.__at_0x00000000
const int baz __attribute__((at(0x0000))) = 100;
// place the RW variable in a section called .ARM.__at_0x00002000
int foo __attribute__((at(0x2000))) = 100;
// place the ZI variable in a section called .ARM.__at_0x00004000
int bar __attribute__((at(0x4000), zero_init));
// place the ZI variable in a section called .ARM.__at_0x00008000
int variable __attribute__((at(0x8000), zero_init));

The following scatter file shows how the placement of __at sections is achieved automatically:

LR1 0x0
    ER_RO 0x0 0x2000
        *(+RO)      ; .ARM.__at_0x00000000 lies within the bounds of ER_RO
    ER_RW 0x2000 0x2000
        *(+RW)      ; .ARM.__at_0x00002000 lies within the bounds of ER_RW
    ER_ZI 0x4000 0x2000
        *(+ZI)      ; .ARM.__at_0x00004000 lies within the bounds of ER_ZI
; The linker creates a load and execution region for the __at section
; .ARM.__at_0x00008000 because it lies outside all candidate regions.
Non-ConfidentialPDF file icon PDF versionARM DUI0474M
Copyright © 2010-2016 ARM Limited or its affiliates. All rights reserved.