11.5 Handles

The modified Harvard architecture of dsPIC30F devices supports two memory spaces of unequal size. Data memory space can be fully addressed with 16 bits while program memory space requires 24 bits. Since the native integer data type (register width) is only 16 bits, there is an inherent difficulty in the allocation and manipulation of function pointers that require a full 24 bits. Reserving a pair of 16-bit registers to represent every function pointer is inefficient in terms of code space and execution speed, since many programs will fit in 64K words of program space or less. However, the linker must accommodate function pointers throughout the full 24-bit range of addressable program memory.

Note: Future versions of the compiler may define function pointers to be 24 bits or larger. In such cases, handles will not be used.

In order to ensure a valid 16-bit pointer for any function in the full program memory address space, the MPLAB XC-DSC assembler and linker support the handle() operator. The C compiler uses this operator whenever a function address is taken. Assembly programmers can use this operator three different ways:

mov    #handle(func),w0 ; handle() used in an instruction
.word  handle(func)     ; handle() used with a data word directive
.pword handle(func)     ; handle() used with a instruction word
;directive

The linker searches all input files for handle operators and constructs a jump table in a section named .handle. For each function that is referenced by one or more handle operators, a single entry is made in the jump table. Each entry is a GOTO instruction. Note that GOTO is capable of reaching any function in the full 24- bit address space. Section .handle is allocated low in program memory, well within the range of a 16-bit pointer.

When the output file is built, the absolute addresses of all functions are known. Each handle relocation entry is filled with an absolute address. If the address of the target function fits in 16 bits, it is inserted directly into the object code. If the absolute address of the target function exceeds 16 bits, the address of the corresponding entry in the jump table is used instead. Only functions located beyond the range of 16-bit addressing suffer any performance penalty with this technique. However, there is a code space penalty for each unused entry in the jump table.

In order to conserve program memory, the handle jump table can be suppressed for certain devices, or whenever the application programmer is sure that all function pointers will fit in 16 bits. One way is to specify the --no-handles link option on the command line or in the IDE. Another way is to define a symbol named __NO_HANDLES in the linker script:

__NO_HANDLES = 1;

Linker scripts for DSC devices with 32K instruction words or less all contain the __NO_HANDLES definition to suppress the handle jump table.

Note: If the handle jump table is suppressed, and the target address of a function pointer does not fit in 16 bits, a “relocation truncated” link error will be generated.