16.2.1 Function Attributes

access(access-mode, ref-index[, size-index])

The access attribute provides additional information about how a function accesses memory. It can assist in diagnosing potential bugs related to memory access via compiler warnings and help the compiler perform better optimizations.

The ref-index argument is the index (starting from the left with index 1) of the function pointer argument that points to the target object being accessed. A function pointer argument can be referenced by at most one distinct access attribute.

The access_mode argument specifies the type of memory access made by the pointer referenced by the ref-index and can be one of the following:
read_only
The pointer only reads from the target object. Unless the indexed size argument is zero, the target object must be initialized. This check is more robust than just using the const qualifier with the target as it cannot be cast away.
write_only
The pointer (which cannot be to a const-qualified type) only writes to the target object. The object referenced by the pointer need not be initialized.
read_write
The pointer (which cannot be to a const-qualified type) both reads from and writes to the target object. Unless the indexed size argument is zero, the target object must be initialized.
none
The pointer does not access the target object at all. Unless the pointer is NULL, the target object must exist and have at least the size held by the size-index argument. If the size-index argument is omitted for a pointer of void * type, the actual pointer argument is ignored. The referenced object need not be initialized. The mode is intended to be used as a means to help validate the expected object size, for example in functions that call __builtin_object_size.

The optional size-index argument is the index of the function argument that specifies the number of elements of the pointer type referenced by ref-index, or the number of bytes when the pointer type is void *. When this argument is not specified, the pointer argument must be either NULL or point to a space that is suitably aligned and sized for at least one object of the referenced type (this implies that a past-the-end pointer is not a valid argument). The actual size of the access may be less but it must not be more.

For example, the following code uses the access attribute to declare that the pointer argument to puts() will only read its target of unspecified size. The attribute is used again to indicate that the second argument to memcpy() only reads its target and that this target has a size indicated by the value of the third function argument.
__attribute__ ((access (read_only, 1))) int puts(const char *);

__attribute__ ((access (read_only, 2, 3))) void * memcpy(void *, const void *, size_t);

address(addr)

The address attribute specifies an absolute physical address at which the attributed routine will be placed in memory. It can be used with C and C++ functions. For example:
__attribute__((address(0x460000))) void bar (void);

The compiler performs no error checking on the address value, so the application must ensure the value is valid for the target device. The section containing the function will be located at the specified address regardless of the memory-regions specified in the linker script or the actual memory ranges on the target device. The application code must ensure that the address is valid for the target device.

Sections used to hold functions 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.

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 sections. 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.

alias ("symbol")

Indicates that the function is an alias for another symbol. For example:
 void foo (void) { /* stuff */ }
 __attribute__ ((alias("foo"))) void bar (void);

In the above example, the symbol bar is considered to be an alias for the symbol foo.

always_inline

Instructs the compiler to always inline a function declared as inline, even if no optimization level was specified, for example:
void __attribute__ ((always_inline))  foo (void);

const

If the result of a pure function is determined exclusively from its parameters (i.e., does not depend on the values of any global variables), it may be declared with the const attribute, allowing for even more aggressive optimization. Note that a function which de-references a pointer argument cannot be declared const if it depends on the referenced value, as the referenced storage is not considered a parameter of the function. For example:
int __attribute((const)) rv(int a);

deprecated


deprecated (msg)

When a function specified as deprecated is used, the compiler will generate a warning. The optional msg argument, which must be a string, will be printed in the warning if present. The deprecated attribute may also be used for variables and types, for example:
void __attribute__ ((deprecated ("The bar function is no longer used"))) bar (void);

externally_visible

This attribute when used with a function ensures the function remains visible outside the current compilation unit. This might prevent certain optimizations from being performed on the function, for example:
void __attribute__((externally_visible)) foo (void);

format (type, format_index, first_to_check)

The format attribute indicates that the function takes a printf, scanf, strftime, or strfmon style format string at position index in the argument list, and instructs the compiler to type-check the arguments starting at first_to_check against the conversion specifiers in the format string, just as it does for the standard library functions, for example:
extern int __attribute__ ((format (printf, 2, 3))) my_printf (void * my_object, const char *my_format, ...);

The type parameter is one of printf, scanf, strftime or strfmon (optionally with surrounding double underscores, e.g., __printf__) and determines how the format string will be interpreted.

The format_index parameter specifies the position of the format string in the function's parameters. Function parameters are numbered from the left, starting from index 1.

The first_to_check parameter specifies the position of the first parameter to check against the format string. All parameters following the parameter indicated by first_to_check will be checked. If first_to_check is zero, type checking is not performed, and the compiler only checks the format string for consistency.

