9.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.
To specify multiple attributes, separate them by commas within the double parentheses, for example:
__attribute__ ((aligned (16), packed))
.
aligned
attribute,
and declared extern
in file B without aligned
, then a
link error may result.address (addr)
Specify an absolute virtual address for the variable. This attribute can be used in conjunction with a section attribute.
kseg1_data_mem
region. For data
variables on a target feature an L1 data cache, the address is typically in the range
[0x80000000,0x800FFFFC] as defined in the linker script as the
kseg0_data_mem
region. Take special care to use the correct kseg
region for your device or more than one variable might be allocated to the same physical
address.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.
Also, be aware that variables attributed with an absolute address are not accessed via GP-relative addressing. This means that they may be more expensive to access than non-address attributed variables.
In addition, to make effective use of absolute sections and the 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.
Finally, note that “small” data and bss (.sdata
, .sbss
,
etc.) sections are still mapped in the built-in default linker script. This is because
“small” data variables must be grouped together so that they are within range of the
more efficient GP-relative addressing mode. To avoid conflict with these
linker-script mapped sections, choose high addresses for your absolute-address
variables.
space(prog)
or space(data)
, respectively. Also,
see the description for the attribute space
.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.
coherent
The coherent variable attribute causes the compiler/linker to place the variable into a unique section that is allocated to the kseg1 region, rather than the kseg0 region (which is the default on L1 cached devices). This means that the variable is accessed through the uncached address.
For devices featuring an L1 data cache, data variables are allocated to the KSEG0
data-memory region (kseg0_data_mem
), making it accessible through the
L1 cache. Likewise, the linker-allocated heap and stack are allocated to the KSEG0
region.
The is a coherent
variable attribute that allows you to create a DMA
buffer allocated to the kseg1_data_mem region:
unsigned int __attribute__((coherent)) buffer [1024];
When combining the coherent
attribute with the address
attribute, be sure to use the default data-memory region address for the device. On
devices featuring an L1 data cache, the default data-memory region is
kseg0_data_mem:
unsigned int __attribute__((coherent,address(0x80001000)))
buffer[1024]
The __pic32_alloc_coherent(size_t)
and
__pic32_free_coherent(void*)
functions allocate and free memory
from the uncached kseg1_data_mem region. The default stack is allocated to the cached
kseg0_data_mem region, but you may want to create an uncached DMA buffer, so you can use
these functions to allocate an uncached buffer. These functions call the standard
malloc()/free()
functions, but the pointers that they use are
translated from kseg0 to kseg1.
#include<xc.h>
void jak(void){
char* buffer = __pic32_alloc_coherent(1024);
if (buffer){
/* do somehing */
}
else{
/* handle error */
}
if (buffer){
__pic32_free_coherent(buffer);
}
}
deprecated
deprecated (msg)
When a variable specified as deprecated
is used, a warning is generated.
The optional msg
argument, which must be a string, will be printed in
the warning, if present.
externally_visible
This attribute when used with a global object, nullifies the effect of the
-fwhole-program
command-line option, so 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.
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. The
persistent
attribute causes the compiler to place the variable in
special .bss-like section that does not get cleared by the default startup code. Because
the section is always in data space, this attribute is not compatible with the
space
attribute.
int last_mode __attribute__((persistent));
The persistent
attribute implies the
coherent
attribute. That is, persistent
attributed
variables are accessed via the uncached address.
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.
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, data
for data memory, and
serial_mem
for serial memory such as SPI Flash. The
data
space is the default space for non-const variables.
The prog
, data
, and
serial_mem
spaces normally correspond to the
kseg0_prog_mem
, ksegN_data_mem
, and
serial_mem
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)
or space(serial_mem)
, 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)
and
space(serial_mem)
apply to variables that will be programmed by an
in-circuit programmer or a bootloader.
const unsigned int __attribute__((space(prog))) jack = 10;
const unsigned int __attribute__((space(serial_mem))) zori = 1;
signed int __attribute__((space(data))) oz = 5;
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.