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 functionrv()
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.