format_arg(index)

The format_arg attribute specifies that a function manipulates a printf style format string and that the compiler should check the format string for consistency. The index parameter gives the position of the format string in the parameter list of the function, numbered from the left beginning at index 1. For example:
extern char * __attribute__ ((format_arg (2))) my_foo (char *my_str, const char *my_format);

interrupt


interrupt(type)

Functionally equivalent to the isr attribute.

isr

isr(type)

Instructs the compiler to generate prologue and epilogue code for the function as an interrupt handler function, as described in Interrupts. For Cortex-A devices, the type argument specifies the type of the interrupt, which may be one of the identifiers irq, fiq, abort, undef or swi, in lowercase or uppercase. Any argument specifed is ignore when building for Cortex-M devices.

keep

The keep attribute prevents the linker from removing an unused function when --gc-sections is in effect, for example:
void __attribute__((keep)) foo(void);

long_call

Always call the function with an indirect call instruction, for example:
void __attribute__((long_call)) foo(void);

malloc

The malloc attribute asserts that any non-null pointer return value from the function will not be aliased to any other pointer which is live at the point of return from the function. This allows the compiler to perform more aggressive optimizations, for example:
void __attribute__ ((malloc)) *custom_malloc (int size_t);  

naked

Indicates that the compiler should generate no prologue or epilogue code for the function. For example:
void __attribute__ ((naked)) foo(void);

noinline

A function declared with the noinline attribute will never be considered for inlining, regardless of optimization level, for example:
void __attribute__ ((noinline)) foo(void);

nonnull(index, ...)

Indicate to the compiler that one or more pointer arguments to the function must be non-null. When the -Wnonnull option is in effect, the compiler will issue a warning diagnostic if it can determine that the function is called with a null pointer supplied for any nonnull argument. The index argument(s) indicate the position of the pointer arguments required to be non-null in the parameter list of the function, numbered from the left starting at index 1. If no arguments are provided, all pointer arguments of the function will be marked as non-null. For example:
void *  __attribute__((nonnull)) my_memset (void * ptr, int x, size_t len);

nopa

Indicate to the compiler that the assembly code generated for this function should not be considered when performing procedural abstraction, for example:
void  __attribute__((nopa)) setMode (char * msg, unsigned t_sec);

noreturn

Indicate to the compiler that the function will never return control to its caller. In some situations, this can allow the compiler to generate more efficient code in the calling function, since optimizations can be performed without regard to behavior if the function ever did return. Functions declared with noreturn should always have a void return type. For example:
void __attribute__ ((noreturn)) myExit(void);

optimize(optimization)

The optimize attribute allows a function to be built with optimizations that differ to what has been specified on the command line and which will be applied to the rest of the program. The optimization argument can either be a number or a string. String arguments represent the command-line option used to control an optimization, so for example, to enable peephole optimizations (-fpeephole), use optimize("peephole"). The -f option prefix does not need to be specified with the argument. If you want to specify more than one optimization, separate the arguments with commas but with no space characters. Arguments that begin with O are assumed to be an optimization level option, for example optimize("O1,unroll-loops") turns on level 1 optimizations and the unroll-loops optimizations (controlled by the -funroll-loops command-line option). A numerical argument is also assumed to be an optimization level, for example optimize(3) turns on level 3 optimizations and is equivalent to the full usage of the attribute in the following example.
int __attribute__((optimize("O3"))) pandora (void) {
  if (maya > axton)
    return 1;
  return 0;
}
This feature can be used, for instance, to have frequently executed functions compiled with more aggressive optimization options that produce faster and larger code, while other functions can be called with less aggressive options. Typically, however, it is not used for production builds.

pure

Indicates to the compiler that the function is pure, allowing for more aggressive optimizations in the presence of calls to the function. A pure function has no side effects other than its return value, and the return value is dependent only on parameters and/or (non-volatile) global variables, for example:
void __attribute__ ((pure)) foo(void);

ramfunc

The ramfunc attribute locates the attributed routine in RAM rather than in Flash memory on devices that normally execute code from Flash. This attribute can be used for both C functions and C++ class methods. The compiler's default runtime startup code uses the data-initialization template to copy the code associated with functions using this attribute from Flash to RAM at program startup.

For example, the following defines a C function placed in data memory:
__attribute__((ramfunc))
unsigned int myramfunct(void)
{ /* code */ }
The <sys/attribs.h> header file provides a __ramfunc__ macro that is useful for this purpose. For example:
#include <sys/attribs.h>
__ramfunc__ unsigned int myramfunct(void)
{ /* code */ }
In C++ code, it can be used with class methods, as shown in the following example.
class printmyname {
    // Access specifier
public:
    // Data  Members
    string myname;
    int  dummy ;
    // Member Functions()
    printmyname (){
        myname = "microchip";
    }
    
