8.11 Variable Attributes

The compiler keyword __attribute__ allows you to specify special attributes of variables or structure fields. This keyword is followed by an attribute specification inside double parentheses.

You may also specify attributes with __ (double underscore) preceding and following each keyword (e.g., __aligned __ instead of aligned). This allows you to use them in header files without being concerned about a possible macro of the same name.

To specify multiple attributes, separate them by commas within the double parentheses, for example:

__attribute__ ((aligned (16), packed)).

Note: It is important to use variable attributes consistently throughout a project. For example, if a variable is defined in file A with the an attribute, and declared extern in file B without the same attribute, then a link error might result.

address (addr)

Specify an absolute virtual address for the variable. This attribute can be used in conjunction with a section attribute.

This attribute can be used to start a group of variables at a specific address:

 int foo __attribute__((section("mysection"),address(0xA0001000)));

 int bar __attribute__((section("mysection")));

 int baz __attribute__((section("mysection")));

Keep in mind that the compiler performs no error checking on the specified address. The section will be located at the specified address regardless of the memory-region ranges listed in the linker script or the actual ranges on the target device. This application code is responsible for ensuring that the address is valid for the target device and application.

Sections used to hold objects placed at an absolute address will use a name .address.N.decl, where N is the address and decl is the name of the declaration.

In addition, to make effective use of absolute sections and the new best-fit allocator, standard program-memory and data-memory sections should not be mapped in the linker script. The built-in linker script does not map most standard sections such as the .text, .data, .bss, or .ramfunc section. By not mapping these sections in the linker script, we allow these sections to be allocated using the best-fit allocator rather than the sequential allocator. Sections that are unmapped in the linker script can flow around absolute sections whereas sections that are linker-script mapped are grouped together and allocated sequentially, potentially causing conflicts with absolute sections.

Note: In almost all cases, you will want to combine the address attribute with the space attribute to indicate code or data with space(prog) or space(data), respectively. Also, see the description for the space attribute.

aligned (n)

The attributed variable will be aligned on the next n byte boundary.

The aligned attribute can also be used on a structure member. Such a member will be aligned to the indicated boundary within the structure.

If the alignment value n is omitted, the alignment of the variable is set 8 (the largest alignment value for a basic data type).

Note that the aligned attribute is used to increase the alignment of a variable, not reduce it. To decrease the alignment value of a variable, use the packed attribute.

cleanup (function)

Indicate a function to call when the attributed automatic function scope variable goes out of scope.

The indicated function should take a single parameter, a pointer to a type compatible with the attributed variable, and have void return type.

externally_visible

This attribute when used with a global object ensures the object remains visible outside the current compilation unit. This might prevent certain optimizations from being performed on the object.

noload

The noload attribute causes the variable or function to be placed in a section that has the noload attribute set. This attribute tells consumers of the ELF file not to load the contents of the section. This attribute can be useful when you just want to reserve memory for something, but you don't want to clear or initialize memory.

packed

The attributed variable or structure member will have the smallest possible alignment. That is, no alignment padding storage will be allocated for the declaration. Used in combination with the aligned attribute, packed can be used to set an arbitrary alignment restriction greater or lesser than the default alignment for the type of the variable or structure member.

persistent

The persistent attribute specifies that the variable should not be initialized or cleared at startup. Use a variable with the persistent attribute to store state information that will remain valid after a device Reset. For example:
int last_mode __attribute__((persistent));

The persistent attribute typically causes the compiler to place the variable in the .pbss section, which does not get cleared by the default runtime startup code; however, that might not be the case if the object is defined using other attributes. For example, use of either the address or section attributes in addition to persistent will place the object in sections with different names. Because the section used for persistent objects must be placed in data space, this attribute is not compatible with the space attribute. The const qualifier can be used with the persistent attribute provided the object is not initialized. Any attempt to initialize such an object will result in a warning and the initial value ignored.

Note that on microcontrollers featuring an L1 cache, cache reinitialization may cause the runtime value of the variable to change. For devices with an L1 cache and a Memory Protection Unit (MPU), you may choose to use the Memory Protection Unit to create an uncached region of RAM and place the persistent variable into that region.

section ("section-name")

Place the variable into the named section.

For example,

unsigned int dan __attribute__ ((section (".quixote")))

Variable dan will be placed in section .quixote.

The -fdata-sections command line option has no effect on variables defined with a section attribute unless unique_section is also specified.

space(memory-space)

The space attribute can be used to direct the compiler to allocate a variable in a specific memory space. Valid memory spaces are prog for program memory and data for data memory. The data space is the default space for non-const variables.

The prog and data spaces normally correspond to the rom, ram memory regions, respectively, as specified in the default device-specific linker scripts.

This attribute also controls how initialized data is handled. The linker generates an entry in the data-initialization template for the default space(data), but it does not generate an entry for space(prog), since the variable is located in non-volatile memory. Typically, this means that space(data) applies to variables that will be initialized at runtime startup; while space(prog) apply to variables that will be programmed by an in-circuit programmer or a bootloader. For example:
const unsigned int __attribute__((space(prog))) jack = 10;
signed int __attribute__((space(data))) oz = 5;

tcm

The tcm attribute can be applied to data items, where it directs the linker to place the item in the appropriate tightly-coupled memory (TCM) section, that being dtcm, or tcm on those processors where the code and data memory spaces are combined. If no such section is specified in the linker script, this attribute is ignored and a warning is printed. TCM can be used to provide faster and more predictable execution. See Chip-Level Security and Arm® TrustZone® Technology for more details on TCM. This attribute will generally not be supported by other distributions of gcc.

unique_section

Place the variable in a uniquely named section, just as if -fdata-sections had been specified. If the variable also has a section attribute, use that section name as the prefix for generating the unique section name.

For example,

int tin __attribute__ ((section (".ofcatfood"), unique_section)

Variable tin will be placed in section .ofcatfood.

unused

Indicate to the compiler that the variable may not be used. The compiler will not issue a warning for this variable if it is not used.

used

Indicate to the compiler that the object is always used and storage must be allocated for the object, even if the compiler cannot see a reference to it. For example, if inline assembly is the only reference to an object.

weak

The weak attribute causes the declaration to be emitted as a weak symbol. A weak symbol indicates that if a global version of the same symbol is available, that version should be used instead.

When weak is applied to a reference to an external symbol, the symbol is not required for linking. For example:

extern int __attribute__((weak)) s;
int foo() {
  if (&s) return s;  
  return 0; /* possibly some other value */
}

In the above program, if s is not defined by some other module, the program will still link but s will not be given an address. The conditional verifies that s has been defined (and returns its value if it has). Otherwise '0' is returned. There are many uses for this feature, mostly to provide generic code that can link with an optional library.