5.8.3 Changing the Default Function Allocation

You can change the default memory allocation of functions by either:

  • Reserving memory locations
  • Making functions absolute
  • Placing functions in their own section and linking that section

If you wish to prevent functions from using one or more program memory locations so that these locations can be used for some other purpose, it is recommended to reserve the memory using the memory adjust options (see 4.6.1.18 Reserve Option).

The easiest method to explicitly place individual functions at a known address is to make them absolute by using the __at(address) construct in a similar fashion to that used with absolute variables.

The compiler will issue a warning if code associated with an absolute function overlaps with code from other absolute functions. No warning will be issued if the address of an absolute object lies outside the memory of the device or outside the memory defined by the linker classes. The compiler will not locate code associated with ordinary functions over the top of absolute functions.

The following example of an absolute function will place the function at address 400h:

int  __at(0x400) mach_status(int mode)
{
    /* function body */
}

Note that the __at() construct should be placed before the function identifier in the definition (but in this position it is not legal when building code for the C90 language standard). You can, however, place the __at() after the identifier if it is used in a declaration. The __at() construct can then be removed from the definition altogether, as in the following example.

int mach_status(int mode) __at(0x400); // declaration indicates address

int mach_status(int mode) { ... } // defintition can omit the __at()

This construct cannot be used with interrupt functions. See 4.6.1.3 Codeoffset Option for information on how to move Reset and interrupt vector locations (which can be useful for designing applications such as bootloaders).

The code generated for absolute functions is placed in a section dedicated only to that function. The section name has the form shown below (see 5.15.1 Compiler-Generated Psects for a full list of all section names).

xxx_text
Defines the section for a function that has been made absolute. xxx will be the assembly symbol associated with the function, e.g., the absolute function rv() would appear in the psect called _rv_text.

Functions can be allocated to a user-defined psect using the __section() specifier (see 5.15.3 Changing and Linking the Allocated Section) so that this new section can then be linked at the required location. This method is the most flexible and allows functions to be placed at a fixed address, after another section, or anywhere in an address range. When used with interrupt functions, this specifier will only affect the position of the interrupt function body. Never place functions into a section that is also used to hold non-executable objects, such as const objects, as this might cause runtime failures or affect the ability to debug the functions.

Regardless of how a function is located, take care choosing its address. If possible, place functions at either end of a program memory page (if relevant) to avoid fragmenting memory and increasing the possibility of linker errors. Place functions in the first page, which contains the reset and interrupt code, rather than in pages higher in memory, as this will assist the optimizations that merge psects.