18.2.4 Initialize Global Pointer
The compiler toolchain supports Global Pointer (gp
) relative addressing.
Loads and stores to data residing within 32KB of either side of the address stored in
the gp
register can be performed in a single instruction using the
gp
register as the base register. Without the Global Pointer,
loading data from a static memory area takes two instructions – one to load the Most
Significant bits of the 32-bit constant address computed by the compiler/linker and one
to do the data load.
To utilize gp
-relative addressing, the compiler and assembler must group
all of the “small” variables and constants into one of the following sections:
.lit4.
|
lit8 |
.sdata.
|
sbss |
.sdata.*
|
sbss.* |
.gnu.linkonce.s.*
|
.gnu.linkonce.sb.* |
The linker must then group all of the above input sections together. This grouping is
handled by the default linker script. The run-time start-up code must initialize the
gp
register to point to the “middle” of this output section. To
enable the start-up code to initialize the gp
register, the linker
script must initialize a variable which is 32 KB from the start of the output section
containing the “small” variables and constants. This variable is named
_gp
(to match core linker scripts).
Some PIC32 MCUs have more than one register set. The additional register sets can be used as interrupt shadow register sets. The Global Pointer must be initialized in each of the register sets. The default start-up code does this by looping through each of the register sets.
In the loop, the CP0 SRSCtl register's PSS field must be set to the shadow set in which to initialize the global pointer. In the source code, we start with the highest register set, as defined by the PIC32_SRS_SET_COUNT macro, and work down to zero. By initializing the global pointer in the previous set as iterate through the register sets, we initialize the register in each of the sets on the device.