    void  __attribute__((ramfunc, long_call)) set_name(string newname){
        myname = newname;
        dummy = 9;
    }
    void printname() { cout << "name is:" << myname; }
};
The branch/call instruction BL has a limited range (32MB for ARM instructions, 16MB for Thumb2 and 4MB for Thumb). As a result, RAM might not be within range of calls made from code in Flash. To allow such calls, additionally use the long_call attribute with the definition of the function located in RAM when it must be called from functions in Flash. For example:
__attribute__((ramfunc, long_call))
unsigned int myramfunct(void)
{ /* code */ }
The <sys/attribs.h> header file provides a __longramfunc__ macro that will specify both the ramfunc and long_call attributes. For example:
#include <sys/attribs.h>
__longramfunc__ unsigned int myramfunct(void)
{ /* code */ }
If a function in Flash is called by a function located in RAM, the Flash-based function definition must include the long_call attribute.
__attribute__ ((long_call))
unsigned int myflashfunct(void)
{ /* code */ }

__attribute__((ramfunc))
unsigned int myramfunct(void)
{
        return myflashfunct();
}

Having functions located in RAM rather than Flash can increase code size as well as startup time, as the attributed functions must be copied from Flash to RAM at startup. It may also have an impact on runtime performance, depending on your target device. Verify that your application meets your startup timing constraints. Also verify that the increased runtime performance meets your application's timing requirements and that your application does not have hidden dependencies on timing that is negatively impacted by this design selection.

section("name")

Place the function into the given named section. For example:

void __attribute__ ((section (".wilma"))) baz () {return;}

In the above example, function baz will be placed in section .wilma. The -ffunction-sections command line option has no effect on functions declared with the section attribute.

short_call

Always call the function using an absolute call instruction, even when the -mlong-calls command line option is specified, for example:
void __attribute__ ((short_call)) foo(void);

space(id)

Place the function in the memory space identified by the id argument. The id argument may be prog, which places the function in the program space (i.e., ROM), or data, which places the function in a data section (i.e., RAM). Unlike the section attribute, the actual section is not explicitly specified, for example:
void __attribute__ ((space(prog))) foo(void);

[no_]stack_protector

The stack_protector attribute adds stack protection code to the function if one of the following options is set: -fstack-protector, -fstack-protector-strong, or -fstack-protector-explicit. For example:
void __attribute__ ((stack_protector)) foo(void);
Optimizations can affect stack protection in the following ways:
  • Function inlining can affect whether a function is protected.
  • Removal of an unused variable can prevent a function from being protected.

The no_stack_protector attribute can alternatively be used to disable protection for the specified function, even when one of the stack protection options has been issued.

tcm

Attempt to place the function in tightly-coupled memory (TCM), providing highly consistent access times. The actual section will be determined by the compiler, possibly based on other attributes such as space. For example:

void __attribute__((tcm)) foo (void) {return;}

In the above example, the compiler will attempt to place foo in the itcm memory section, or the tcm section on those processors where the code and data memory spaces are combined. Note that the amount of TCM available in program or data memory on the target device may vary, so the compiler cannot ensure all functions with the tcm attribute can be placed in TCM.

Also see Tightly-Coupled Memories.

unique_section

Place the function in a uniquely named section, as if -ffunction-sections were in effect. If the function also has a section attribute, the given section name will be used as a prefix for the generated unique section name. For example:

void __attribute__ ((section (".fred"), unique_section) foo (void) {return;}

In the above example, function foo will be placed in section .fred.foo.

unsupported

Indicate to the compiler that the function is not supported, similar to the deprecated attribute. A warning will be issued if the function is called. For example:
void __attribute__ ((unsupported)) legacyRead(void);

unused

Indicate to the compiler that the function may not be used. The compiler will not issue a warning for this function if it is not used, for example:
void __attribute__ ((unused)) opt_setting(void);

used

Indicate to the compiler that the function is always used and code must be generated for the function even if the compiler cannot determine that the function is called, e.g., if a status function is only called from an inline assembly statement. For example:
void __attribute__ ((used)) foo(void);

warn_unused_result

A warning will be issued if the return value of the indicated function is unused by a caller. For example:
void __attribute__ ((warn_unused_result)) foo(void);

weak

A weak symbol indicates that if another version of the same symbol is available, that version should be used instead. For example, this is useful when a library function is implemented such that it can be overridden by a user written function. For example:
void __attribute__ ((weak)) foo(void);